It’s not very often in the life of a pentester that you find a point-and-click exploit that works right out of the box. Most public scripts are simple proofs of concept that don’t work in every scenario and must be modified to perform the desired action. In fact, the OSCP course from Offensive Security has a big section dedicated to altering existing code to make it work for a specific OS or version. This came in handy recently as I had to modify an exploit to get it to work well within PowerShell Empire.
The MS16_032 vulnerability is extremely useful for several reasons. First, it is possible to execute a confirmed privilege escalation exploit on a variety of different Windows systems (Vista through Windows 10!) where the exposure is unpatched. Secondly, it does not involve any risky memory corruption techniques which may compromise a limited foothold. Finally, this vulnerability is a fairly recent release (only three months old at the time of this writing) and is likely to continue to be out in the wild for some time.
At RSM we regularly utilize Empire to navigate laterally around a compromised network. One of the most useful functions within Empire involves executing a PowerShell script on a host which creates a backdoored process known as an ‘agent’. While MS16-032 currently has a PoC powershell exploit available, the payload only triggers a local command prompt to pop up with SYSTEM privileges. This is very useful if you have physical or RDP access to the machine but not that helpful when it comes to interacting stealthily using Empire.
The exploit on Exploit-DB uses a pair of Windows API calls to check to see if the new process has a privileged token:
# LOGON_NETCREDENTIALS_ONLY / CREATE_SUSPENDED
$CallResult = [Advapi32]::CreateProcessWithLogonW(
"user", "domain", "pass",
0x00000002, "C:\Windows\System32\cmd.exe", "",
0x00000004, $null, $GetCurrentPath,
[ref]$StartupInfo, [ref]$ProcessInfo)
As you can see this example simply created the cmd window as discussed above. In order to figure out exactly how this process worked, I consulted MSDN which had a very convenient page outlining each argument of the function call. At first I wanted be able to pass it an arbitrary command from within Empire. I added the following lines at the top:
param (
[Parameter(Mandatory = $True)]
[string]$Cmd
)
and then modified both API calls to use powershell to execute the input:
# LOGON_NETCREDENTIALS_ONLY / CREATE_SUSPENDED
$CallResult = [Advapi32]::CreateProcessWithLogonW(
"user", "domain", "pass",
0x00000002, "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe", $Cmd,
0x00000004, $null, $GetCurrentPath,
[ref]$StartupInfo, [ref]$ProcessInfo)
Success! I could now use this script to execute commands with administrator privileges (e.g. adding a new administrator). Now the tricky part came when I wanted to actually create an Empire agent with SYSTEM privileges without having desktop access.
Empire has a feature that allows you to import your own custom PowerShell scripts by using the scriptimport
command from an active agent’s menu. Once you load your custom PS file in memory, you can tab complete the functions by using scriptcmd.
In order to get an agent to run, I tried passing the default launcher staging output as a parameter but that failed. My guess was that the encoded string was just too long, so I decided to try it without the Base64 encoding. The one-liner without encoding is very ugly looking, so I had to use Python string replace() to fix all of the nasty characters before it would work as a parameter.
The final working code can be found below. Remember that the stager output must NOT be Base64 and must have all quotes and $ characters properly formatted to be literals.