Recently I started to dive deeper into the topic „LPE on Windows“, obviously one of the first things you will learn is to look what runs as system and does it load anything were you have write access to.
I started my learning with some very educating sources about DLL Ghosting and Sideloading. In the end the goal is the same, you want to provide a malicious DLL to a privileged process and either this:
- DLL already exists and you can overwrite it, or this
- DLL exists but you can place your DLL at a location wich is prioritized, or this
- DLL does not exist and you can write at a location where the process is looking for it
A way better description of this process is described on this page: https://itm4n.github.io/windows-dll-hijacking-clarified/
For my research I used the tool: Procmon from Sysinternals. I setup some filters, let it run for some hours and I quickly realized that the output is huge, too huge. There are so many calls that are running as System and accessing my file system that it would took days to check every location by hand, if I can place something there. I decided to wrote a little PowerShell script, which can parse the output of Procmon and check every location if the current user has write access to it or not. You can find the project here: PSAccessFinder
This pushed my process of hunting to another level, the idea is: just run Procmon for hours, export the Log and parse it with PSAccessFinder and you will retrieve locations that are accessed by a higher privileged process and you have write access to. If you wonder what filter you should set and how this process looks like in a actual case, check this great post about a LPE finding in the Asus Amoury Crate service.
Well, if you start doing this by your own, you will quickly notice, that not every „CreateFile“ call in Procmon leads to an effektiv load of you placed DLL. There are many calls that just checks for attributes, permissions, if the file exists and so on. What you are really looking for is „LoadLibraryA“ and „LoadLibraryExW“ calls. This means, a DLL is dynamic linked and loaded by the application and you can use the „DLL_PROCESS_ATTACH“ call in your DLL to execute commands. Unfortunately , these calls are only visible in the stack and (at least I don´t know how) you can’t filter for them, so there is still some manual analyses to do.
Enough theory, lets start to investigate what runs on my pc 🙂
I love playing computer games, although I haven’t much time for this I still have all of these Software installed on my PC and from time to time I find some gaps to play something.
So lets start Procmon with the following filters.
There are still a lot of results over time, but this is where my script PSAcessFinder comes in, so don’t worry about the amount of events right now.
Tip: To speed up the amount of calls it is a good idea to start some applications, best one are these, who have also services installed. Especially application updates are always a good trigger because they are often have a service and these run as local system, because they need write access to places where a normal user does’t have permissions to. So lets go and trigger some updates! 🙂
After (how ever, how long you want to wait) stop the capturing and export the events as csv. But don´t close Procmon! We will need the actual capture for further investigation later on!
Now its time to check the locations for write access, start findWriteAccess.ps1 with the inputCSV parameter, pointing to your exported Logfile.
PS C:\>.\findWriteAccess.ps1 -inputCSV .\Logfile.CSV try to parse csv and remove duplicates... starting search for write access in 86 locations... found some folders, happy hunting :) Process AcessTo FullPath Acess Rights ------- ------- -------- ----- ------ GalaxyCommunication FullPath C:\ProgramData\GOG.com\Galaxy\redists\GalaxyCommunication.exe VORDEFINIERT\Benutzer Write Search took 0 minutes and 0 seconds
If you are lucky you will get some output like this, if not, don´t worry there are other possibilities to find a LPE. But maybe you just need to run Procmon again and for a longer time.
If you found something, great! Now its time to check, if there is really a DLL call, what you can abuse. So go back to Procmon and search for this process, if you cant find it, just open the CSV, search there for the exact path, look at the TimeStamp and scroll through your Procmon output until you reach the Timestamp. It must be there!
In my case I found this:
It looks like the GalayCommunication.exe is running as System and I have write access to the directory where it is stored. Lets verify this.
Indeed! The Builtin Users have write access to this folder.
So, now lets check the DLLs. Site note at this place, of course if you have write access to the exe you can just replace the exe with anything you want to get your LPE 🙂 But for the sake of learning DLL hijacks lets stick to the loading DLLs.
Remembering the theory section, we need to find a LoadLibrary call, so I checked the stack of every DLL , and indeed, there was exactly one DLL which was called via LoadLibrary.
The nice part about this, you can see that the result is „NAME NOT FOUND“, this means we have a Ghost DLL injection. This is great because we don´t need to overwrite some other DLL which maybe will break the application.
So lets create a DLL in c++ and place it at our vulnerable location. As proof of concept I just created a simple DLL that wrote the current username to the file proof.txt.
TCHAR username[UNLEN + 1]; DWORD size = UNLEN + 1; GetUserName((TCHAR*)username, &size); ofstream myfile; myfile.open("C:\\target\\proof.txt"); myfile << username; myfile.close();
Compile the DLL and plant it
start the service and check the proof.txt.
hmm the file was created but the Username is „Admin“, thats my current logged on user and not the system user. It seams that the application drops the privileges to the current user.
I was curious, what happens if I remove the permission for the current user „Admin“ to this file?
Run the service again and
wow! removing the permission to the file forces some how that the SYSTEM user will take affect. This is at least a arbitrarily file write and can lead to local privilege escalation 🙂
I don´t know since when GOG changed this permission issue, my installation is about one year old. I checked a fresh installation and the Builtin Users doesn’t have any write permissions to the redists folder anymore. So unfortunately this is not a „valid“ new finding. But by investigating the folder permissions of the new installation again I found another (new and valid) LPE in the Software: GOG Galaxy – CVE-2022-31262