Skip to content

Fuzzing Windows

Tamas K Lengyel edited this page May 11, 2021 · 9 revisions

Generate json from Windows kernel debug info

  1. Download Volatility3 from https://github.com/volatilityfoundation/volatility3/releases/latest
  2. Build it: python3 setup.py build
  3. Boot your Windows VM
  4. Run vmi-win-guid name <vm_name>
# vmi-win-guid name windows10
Windows Kernel found @ 0x3400000
	Version: 64-bit Windows 10
	PE GUID: d3f646971046000
	PDB GUID: 3fcc539ff307dd2d9c509206d352b9aa1
	Kernel filename: ntkrnlmp.pdb

Note the PDB GUID and Kernel filename

  1. Use Volatility3's pdbconv to grab the PDB and convert it to JSON:
python3 volatility3/volatility/framework/symbols/windows/pdbconv.py \
    --guid 3fcc539ff307dd2d9c509206d352b9aa1 \
    -p ntkrnlmp.pdb \
    -o windows10.json

Fuzzing a kernel driver with source-access

When you have the ability to recompile your target you can use the standard cpuid harness to mark the beginning and end of the code you want to fuzz. Follow the setup steps from the official Microsoft documentation to set up the Visual Studio environment for WDK: Download the Windows Driver Kit (WDK). You can take a look at the testmodule_win sample driver that includes the cpuid harness you can compile into your target:

TITLE kfx harness

.code
;void harness(void);
harness PROC
	push rax
	push rbx
	push rcx
	push rdx
	mov rax,13371337h
	cpuid
	pop rdx
	pop rcx
	pop rbx
	pop rax
	ret
harness ENDP

;void harness_extended(int magic_mark, unsigned long long address, size_t size);
harness_extended PROC
	push rax
	push rbx
	push rcx
	push rdx
	push rsi

	mov rax,rcx
	mov rsi,rdx
	mov rcx,r8
	cpuid

	pop rsi
	pop rdx
	pop rcx
	pop rbx
	pop rax
	ret
harness_extended ENDP

END

Make sure you enable loading of the test kernel module in your VM by running the following commands and then rebooting your VM:

bcdedit /set nointegritychecks on
bcdedit /set testsigning on

The setup and fuzzing phase are the same as when fuzzing Linux. In order to override the default built-in Linux sink points, you can specify --sink on the kfx command line to specify the functions you want to report as crash. For example, in the following we'll report all calls to KiDispatchException as a crash to AFL:

AFL_KILL_SIGNAL=15 ./AFLplusplus/afl-fuzz -i input -o output -- \
    ./kfx --domain windows10 --json ~/windows10.json \
    --address 0xffffde8cd4144800 \
    --input-limit 69 \
    --input @@ --ptcov \
    --sink KiDispatchException

Fuzzing the kernel (or kernel-driver) with no source-access

If you don't have the ability to recompile your target you can use breakpoints as your harness. You will want to use windbg to set the breakpoints in your target that will mark the beginning and end of the code you are fuzzing. To be able to attach windbg remotely to your VM you'll need 2 Windows VMs: one that you will fuzz (target VM) and the other where you are running windbg. The VM config for both needs to contain the option serial = 'pty' and you'll need socat installed.

  1. Boot your VM that will run windbg, start windbg and press CTRL+K to open the debug menu, select COM as your target and hit OK.
  2. Boot your target VM, open a cmd.exe prompt with Administrator privileges and run:
bcdedit /debug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200
  1. Reboot your target VM.
  2. Run scripts/serial-bridge.sh from this repository with the names of the VMs. For example ./scripts/serial-bridge.sh windows10-1 windows10-2.
  3. As the target VM is booting the windbg session will activate.
  4. Select the Debug -> Break option in windbg to activate debugging (you can also wait till Windows finished booting completely).
  5. Place a breakpoint into the target where you want to start fuzzing at (for example bu sioctl!SioctlDeviceControl)
  6. Resume the VM Debug -> Go
  7. Trigger the execution of your target
  8. When the start breakpoint is caught by windbg note what the first byte is at your target RIP
  9. Place a breakpoint into the target where you want to stop fuzzing at (make sure it's not in the fast-path of the kernel's normal execution, you want the end breakpoint to trigger only if the start breakpoint triggers as well)
  10. Resume the VM Debug -> Go
  11. Start kfx in dom0 with --setup --harness breakpoint --start-byte <first_byte> where <first_byte> is the byte you found above in hex (for example 0x48)
  12. Trigger the execution of your target again
  13. kfx will catch when the breakpoint triggers now instead of windbg
  14. You can start fuzzing your target

The above process assumes your target code (including your start and end breakpoints) only execute when you manually trigger them. In case you need to place your end breakpoint into a location that's in the kernel's execution fast-path, then you'll not be able to place it directly with windbg. You can still place the start breakpoint with windbg. Catch the start breakpoint with kfx --setup as noted above, and use rwmem to write the end breakpoint into the VM.

echo -n -e '\xCC' > cc
./rwmem --domid <target_domid> --read <end_harness> --file backup --limit 1
./rwmem --domid <target_domid> --write <end_harness> --file cc --limit 1

To figure out where to place the end harness manually may require additional information. For example to place it at the address where a function returns to you want to catch the function's entry (for example bu sioctl!SioctlDeviceControl). When kfx catches the start breakpoint run xen-hvmctx <target_domid> | grep rsp and check what the address is in the RSP register (for example rsp 0xffff82021097f688).

Use rwmem to figure out what's the return address is by checking the value on the stack where rsp points to:

./rwmem --domid <target_domid> --read <rsp_value> --limit 8 --file ret
xxd -e ret | awk '{ print "0x" $3 $2 }'

Once you know what the return address is you can use rwmem as described above to write the breakpoint (cc) into that address to be your end harness. Once you are finished fuzzing, you will want to remove the end harness breakpoint you manually placed by writing the original byte saved in the backup file above.