Loading repository data…
Loading repository data…
0vercl0k / repository
wtf is a distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and / or kernel-mode targets running on Microsoft Windows and Linux user-mode (experimental!).
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
what the fuzz or wtf is a distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and or kernel-mode targets running on Microsoft Windows or Linux (experimental, see linux_mode). Execution of the target can be done inside an emulator with bochscpu (slowest, most precise), inside a Windows VM with the Windows Hypervisor Platform APIs or inside a Linux VM with the KVM APIs (fastest).
It uncovered memory corruption vulnerabilities in a wide range of softwares: IDA Pro, a popular AAA game, the Windows kernel, the Microsoft RDP client, NVIDIA GPU Display driver, etc.
Compiled binaries are available from either the CI artifacts or from the Releases section for both Windows & Linux.
If you would like to read more about its history or how to use it on a real target, I recommend to take a look at those posts to get started 🔥
The best way to try the features out is to work with the fuzzer_hevd / fuzzer_tlv_server modules. You can grab the target-hevd.7z / target-tlv_server.7z archives and extract them into the targets/ directory. The archives contain the directory trees that are expected for every targets:
inputs is the folder where your input test-cases go into,outputs is the folder where the current minset files are saved into,coverage is the folder where the .cov files are expected to be in,crashes is where the crashes gets saved in,state is where the memory dump (mem.dmp) as well as the CPU state (regs.json) and the symbol store are stored in (symbol-store.json). The symbol store is a simple JSON file that is used on Linux systems to know where to put breakpoints as there is no support for symbols / dbgeng on those platforms. wtf generates this file at runtime everytime you run your target on Windows.What follows assume that you downloaded the target-hevd.7z file attached to the latest release, and extracted it in the targets directory of your clone of wtf. You should have wtf/targets/hevd in which you find the inputs / outputs, etc. directories.
The server is basically the brain and keeps track of all the state: the aggregated code-coverage, the corpus, it generates and distributes the test-cases to client.
This is how you might choose to launch a local server node:
wtf.exe master --name hevd --max_len=1028 --runs=10000000
The max_len option is used to limit the size of the generated test-case, runs is the number of test-cases it will generate, address specify where wtf needs to be listening on, target is a directory with the directory tree we described above (the user can also choose to override those directories with --input / --output / --crashes) and name specifies your fuzzing module name so that the master can invoke your generator function if you have defined one.
The client nodes run a test-case that has been generated and distributed by the server and communicates the result back to the server (code-coverage, result, etc.).
This is how you would start a client node that uses the bochscpu backend:
wtf.exe fuzz --name hevd --limit 10000000
The fuzz subcommand is used with the name option to specify which fuzzer module needs to be used, backend specifies the execution backend and limit the maximum number of instruction to execute per testcase (depending on the backend, this option has different meaning).
If you would like to run a test-case (or a folder filled with test-cases), you can use the run subcommand.
This is how you would would run the crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 test-case:
wtf.exe run --name hevd --limit 10000000 --input crashes\crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0
To minset a corpus, you need to use a server node and as many client nodes as you need like you would for a fuzzing job. You can simply set the runs optins to 0.
This is how you would minset the corpus in outputs into the minset directory (also highlights how you can override the inputs and outputs directories):
wtf.exe master --name hevd --max_len=1028 --runs=0 --inputs=outputs --outputs=minset
The main mechanism available to instrospect in an execution backend is to generate an execution trace. bochscpu is the fastest backend to do that, because exiting VMX mode is very expensive on the other backends.
This is how you would generate an execution trace for the crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 test-case:
wtf.exe run --name hevd --limit 10000000 --input crashes\crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 --trace-type=rip
To symbolize execution traces you should use symbolizer-rs. This is how you would symbolize the crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0.trace execution trace generated above:
symbolizer-rs.exe --trace crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0.rip.trace
If you see yourself needing more contextual awareness, the bochscpu backend allows you to generate execution traces that can be loaded in the Tenet trace explorer. In the below, I start from a crash in memmove and walk back to find out where the source pointer is coming from (user-mode!):
wtf.exe run --name hevd --limit 10000000 --input crashes\crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 --trace-type=tenet
To generate code-coverage traces you can simply use the run subcommand with the --trace-type=cov option.
This is how you would generate code-coverage traces for all the files inside the minset folder and store them in the coverage-traces folder:
wtf.exe run --name hevd --input minset --trace-path=coverage-traces --trace-type=cov
Those traces aren't directly loadable into lighthouse because they aren't symbolized.
This is how you would symbolize all the files inside the coverage-traces folder and write the results into coverage-traces-symbolized:
symbolizer-rs.exe --trace coverage-traces -o coverage-traces-symbolized --style modoff
And finally, you can load those up in lighthouse:
Also if you don't care about individual code-coverage, the master maintains a coverage.cov file contains the unique aggregated code-coverage that has been exercised. It makes it easy to check on the global code-coverage really quick during a fuzzing job.
wtf runs user & kernel mode through an execution backend and relies on the user to insert test-cases in the target. Unlike other classical fuzzer tools, wtf doesn't do much of the heavy lifting; the user does. The user needs to know the harnessed target very well and onboarding a target is an iterative process that will take time. It has a lot of flexibility to offer if you are ready to get hacking though :)
The usual workflow to harness a target is as follows:
Get your target running into a Hyper-V VM running Windows with one virtual CPU and 4GB of RAM.
Put your target into the desired state using KD. For example, to target HEVD's IOCTL handler, I chose to stop the target in user-mode right before the client invokes DeviceIoControl. This will vary depending on your targets but you probably want it to be close to the code you want to fuzz.
kd> r
rax=000000dfd98ff3d0 rbx=0000000000000088 rcx=0000000000000088
rdx=00000000deadbeef rsi=0000000000000000 rdi=0000000000000000
rip=00007ff6f5bb111e rsp=000000dfd98ff380 rbp=0000000000000000
r8=000000dfd98ff3d0 r9=0000000000000400 r10=000002263e823055
r11=00007ff6f5bcb54d r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
hevd_client!main+0xae:
00007ff6`f5bb111e ff15dc1e0100 call qword ptr [hevd_client!_imp_DeviceIoControl (00007ff6`f5bc3000)] ds:002b:00007ff6`f5bc3000={KERNEL32!DeviceIoControlImplementation (00007ff8`3e2e6360)}
Use snapshot to generate the kernel crash-dump as well as the regs.json file that contains the CPU state. I recommend to dump those file in a state directory under your target directory (targets/hevd/state for example):
kd> .load c:\work\codes\snapshot\target\release\snapshot.dll
kd> !snapshot -h
[snapshot] Usage: s