DLL proxying refers to replacing a DLL with our own, which will provide the same functionality as the original one.
This was seen recently in the 3CX supply chain attack, where a modified ffmpeg
would load malicious code.
The advantages of doing this are providing persistence, as well as privilege escalation in some cases.
In what cases can this exploited?
A more detailed explanation is available on MSDN but I will provide the simpler, more common version.
When a DLL is loaded (either via LoadLibrary
or the Windows Loader), the search order is as follows:
- KnownDLLs (available at
HKML\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
). - The application’s folder
C:\Windows\System32
C:\Windows
- The current folder
- The directories listed in the %PATH%.
How can I make use of this
We can exploit this issue if one of the DLL search paths is somewhere where we can write. This is particularly useful if the program is attempting to load a DLL that doesn’t exist.
CreateFile C:\Users\User\source\repos\DllProxying\x64\Debug\FakeDll.dll NAME NOT FOUND
CreateFile C:\Windows\System32\FakeDll.dll NAME NOT FOUND
CreateFile C:\Windows\System\FakeDll.dll NAME NOT FOUND
CreateFile C:\Windows\FakeDll.dll NAME NOT FOUND
As you can see, the file does not exist on disk, and I am capable of writing to my User’s folder.
Now let’s see what the DLL looks like:
|
|
Our main file, now using a real DLL which only exports a Hello
function.
typedef void(*HelloFn)();
int main()
{
HMODULE hModule = LoadLibrary(L"SampleDll.dll");
HelloFn helloFn = (HelloFn)GetProcAddress(hModule, "Hello");
HelloFn();
return 0;
}
If I want to replace SampleDll
with my own DLL, I would have to maintain the functionality of the original DLL.
We can perform this by proxying functions over to a separate DLL.
First, we require dumpbin
from Microsoft.
We will run it on the DLL we intend to proxy with dumpbin /exports
.
Dump of file SampleDll.dll
File Type: DLL
Section contains the following exports for SampleDll.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00011028 Hello = @ILT+35(Hello)
Here is what our proxy DLL will look it, it will export functions from the original SampleDll
while still adding its own functionality.
|
|
While more often than not it’s not a privilige escalation, it is something that number of applications are vulnerable to, which can aid in malware persistence.
I may write about more advanced techniques in the future, if there is an interest.
I have placed the relevant code on GitHub.