HEVD Windows Kernel Exploitation 3 -Write What Where

Let’s continue with the third blogpost of the Kernel exploitation series. Few notes:

  • With Stack Overfow:  we put our shellcode in user-land in an allocated memory and execute in kernel-land
  • With Arbitraty Overwrite: we’ll be writing the value pointed by “what” to the memory location referenced by “where”

The strategy for this blogpost:

Initial Phase:

  • Source Code Review
  • Finding IOCTL
  • Verifying the vulnerability with the initial script

Exploitation Phase:

  • Enumerate all drivers
  • Find the address for ntoskrnl.exe
  • Load ntoskrnl.exe into LoadLibraryExA
  • Enumerate HalDispatchTable address
  • Overwrite HalDispatchTable + 0x4 with a pointer to our shellcode

Source Code Review:

We have 2 source-code files for this vulnerability:

Let’s start with the header file: ArbitraryWrite.h:

  • in the first snippet, typedef is used to create new datatype for what and where
  • WRITE_WHAT_WHERE is an alias used to reference the struct _WRITE_WHAT_WHERE
  • PWRITE_WHAT_WHERE is an ‘aliased pointer’ to the struct _WRITE_WHAT_WHERE
  • in the second snippet, we see a variable UserWriteWhatWhere with the datatype PWRITE_WHAT_WHERE which was a pointer to the struct _WRITE_WHAT_WHERE which contains What & Where pointers

After getting some insights from the header file, we’ll have a look at the C code:

  • here we see what and where which was declared in the header file already
  • they are initialized here as NULL

Then we see the secure version of the code which verifies if values pointed by what and where resides in User mode. The vulnerable version doesn’t verify while writing the value pointed by WHAT to the memory location referenced by WHERE, if the values reside in user mode or not. 

So after doing some source code review, we’ll find the IOCTL code as the first thing: 

  • if we subtract 0x222003 from our IOCTL and we don’t get 0x0,
  • subtract another 0x4. If we don’t get 0x0,
  • subtract another 0x4. If we get 0x0, jump to the Arbitrary Write function.
  • this makes our IOCTL 0x222003 + 8 bytes = 0x22200B

Now we have the IOCTL code, we’ll verify the vulnerability with our initial script:

After verifing the vulnerability, we will proceed with the exploitation phase:

Exploitation Phase:

  • Enumerate all drivers
  • Find the address for ntoskrnl.exe
  • Load ntoskrnl.exe into LoadLibraryExA
  • Enumerate HalDispatchTable address
  • Overwrite HalDispatchTable + 0x4 with a pointer to our shellcode

So I’ll give a bit of theory here to understand what are we doing and why are we doing it, then will continue purely with code snippets and explaning the lines of code:

Since the Arbitrary Overwrite vulnerability exists, we need to find a way to execute user mode shellcode from kernel mode. This can be done via HalDispatchTable which is a part of the kernel for hardware/machine instructions. It helps making various hardware architectures to be compatible with Windows. We’ll use various Windows API calls for our goal. Let’s start by creating code snippets for each goal:

Enumerate all drivers:

We’ll use EnumDeviceDrivers() to enumerate all driver addresses: https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumdevicedrivers

  • It gets 3 parameters: *lpImageBase,  cb, and lpcbNeeded:
  • An array that receives the list of load addresses for the device drivers.
  • The size of the lpImageBase array, in bytes
  • The number of bytes returned in the lpImageBase array

Find the address for ntoskrnl.exe:

For finding the address of ntoskrnk.exe, we will use GetDeviceDriverBaseNameA function: https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea

  • it gets 3 parameters: ImageBase, lpFilename, nSize
  • ImageBase: the load address of the device driver
  • nSize: the size of the lpBaseName buffer, in characters

Load ntoskrnl.exe into LoadLibraryExA:

This time we’ll use the API function: LoadLibraryExA: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa

  • it gets 3 parameters: lpLibFileName, hFile, dwFlags
  • lpLibFileName: A string that specifies the file name of the module to load
  • hFile: This parameter is reserved for future use. It must be NULL
  • dwFlags: The action to be taken when loading the module

Enumerate HalDispatchTable address:

We’ll use GetProcAddress() to find the address of HalDispatchTable: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress

  • it gets 2 parameters: hModule, lpProcName
  • hModule: A handle to the DLL module that contains the function or variable
  • lpProcName: The function or variable name, or the function’s ordinal value

Final Exploit – few more additions

So let’s see what do we have in our final exploit:

  1. DLLs for windows APIs (kernel32, ntdll, psapi)
  2. We define the what & where stuctures
  3. shellcode (same we used in the Stack overflow exploit)
  4. Defeating DEP with VirtualAlloc (same we used in the Stack overflow exploit)
  5. Enumerate all drivers – explained above
  6. Find the address for ntoskrnl.exe – explained above
  7. Load ntoskrnl.exe into LoadLibraryExA – explained above
  8. Enumerate HalDispatchTable address – explained above
  9. Trigger the exploit
  10. CreateFileA and DeviceIoControl API functions – same as the Stack overflow exploit
  11. NtQueryIntervalProfile() call to make sure the exploit is working by executing the shellcode at HAL+0x4
  12. Pop the shell – same as used in Stack Overflow exploit

Most of the code is already given above, there are few adjustments made with the explanations given below. After that run the script and enjoy the SYSTEM shell.

  • w00t w00t 🎉
 import struct, sys, os
from ctypes import *
from subprocess import * 

# DLLs for Windows APIs


# Here we’ll define What & Where in our exploit 

# Shellcode 

# Defeating DEP with VirtualAlloc. Creating RWX memory, and copying our shellcode in that region

# Enumerate all drivers:

# Find the address for ntoskrnl.exe: 

# Load ntoskrnl.exe into LoadLibraryExA: 

# Enumerate HalDispatchTable address: 

# Now we trigger the exploit here:  

# CreateFileA and DeviceIoControl -same as used in Stack Overflow exploit  

# NtQueryIntervalProfile() will eventually call the Where location (HAL + 0x4) and execute it


# Pop the shell – same as used in Stack Overflow exploit  
Final Exploit