In the previous post we evaluated Exploit Guard controls against a simple buffer overflow vulnerability in a test application. We used Matt Graeber’s Exploit Guard documentation as a guide.
As expected, the controls designed to protect against image loads did not provide value in that scenario.
This post evaluates the image load controls against the scenario they are designed for.
tl;dr: Exploit Guard can offer effective protection against .dll based process injection.
New results:
Control | Effective? |
---|---|
Block Remote Image Loads | YES |
Block Low Integrity Image Load | YES |
Setting up for Process Injection
Before we jump in, i want to acknowledge reenz0h (Sektor7) and the top notch training in the Red Team Operator: Malware Development Course. The templates I am using for testing the Exploit Guard controls are all based on the course content you’ll be provided in his course. I’m not going to provide the full source code i used for testing the Exploit Guard controls in this post because it’s not my IP, but all the examples in this post are provided as simple to use templates in the Sektor7 course
We start by compiling the ‘evil’ .dll.
In this case, i’m just going to use some shellcode to start a 64 bit version of the windows calculator.
We’re using cl.exe
from the visual studio c/c++ tools:
cl.exe /O2 /D_USRDLL /D_WINDLL implantDLL.cpp implantDLL.def /MT /link /DLL /OUT:implantDLL.dll
Next we compile the binary that is going to inject our ‘malicious’ .dll into the remote process.
To create a binary specifically designed to do our process injection we would write a program that will open the target process with:
OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)(pid));
where pid
has been identified with a search function looking for ‘notepad.exe’, and the PROCESS_ALL_ACCESS
parameter is provided to our OpenProcess
call.
Then, we create a buffer in the remote notepad process and copy all of the bytes from our implant.dll
into that buffer.
Finally we use CreateRemoteThread
to create a thread inside notepad.exe based on the shellcode we’ve pushed into it’s process memory.
Something like:
CreateRemoteThread(pHandle, NULL, 0, pLoadLibrary, remBuf, 0, NULL);
Where remBuf
is the buffer inside notepad that we’ve loaded the dll bytes into.
We compile the process injection program with:
cl.exe /nologo /Ox /MT /W0 /GS- /DNDEBUG /TcinjectDLL.cpp /link /OUT:injectDLL.exe /SUBSYSTEM:CONSOLE /MACHINE:x64
This gives us everything we need for process injection:
- A malicious dll to inject into a remote process (in this case, just calc.exe but a bad guy will have better ideas)
- An executable who’s sole purpose is to shove our malicious dll into a remote process (notepad.exe).
Testing:
We run the injectdll.exe program to load our dll in the notepad.exe process; it then runs the code with the CreateRemoteThread API.
From the process hacker view there is no child process for our ‘malicious’ code but you can clearly see calc.exe running in the screenshot.
The only hint that anything is wrong is the horrible little .dll in the notepad process address space:
To summarize the test:
- We used the
OpenProcess
function from our dllinjector program to get access to notepad - We carved out some memory space in notepad.exe
- We copied our dll bytes into that memory
- The we started a thread by pointing at the dll code we’d just implanted using
CreateRemoteThread
.
Reminder: Everything you need to create the code above is in the Secktor7 content (it’s not my IP to share). You’ll get templates that make everything above (and a whole lot of other techniques) very straightforward and they’ll show you how to use them.
Exploit Guard v Process Injection
Now we’ll configure Exploit Guard and determine whether it can help in this scenario.
Block Remote Image Loads
This control is designed to “Prevent loading of images from remote devices”.
When the process injection is initiated from a local folder this control does not provide any protection (by design); this makes a lot of sense because loading .dll’s from the local machine is what normal processes do. The hope is that a malicious .dll would have been gobbled up by defender if it was sitting on the local disk.
To better evaluate the control, we’ll move the dll to a remote share and update the injection code (char dll[] = "Z:\\implantDLL.dll";
); aiming to simulate an adversary who keeps the malware dll in a remote location; copying it into the memory of a victim process from the remote location to avoid detection on the target client.
That works! Exploit Guard Steps in and we see event 8:
Process '\Device\HarddiskVolume1\Windows\System32\notepad.exe' (PID 9644) was blocked from loading a binary from a remote share.
Another useful finding on this one was that notepad.exe didn’t crash.
The process was able to continue while still being resilient to the remote image load.
Result: Successful Mitigation
Block Low Integrity Image Load
The documentation says that this control “Prevents the loading of images marked with Low Integrity”.
Once configured for notepad.exe we attempt to inject our malicious .dll.
That also works. Event 6:
Process '\Device\HarddiskVolume1\Windows\System32\notepad.exe' (PID 4076) was blocked from loading the low-integrity binary '\;S:0000000000084b0e\dc1\sysvol\implantDLL.dll'.
And, similar to the remote image load, the process remains unharmed - the exploit guard control does not need to terminate the process, it simply swats away the low integrity image I’ve tried to load into the process.
Result: Successful Mitigation