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.