Nixでnetconsdをファズするワークフローを作る
原文は Michael Lynch により に公開されました。 このブログを購読する
最近、なかなか寝付けないときは、ファズテストできそうなソフトウェアを探している。
今週のはじめ、Fady Othman氏の投稿「Meta Bug Bounty — Fuzzing ’netconsd’ for fun and profit」を思い出した。コードを徹底的にファズする方法についての良いチュートリアルだ。
多くのファズ関連のブログ記事と同様、この内容も再現するのが少し難しいと感じた。筆者の環境やツールチェーンをどう再現するかを、読者自身が考えなければならないからだ。
そこで、以前xpdfでやったように、Nixを使ってOthman氏のファザーを簡単に再現できるバージョンを作ってみようと思った。xpdfについての投稿の方がずっと丁寧で完成度が高い。こちらは興味のある人向けの簡単なメモに過ぎない。
fuzz-netconsd
数時間かけてnetconsd用に作成したファズ用ワークフローがこちらだ。
gitとNixがインストールされていれば、次のコマンドで私のワークフローを実行できる。
nix run gitlab:mtlynch/fuzz-netconsd
これは私が初めて書いた、ファズツールがコンパイル済みバイナリをシェル経由で実行するのではなく、関数呼び出しを通じてテスト対象のコードを直接呼び出すタイプのファザーだ。honggfuzzやAFL++ではこれを「persistent mode」と呼んでおり、おそらくファズ実行のたびに新しいプロセスを生成するのではなく、一つのプロセスを維持し続けられるからだと思う。
関数呼び出しによるファズは、対象のコードが共有ライブラリすら公開していない場合でも実行できるのが面白いところだ。今回はワークフローのinstallPhaseで、呼び出したいコードを含む.oファイルと、それに対応する.hヘッダーを、そのステップのNix出力ディレクトリにコピーすることでこれを実現した。
必要なヘッダーとオブジェクトファイルが揃ったので、ファズ対象の関数ncrx_processを呼び出すのに必要最小限のコードだけを持つ、シンプルなテストハーネスを書いた。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "ncrx.h"
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
// Convert the random bytes of the payload to a null-terminated string.
char *payload = (char *)malloc(len + 1);
if (!payload) return 0;
memcpy(payload, buf, len);
payload[len] = '\0';
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
perror("clock_gettime");
return 1;
}
uint64_t now = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
struct ncrx *ncrx = ncrx_create(NULL);
// Call the function that we're fuzzing.
ncrx_process(payload, now, 0, ncrx);
// Clean up the resources we allocated.
ncrx_destroy(ncrx);
free(payload);
return 0;
}
永続モードでのファズは、思っていたより簡単だった。netconsdについて多くを学ぶ必要すらなかった。今でもそれが正確に何をするものなのかはよく分かっていないが、ファザーの下でその解析関数の1つを呼び出すのに十分なことは理解できた。
おそらく何も見つからないだろう
Othman氏は自身のファズ作業で100%のカバレッジを達成したと報告しており、これは極めて徹底している。
netconsdのコミット履歴を確認したところ、Othman氏の作業以降、ほとんど動きがない。記事中では明言されていないが、Othman氏が発見した脆弱性を修正したのはおそらくこの変更だろう。
この段階でファズによって何かが見つかるとは思えない。12時間クラッシュが一件も出なかった時点でファザーを止めた。
やり残したこと
- Othman氏はkleeツールを使ってファズコーパス用のエッジケース入力を生成していた。私はそれを実装しなかったが、kleeはすでにNix向けにパッケージ化されているため、ワークフローにうまく組み込めるはずだ。
- Othman氏が使っていたAFL++の代わりに、honggfuzzを使った。honggfuzzの方がシンプルで好みだが、Othman氏はAFL++の各種設定を熟知しており、より高いカバレッジを得ている。
- 私の初期のドラフト実装ではAFL++を使っているので、そちらのバージョンを試したい場合はどうぞ。
記事をランダムに読む
コメント
ログインしてコメントする