Digging Deeper into Vulnerable Windows Services
Privilege escalation is a common goal for threat actors after they have compromised a system. Having elevated permissions can allow for tasks such as: extracting local password-hashes, dumping clear text credentials from memory, and installing persistent back doors on the system. Insecurely-configured Windows Services can be one avenue for privilege escalation. Windows Services typically run under the context of an elevated user. If you can get the service to run your malicious program, your program will likely run with elevated permissions. This blog post discusses two obstacles that might arise when attempting to exploit Windows Services.
Local Windows Privilege-Escalation via Insecure Service with Application Whitelisting Present
In this section, we briefly discuss a scenario with the following conditions:
- You have command-line access to a Windows system
- You are an unprivileged user
- You have permissions to overwrite a privileged service
- You either have permissions to stop/restart the vulnerable service mentioned in 3 or you are able to stop it with another method (such as using blank DLL files to crash the service).
- You can restart the system
- Application whitelisting is enabled on the system
In other words, you’ve run PowerUp or another local-privilege escalation script, you see a service is vulnerable, you can easily overwrite it…but your malicious binary won’t run because application whitelisting (AWS) is preventing it from executing. What to do? Well, we can turn to some of the nifty AWS bypass techniques that have been disclosed by Casey Smith and others. InstallUtil is a great one since the template is fairly small, you can easily customize your program to perform whatever privileged-task you’d like (e.g., add a user and make them local admin, establish a C2 connection as SYSTEM, etc.), C# is fun to write and can be compiled locally, and many other great benefits.
In this example, we have code that was written to:
- Create a new local user
- Add the new user to the local Administrators group
- Make another call to InstallUtil that runs a second, custom C# program that calls out to a remote server and establishes a Meterpreter C2 session
- Run via InstallUtil
The code can be compiled using the csc.exe C# compilation tool that is typically present on Windows systems and is usually trusted by AWS. Let’s say your code is located at C:\Users\Public\runthis.cs, the following command can likely be used to compile the program.
C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /platform:anycpu /out:C:\Users\Public\shell.exe C:\Users\Public\runthis.cs
How do we get this to work with the service though? Easy! If you have written permissions for the service, you likely have permissions to reconfigure certain properties of the service as your normal. Windows Service-Config tool, called sc, can be used to tell the vulnerable service which binary it should run by configuring the service’s binPath property. The binPath property not only points to the binary, but it also allows you to specify command-line arguments just as you would if you called it directly from the command line. Let’s say that the service is named ExploitThisService and your binary is located at C:\Users\Public\shell.exe (as given by the compilation command above), then you could use the following service-config command:
sc config ExploitThisService binPath= "C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe /logfile=C:\Users\Public\logfile.txt /LogToConsole=false /U C:\Users\Public\shell.exe"
That’s it! Restart the computer and voila, your executable should run under the same privileged context that the vulnerable service was running.
Local Windows Privilege-Escalation via Insecure Service without Stop/Restart Permissions
Let’s consider another scenario that is similar to the first section of this write-up. In this scenario, however, let’s assume that you do not have the ability to stop or restart the service. This missing permission is actually quite common. Without being able to stop the service, you won’t be able to overwrite the executable and may not be able to update the configuration. What do we do in that case? One possibility is to take advantage of the way that programs search for DLLs that they need to load upon execution.
DLL hijacking is nothing new. The concept is that you overwrite a DLL that is required by a program with your own malicious DLL. The program runs, calls your DLL, and your code is executed. That isn’t what we are talking about here though. In this case, we are going to use DLLs to crash the service so that we can overwrite it.
A design decision made by Windows dictates that, by default, programs will first look in their current folder for any necessary DLLs. Hardcore Windows people, please correct me if I am wrong with the following statement: all Windows programs will require at least one DLL from the C:\Windows\System32 folder if it is not included with the program. Obviously, that folder path is used in a general sense and I am sure people will troll me on the fact that it can be changed…but you get the idea.
So how do we take advantage of this? Easy! Have you ever tried to run a program and were greeted with an angry-looking message that said it couldn’t find a required DLL? Probably…What would happen if the program could find the DLL but the DLL was corrupted? Or…if the DLL was just a blank file? *Queue Light Bulb Graphic*
Let’s assume that the vulnerable service is located in the folder C:\VulnService\. The following PowerShell one-liner will parse the C:\Windows\System32\ directory, grab the names of all of the DLLs, create blank files with the same names, and place them in C:\VulnService\ directory.
dir C:\Windows\System32 -filter “*.dll” | select-object Name | foreach-object{ $str = \”C:\\VulnService\\\” + $_.name; New-Item -type file $str }
Now, restart the system and…boom! The service should crash and you should now be able to overwrite it with a malicious binary of your choosing or update the service config to utilize the AWS bypass method mentioned in the previous section. Don’t forget to remove the blank DLLs from the folder before attempting to run your binary or it might end up in the same grave as the vulnerable service.
You probably noticed that this is a lot of DLLs to copy over and you likely don’t need all of them. You’re right! We are currently narrowing down a list of commonly-required DLLs by running random programs and using DLL inspection tools to determine which DLLs are loaded. There are some lists out there of commonly-used DLLs and we’ve got ours narrowed down to about 15 or so. It will be released once we are satisfied…or we’ve grown bored of running random programs.
We will point out that we mentioned the DLL search behavior is default; this doesn’t mean it can’t be changed. You can change the DLL search behavior by referring to some of the methods in this article that was released by Microsoft: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx
Ready to learn more?
Level up your skills with affordable classes from Antisyphon!
Available live/virtual and on-demand