This seems bonkers so I'm hoping I didn't find a big security gap... I have Powershell JEA (just enough administration) successfully set up on a server to allow only certain administrative functions. Specifically, I don't have the "net" command allowed at all. If I do the below:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
net stop "My windows service"
}
Then I get the error below as expected:
The term 'net.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. CategoryInfo : ObjectNotFound: (net.exe:String) [], CommandNotFoundException FullyQualifiedErrorId : CommandNotFoundException
BUT, if I wrap my "net.exe" usage inside a function, it actually works:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
function StopService($servicename) {
net stop "$($servicename)"
}
StopService "My windows service"
}
The above does not throw an error and actually stops the service. WTF?
This is more than the "net" command. Another example: "Out-File" is not allowed. The below code fails:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
"hacked you" | Out-File C:\test.txt
}
With the error:
The term 'Out-File' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. CategoryInfo : ObjectNotFound: (Out-File:String) [], CommandNotFoundException FullyQualifiedErrorId : CommandNotFoundException PSComputerName : vxcazdev01
But if I do it this way, it works:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
function DoIt() {
"hacked you" | Out-File C:\test.txt
}
DoIt
}
Why is this happening? Am I missing something? The JEA project on github is now read-only so I can't open an issue there.
Edit to add: the same problem happens if I use Enter-PSSession instead of Invoke-Command.
Edit to add relevant session config pieces: My session config file only has a few customizations from the default file produced by the New-PSSessionConfigurationFile command:
SessionType = 'Default'
RunAsVirtualAccount = $true
RoleDefinitions = @{
'MYDOMAIN\MYADGROUP' = @{ RoleCapabilities = 'MyCustomRole' }
}
MYADGROUP is the only group my test user is a member of. And then this is registered on the server like so:
Register-PSSessionConfiguration -Path "C:\Program Files\WindowsPowerShell\Modules\MyJEAModule\VSM.pssc" -Name 'MYCONFIG' -Force
CodePudding user response:
I wouldn't say that it's a security hole, it's that you are clearly demonstrating what could happen on a system when you have not set up a fully secured configuration. Microsoft even states JEA doesn't protect against admins because "they could simply RDP in and change the configuration". We need the correct combination of SessionType and RoleDefinitions, and that they are meant for two different configurations.
Your example demonstrates a configuration setup where, even though we lock the front door of the house, we started off with a house that had all the windows and doors open. It is fully possible to get in through the back door, or reach through a window and unlock the front door, thus demonstrating the fruitlessness of locking the front door. For example, I don't need to run net stop I could just do a taskkill instead, or..., or..., etc.
Let's look at the overview of what JEA is designed for:
- Reduce the number of administrators on your machines using virtual accounts or group-managed service accounts to perform privileged actions on behalf of regular users.
- Limit what users can do by specifying which cmdlets, functions, and external commands they can run.
- Better understand what your users are doing with transcripts and logs that show you exactly which commands a user executed during their session.
Reduce the number of administrators
We can use JEA to remove people from the local administrators group, or larger Domain Admin groups. They can then selectively get elevated Administrator rights when needed through Virtual Accounts.
If we set it up with the SessionType = 'Default' this enables all language features. We essentially can have a Jr. Technical Analyst without Domain Admin rights, without Local Admin rights, log on, and do Administrative duties. This is what the session type is meant for.
Limit what users can do
If we set it up with the SessionType = 'Default' this enables all language features. In mode it doesn't matter what commands we limit, all the doors and windows are open and we can pretty much do whatever we want. One rule in Windows is that there is always 3-4 different ways to do something. You just can't plug all the holes when everything is wide open.
@MathiasR.Jessen is right, the only way to Limit what users can do is to first lock down the system. Setting SessionType = 'RestrictedRemoteServer' locks down the session to:
Sessions of this type operate in NoLanguage mode and only have access to the following default commands (and aliases):
- Clear-Host (cls, clear)
- Exit-PSSession (exsn, exit)
- Get-Command (gcm)
- Get-FormatData
- Get-Help
- Measure-Object (measure)
- Out-Default
- Select-Object (select)
No PowerShell providers are available, nor are any external programs (executables or scripts).
This starts us out with a completely locked up house. We then selectively enable the needed commands. Ideally we should pre-create custom functions so that the custom function is the only thing they can run, they are technically not even allowed to execute the commands inside the function at all, it's all handled by the Virtual Account.
What you did was essentially exploiting this custom function capability, by "cheating" and creating our own "custom function" that will run in the Virtual Account scope, and not your own, which is why it was able to run "non-allowed" functions, and you were not. If the SessionType = 'RestrictedRemoteServer', you wouldn't be able to create scripts or custom functions like demonstrated, and hence, the "hole" would not be there.
Better understand what your users are doing
Finally the other benefit for JEA is that it can record a transcript of all the commands that are run. This might be needed for audit reasons or fed into a SIEM solution or to find out how your Jr. Technical Analyst messed up your system ;-).
CodePudding user response:
I'm just going to answer this question myself with the answer: security hole by design.
The documentation says this:
The body (script block) of custom functions runs in the default language mode for the system and isn't subject to JEA's language constraints.
It's rather surprising, to me at least, that JEA will let you lock down actions on a server in security sandbox, but as soon as one writes their own custom functions they have full administrative rights to the machine and have broken out of the box. Allowing or restricting the creation of custom functions via the language mode is one thing, but bypassing the set security permissions is another. In my opinion, user-written custom functions should be subject to full security limitations; custom functions written in the role capabilities files should have full admin rights as the documentation indicates.
The other answer by HAL9256 is great, but it describes the benefits of JEA, which is not the topic of this post.
