
what the fuzz分散型、コードカバレッジガイド、クロスプラットフォームのスナップショットベースファザー。Microsoft Windows 上のユーザーモードまたはカーネルモードターゲット、および Linux ユーザーモード(実験的!)を攻撃するために設計されています。
what the fuzz(略称 wtf)は、分散型、コードカバレッジガイド、カスタマイズ可能、クロスプラットフォームのスナップショットベースファザーで、Microsoft Windows または Linux(実験的、linux_mode 参照)上のユーザーモードまたはカーネルモードターゲットを攻撃するために設計されています。ターゲットの実行は、エミュレータ内で bochscpu を使用する(最も遅いが最も正確)、Windows VM 内で Windows Hypervisor Platform APIs を使用する、または Linux VM 内で KVM APIs を使用する(最速)ことができます。
このファザーは、IDA Pro、人気の AAA ゲーム、Windows カーネル、Microsoft RDP クライアント、NVIDIA GPU Display ドライバ など、幅広いソフトウェアでメモリ破壊の脆弱性を発見しました。
コンパイル済みバイナリは、CI アーティファクト または リリース セクションから Windows と Linux の両方で入手できます。
その歴史や実際のターゲットでの使用方法について詳しく知りたい場合は、以下の記事を読むことをお勧めします 🔥
機能を試す最良の方法は、fuzzer_hevd / fuzzer_tlv_server モジュールを使用することです。target-hevd.7z / target-tlv_server.7z アーカイブをダウンロードし、targets/ ディレクトリに展開します。アーカイブには、すべてのターゲットに必要なディレクトリツリーが含まれています。
inputs は、入力テストケースを配置するフォルダです。outputs は、現在の minset ファイルが保存されるフォルダです。coverage は、.cov ファイルが置かれることが期待されるフォルダです。crashes は、クラッシュが保存される場所です。state は、メモリダンプ(mem.dmp)、CPU 状態(regs.json)、およびシンボルストア(symbol-store.json)が保存されるフォルダです。シンボルストアは、Windows でターゲットを実行するたびに wtf がランタイムに生成するシンプルな JSON ファイルです。このファイルは、シンボル / dbgeng をサポートしない Linux システム上でブレークポイントを設定する場所を知るために使用されます。以下は、最新リリースに添付された target-hevd.7z ファイルをダウンロードし、wtf のクローンの targets ディレクトリに展開したことを前提としています。wtf/targets/hevd に inputs、outputs などのディレクトリがあるはずです。
サーバーは基本的に頭脳であり、すべての状態(集約されたコードカバレッジ、コーパス)を追跡し、テストケースを生成してクライアントに配布します。
ローカルサーバーノードを起動する方法は次のとおりです。```text wtf.exe master --name hevd --max_len=1028 --runs=10000000
`max_len` オプションは生成されるテストケースのサイズを制限するために使用されます。`runs` は生成するテストケースの数、`address` は **wtf** の待ち受け先を指定し、`target` は前述のディレクトリツリーを持つディレクトリです(ユーザーは `--input` / `--output` / `--crashes` でこれらのディレクトリを上書きすることもできます)。`name` はファジングモジュール名を指定し、マスターが定義済みのジェネレーター関数を呼び出せるようにします。
<p align='center'>
<img src="https://assets.kitploit.com/production/public/readmes/4699/4a03fc75eed3ed5a92f7f10def697dbf220ae36b0701f05b37759eb432fc0fd9.webp">
</p>
### ファジングノード
クライアントノードはサーバーによって生成・配布されたテストケースを実行し、結果(コードカバレッジ、結果など)をサーバーに返します。
以下は、*bochscpu* バックエンドを使用するクライアントノードを起動する方法です。```text
wtf.exe fuzz --name hevd --limit 10000000
fuzz サブコマンドは、name オプションと共に使用してどのファザーモジュールを使用するかを指定し、backend は実行バックエンドを指定し、limit はテストケースごとに実行する命令の最大回数を制限します(バックエンドによって、このオプションの意味は異なります)。
テストケース(またはテストケースが入ったフォルダ)を実行したい場合は、run サブコマンドを使用できます。
crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 テストケースを実行する方法は次のとおりです:```
wtf.exe run --name hevd --limit 10000000 --input crashes\crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0
<p align='center'>
<img src="https://assets.kitploit.com/production/public/readmes/4699/49b3ca8582d6314724e5615c687472499d5f8f41d04c9543c0a6a070c51f56f8.webp">
</p>
### コーパスのMinset
コーパスをMinsetするには、ファジングジョブと同様に、サーバーノードと必要な数のクライアントノードを使用する必要があります。`runs`オプションを0に設定するだけです。
これは、`outputs`内のコーパスを`minset`ディレクトリにMinsetする方法です(`inputs`ディレクトリと`outputs`ディレクトリを上書きする方法も示しています)。```
wtf.exe master --name hevd --max_len=1028 --runs=0 --inputs=outputs --outputs=minset
実行バックエンド内で内部調査を行う主なメカニズムは、実行トレースを生成することです。bochscpu はそれを実行する最速のバックエンドです。なぜなら、他のバックエンドではVMXモードを終了するのに非常にコストがかかるからです。
次のようにして、crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 テストケースの実行トレースを生成します:
cd runners/trace
python -m pandora -t samples -tt trace -bp bochscpu x64 -nt 4 -m 512 -tl 10000000 crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0
wtf.exe run --name hevd --limit 10000000 --input crashes\crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 --trace-type=rip
<p align='center'>
<img src="https://assets.kitploit.com/production/public/readmes/4699/340b4b251e378eaf21c6f5ffdd4f013bd2cef89f23a604cffd0ebf897d27c71f.webp">
</p>
実行トレースをシンボル化するには、[symbolizer-rs](https://github.com/0vercl0k/symbolizer-rs) を使用してください。以下は、上記で生成された `crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0.trace` 実行トレースをシンボル化する方法です:```
symbolizer-rs.exe --trace crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0.rip.trace
より多くのコンテキスト認識が必要だと感じた場合、bochscpu バックエンドを使用すると、Tenet トレースエクスプローラーに読み込める実行トレースを生成できます。以下では、memmove 内のクラッシュから開始し、ソースポインタがどこから来ているのかを(ユーザーモード!)遡って調べています:```
wtf.exe run --name hevd --limit 10000000 --input crashes\crash-0xfffff764b91c0000-0x0-0xffffbf84fb10e780-0x2-0x0 --trace-type=tenet
<p align='center'>
<img src="https://assets.kitploit.com/production/public/readmes/4699/34df2f5ca8f378db664d3f01bcbefdd43409e300d256d50e3f4f630eb06cc7be.webp">
</p>
### コードカバレッジトレースの生成
コードカバレッジトレースを生成するには、単に`run`サブコマンドを`--trace-type=cov`オプションとともに使用します。
これは、`minset`フォルダ内のすべてのファイルのコードカバレッジトレースを生成し、`coverage-traces`フォルダに保存する方法です:```
wtf.exe run --name hevd --input minset --trace-path=coverage-traces --trace-type=cov
これらのトレースは記号化されていないため、lighthouseに直接ロードできません。
以下のようにして、coverage-tracesフォルダ内のすべてのファイルを記号化し、結果をcoverage-traces-symbolizedに書き込みます。```
symbolizer-rs.exe --trace coverage-traces -o coverage-traces-symbolized --style modoff
<p align='center'>
<img src="https://assets.kitploit.com/production/public/readmes/4699/8a3c3ca18571abef16a9f87f736fe4d52ac102f41095eab4db32533cb5b198b4.webp">
</p>
そして最後に、それらを[lighthouse](https://github.com/gaasedelen/lighthouse)に読み込むことができます:
<p align='center'>
<img src="https://assets.kitploit.com/production/public/readmes/4699/35d9c25c3d26abf5761fec9e7848ba09d090c7aab32322a740732d82e85964e8.webp">
</p>
また、個別のコードカバレッジを気にしない場合、masterブランチには、実行されたユニークな集計コードカバレッジを含む`coverage.cov`ファイルが保持されています。これにより、ファジングジョブ中にグローバルなコードカバレッジをすぐに確認できます。
## どのように動作しますか?
**wtf**は*実行バックエンド*を介してユーザーモードとカーネルモードを実行し、ユーザーがターゲットにテストケースを挿入することを前提としています。他の古典的なファザーツールとは異なり、**wtf**はあまり重い処理を行いません。ユーザーが行います。ユーザーはハーネス化されたターゲットを非常によく理解している必要があり、ターゲットのオンボーディングは時間がかかる反復プロセスです。ただし、ハッキングに取り組む準備ができていれば、非常に柔軟性があります:)
ターゲットをハーネス化するための通常のワークフローは以下の通りです:
1. ターゲットを、1つの仮想CPUと4GBのRAMを搭載したWindowsを実行するHyper-V VMで動作させます。
1. [KD](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/)を使用してターゲットを目的の状態にします。例えば、[HEVD](https://github.com/hacksysteam/HackSysExtremeVulnerableDriver)のIOCTLハンドラをターゲットにする場合、クライアントが[DeviceIoControl](https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol)を呼び出す直前のユーザーモードでターゲットを停止することを選択しました。これはターゲットによって異なりますが、おそらくファズしたいコードの近くにしたいでしょう。
```
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)}
```
1. [snapshot](https://github.com/0vercl0k/snapshot)を使用して、カーネルクラッシュダンプとCPU状態を含む`regs.json`ファイルを生成します。これらのファイルを`target`ディレクトリの下の`state`ディレクトリにダンプすることをお勧めします(例:`targets/hevd/state`):
```
kd> .load c:\work\codes\snapshot\target\release\snapshot.dll
kd> !snapshot -h
[snapshot] Usage: snapshot [OPTIONS] [STATE_PATH]
Arguments:
[STATE_PATH] The path to save the snapshot to
Options:
-k, --kind <KIND> The kind of snapshot to take [default: full] [possible values: active-kernel, full]
-h, --help Print help
kd> !snapshot c:\work\codes\wtf\targets\hevd\state
[snapshot] Dumping the CPU state into c:\work\codes\wtf\targets\hevd\state\regs.json..
[snapshot] Dumping the memory state into c:\work\codes\wtf\targets\hevd\state\mem.dmp..
Creating c:\\work\\codes\\wtf\\targets\\hevd\\state\\mem.dmp - Full memory range dump
0% written.
5% written. 1 min 50 sec remaining.
10% written. 1 min 17 sec remaining.
15% written. 1 min 30 sec remaining.
[...]
Wrote 4.0 GB in 1 min 32 sec.
The average transfer rate was 44.5 MB/s.
Dump successfully written
[snapshot] Done!
```
1. [ファザーモジュール](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_hevd.cc)を作成し、ターゲットに[テストケースを挿入](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_hevd.cc#L20)するコードを書き、[その](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_hevd.cc#L81)[様々な](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_hevd.cc#L104)[条件](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_hevd.cc#L115)を定義して、[クラッシュを検出](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_hevd.cc#L115)したり[テストケースの終了](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_hevd.cc#L69)を判断します。
1. [Mutator_t](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/mutator.h)インターフェースをサブクラス化することで、独自のミューテーター/ジェネレーターを作成することもできます。[fuzzer_tlv_server.cc](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_tlv_server.cc)は、独自のものを実装する方法を理解するための良い例です。
この時点で、ファザーモジュールが期待通りに動作することを反復して確認する必要があります。実行バックエンドはブラックボックスなので、正しいパスを通り、正しい動作をすることを確認するために実行トレースを生成する必要があります。このフェーズでは、主に[bochscpu](https://github.com/yrp604/bochscpu)バックエンドを使用します。これは完全に決定論的で、起動が速く、実行トレースの生成が可能で、コードカバレッジが無料で得られるなど、開発とプロトタイピングに適した環境です。
モジュールに満足したら、必要に応じて[winhv](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/whv_backend.h) / [kvm](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/kvm_backend.h)バックエンドでも動作するように検討し始めることができます。*bochscpu*バックエンドと他のバックエンドとの大きな違いの1つは、他のバックエンドがコードカバレッジ情報を提供するためにソフトウェアブレークポイントを使用することです。その結果、カバレッジを取得したいモジュールを[IDA](https://hex-rays.com/IDA-pro/)で読み込み、[gen_coveragefile_ida.py](https://github.com/0vercl0k/wtf/blob/HEAD/scripts/gen_coveragefile_ida.py)スクリプトを使用して、wtfで読み込まれる単純なJSONファイルを生成する必要があります。このJSONファイルは、任意のツールを使用して自分で生成することもできます。基本的には基本ブロックの仮想アドレスのリストです。
[WoW64](https://docs.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details)アプリケーションをターゲットにするには、スナップショットを作成する直前に`!wow64exts.sw` Windbgコマンドを使用して64ビットコンテキストに切り替えることもできます(このトリックを共有してくれた[@cube0x8](https://twitter.com/cube0x8)に感謝します!):```
32.kd:x86> !wow64exts.sw
The context is partially valid. Only x86 user-mode context is available.
Switched to Host mode
32.kd> !snapshot
複雑なターゲットは通常、複雑な状態も保持しており、複雑な問題を引き起こすためには、1回のセッションで複数のテストケースを配信する必要があるかもしれません。tlv_server.cc はそのようなサーバの例で、1つのテストケースだけでパース機能を実行してもバグを発見するには不十分です。
このケースに対処するには、この問題を解決する方法の例を示している fuzzer_tlv_server.cc を確認してください。
wtf には、2つの人気のある汎用ミューテータ、libfuzzer と honggfuzz が付属しています。独自のミューテータを提供したり、自分でテストケースを生成したりすることもできます。
それを行うには、Mutator_t インターフェースをサブクラス化し、ファジングモジュールを定義するときにミューテータをインスタンス化する関数を登録します。```c++ class CustomMutator_t : public Mutator_t { public: static std::unique_ptr<Mutator_t> Create(std::mt19937_64 &Rng, const size_t TestcaseMaxSize) { return std::make_unique<CustomMutator_t>(Rng, TestcaseMaxSize); } // ... };
Target_t target("target", Init, InsertTestcase, Restore, CustomMutator_t::Create);
完全な例として、[fuzzer_tlv_server.cc](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_tlv_server.cc) モジュール内の [CustomMutator_t](https://github.com/0vercl0k/wtf/blob/HEAD/src/wtf/fuzzer_tlv_server.cc) クラスを参照してください。
## 実行バックエンド
このセクションでは、実行バックエンド間のさまざまな違いについて簡単に説明します。
### bochscpu
- ✅ 完全なシステムコードカバレッジ (`--edges` でエッジカバレッジ可能),
- ✅ デマンドページング,
- ✅ タイムアウトは命令数で指定でき、非常に正確,
- ✅ 完全な実行トレースをサポート,
- ✅ 完全に決定論的,
- ❌ 短い実行には良いが、長い実行には適さない (IDAをファジングしていた時はKVMより約100倍遅かった).
### whv
- ✔ ソフトウェアブレークポイントによるコードカバレッジ,
- ❌ デマンドページングのため起動が遅い (クラッシュダンプ全体をメモリに読み込む必要がある),
- ✔ タイムアウトはタイマーで実装,
- ✅ 完全な実行トレースをサポートするが遅い (VMXのexitはコストが高い),
- ✔ 非決定性の原因を手動で処理すれば決定論的 (例: `rdrand` を使用する `nt!ExGenRamdom` をパッチする),
- ✔ 長い実行には速度は問題ないようだ (ただし whv には多くのボトルネックがある; IDAをファジングしていた時はkvmより約10倍遅かった).
### KVM
- ✔ ソフトウェアブレークポイントによるコードカバレッジ,
- ✅ UFDD経由でデマンドページングをサポート,
- ✔ タイムアウトはタイマーで実装。✅ ハードウェアがPMU仮想化をサポートしている場合、X回のリタイア命令後に [PMI](https://forum.osdev.org/viewtopic.php?f=1&t=27040) を生成するために使用される (`MSR_IA32_FIXED_CTR0`),
- ✅ 完全な実行トレースをサポートするが遅い (VMXのexitはコストが高い),
- ✔ 非決定性の原因を手動で処理すれば決定論的 (例: `rdrand` を使用する `nt!ExGenRamdom` をパッチする),
- ✅ 長い実行に最も高速 (~500m - 15億命令; IDAをファジングしていた時は *bochscpu* より約100倍、*whv* より約10倍高速).
## ビルド
[CI](https://github.com/0vercl0k/wtf/actions/workflows/wtf.yml) は **wtf** を Ubuntu では [clang++](https://clang.llvm.org/) / [g++](https://gcc.gnu.org/gcc-11/) の両方を使用し、Windows では Microsoft の [Visual Studio](https://visualstudio.microsoft.com/vs/community/) を使用し、OSX では [clang++](https://clang.llvm.org/) を使用してビルドします。
自分でビルドするには、*Visual Studio 開発者コマンド プロンプト* を起動し、[Ninja](https://ninja-build.org/) ジェネレーターを使用する [build-release.bat](https://github.com/0vercl0k/wtf/blob/HEAD/src/build/build-release.bat) を実行するか、Visual Studio ソリューションファイルを生成する [build-release-msvc.bat](https://github.com/0vercl0k/wtf/blob/HEAD/src/build/build-release-msvc.bat) を実行する必要があります。```
(base) wtf\src\build>build-release.bat
[...]
[2/2] Linking CXX executable wtf.exe
(base) wtf\src\build_msvc>..\build\build-release-msvc.bat
[...]
Finished generating code
wtf.vcxproj -> wtf\src\build_msvc\RelWithDebInfo\wtf.exe
Building Custom Rule wtf/src/CMakeLists.txt
特に感謝します: