If you have seen the film Spartacus from 1960, you will remember the scene where the Romans are asking for Spartacus to give himself up. The moment the real Spartacus stood up, a lot of others stood up as well and claimed to be him using the "I AM SPARTACUS" phrase.
When a process that is vulnerable to DLL Hijacking is asking for a DLL to be loaded, it's kind of asking "WHO IS VERSION.DLL?" and random directories start claiming "I AM VERSION.DLL" and "NO, I AM VERSION.DLL". And thus, Spartacus.
...but with a twist as Spartacus is utilising the SysInternals Process Monitor and is parsing raw PML log files. You can leave ProcMon running for hours and discover 2nd and 3rd level (ie an app that loads another DLL that loads yet another DLL when you use a specific feature of the parent app) DLL Hijacking vulnerabilities. It will also automatically generate proxy DLLs with all relevant exports for vulnerable DLLs.
version.dll
, Spartacus will create a version.dll.cpp
file for you with all the exports included in it. Then you can insert your payload/execution technique and compile.[Defence]
Monitoring mode trying to identify running applications proxying calls, as in "DLL Hijacking in progress". This is just to get any low hanging fruit and should not be relied upon.DllMain
. This technique was inspired and implemented from the walkthrough described at https://www.redteam.cafe/red-team/dll-sideloading/dll-sideloading-not-by-dllmain, by Shantanu Khandelwal. For this to work Ghidra is required.CreateFile
..dll
.procmon.exe
or procmon64.exe
.Drop Filtered Events
to ensure minimum PML output size.Auto Scroll
.ENTER
.Argument | Description |
---|---|
--pml | Location (file) to store the ProcMon event log file. If the file exists, it will be overwritten. When used with --existing-log it will indicate the event log file to read from and will not be overwritten. |
--pmc | Define a custom ProcMon (PMC) file to use. This file will not be modified and will be used as is. |
--csv | Location (file) to store the CSV output of the execution. This file will include only the DLLs that were marked as NAME_NOT_FOUND, PATH_NOT_FOUND, and were in user-writable locations (it excludes anything in the Windows and Program Files directories) |
--exe | Define process names (comma separated) that you want to track, helpful when you are interested only in a specific process. |
--exports | Location (folder) in which all the proxy DLL files will be saved. Proxy DLL files will only be generated if this argument is used. |
--procmon | Location (file) of the SysInternals Process Monitor procmon.exe or procmon64.exe |
--proxy-dll-template | Define a DLL template to use for generating the proxy DLL files. Only relevant when --exports is used. All #pragma exports are inserted by replacing the %_PRAGMA_COMMENTS_% string, so make sure your template includes that string in the relevant location. |
--existing-log | Switch to indicate that Spartacus should process an existing ProcMon event log file (PML). To indicate the event log file use --pml , useful when you have been running ProcMon for hours or used it in Boot Logging. |
--all | By default any DLLs in the Windows or Program Files directories will be skipped. Use this to include those directories in the output. |
--detect | Try to identify DLLs that are proxying calls (like 'DLL Hijacking in progress'). This isn't a feature to be relied upon, it's there to get the low hanging fruit. |
--verbose | Enable verbose output. |
--debug | Enable debug output. |
--generate-proxy | Switch to indicate that Spartacus will be creating proxy functions for all identified export functions. |
--ghidra | Used only with --generate-proxy. Absolute path to Ghidra's 'analyzeHeadless.bat' file. |
--dll | Used only with --generate-proxy. Absolute path to the DLL you want to proxy. |
--output-dir | Used only with --generate-proxy. Absolute path to the directory where the solution of the proxy will be stored. This directory should not exist, and will be auto-created. |
--only-proxy | Used only with --generate-proxy. Comma separated string to indicate functions to clone. Such as 'WTSFreeMemory,WTSFreeMemoryExA,WTSSetUserConfigA' |
Collect all events and save them into C:\Data\logs.pml
. All vulnerable DLLs will be saved as C:\Data\VulnerableDLLFiles.csv
and all proxy DLLs in C:\Data\DLLExports
.
--procmon C:\SysInternals\Procmon.exe --pml C:\Data\logs.pml --csv C:\Data\VulnerableDLLFiles.csv --exports C:\Data\DLLExports --verbose
Collect events only for Teams.exe
and OneDrive.exe
.
--procmon C:\SysInternals\Procmon.exe --pml C:\Data\logs.pml --csv C:\Data\VulnerableDLLFiles.csv --exports C:\Data\DLLExports --verbose --exe "Teams.exe,OneDrive.exe"
Collect events only for Teams.exe
and OneDrive.exe
, and use a custom proxy DLL template at C:\Data\myProxySkeleton.cpp
.
--procmon C:\SysInternals\Procmon.exe --pml C:\Data\logs.pml --csv C:\Data\VulnerableDLLFiles.csv --exports C:\Data\DLLExports --verbose --exe "Teams.exe,OneDrive.exe" --proxy-dll-template C:\Data\myProxySkeleton.cpp
Collect events only for Teams.exe
and OneDrive.exe
, but don't generate proxy DLLs.
--procmon C:\SysInternals\Procmon.exe --pml C:\Data\logs.pml --csv C:\Data\VulnerableDLLFiles.csv --verbose --exe "Teams.exe,OneDrive.exe"
Parse an existing PML event log output, save output to CSV, and generate proxy DLLs.
--existing-log --pml C:\MyData\SomeBackup.pml --csv C:\Data\VulnerableDLLFiles.csv --exports C:\Data\DLLExports
Run in monitoring mode and try to detect any applications that is proxying DLL calls.
--detect
Create proxies for all identified export functions.
--generate-proxy --ghidra C:\ghidra\support\analyzeHeadless.bat --dll C:\Windows\System32\userenv.dll --output-dir C:\Projects\spartacus-wtsapi32 --verbose
Create a proxy only for a specific export function.
--generate-proxy --ghidra C:\ghidra\support\analyzeHeadless.bat --dll C:\Windows\System32\userenv.dll --output-dir C:\Projects\spartacus-wtsapi32 --verbose --only-proxy "ExpandEnvironmentStringsForUserW"
Note: When generating proxies for export functions, the solution that is created also replicates VERSIONINFO
and timestomps the target DLL to match the date of the source one (using PowerShell).
Below is the template that is used when generating proxy DLLs, the generated #pragma
statements are inserted by replacing the %_PRAGMA_COMMENTS_%
string.
The only thing to be aware of is that the pragma
DLL will be using a hardcoded path of its location rather than trying to load it dynamically.
#pragma once
%_PRAGMA_COMMENTS_%
#include <windows.h>
#include <string>
#include <atlstr.h>
VOID Payload() {
// Run your payload here.
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
Payload();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
If you wish to use your own template, just make sure the %_PRAGMA_COMMENTS_%
is in the right place.
Whether it's a typo, a bug, or a new feature, Spartacus is very open to contributions as long as we agree on the following:
Click to Open Code Editor