Creating a Nix Workflow to Fuzz netconsd

Michael Lynch

Nixでnetconsdをファジングするワークフローを作る

最近、眠れないときは、ファジングテストをするソフトウェアを探します。

今週の初め、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」と呼びます。ファジングを実行するたびに新しいプロセスを生成するのではなく、1つのプロセスを継続的に使い続けられるからだと思います。

関数呼び出しによるファジングが興味深いのは、対象コードが共有ライブラリを公開していなくても実行できる点です。ワークフローの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;
}

persistent modeによるファジングは、思っていたより簡単でした。netconsdについて多くを学ぶ必要すらありませんでした。今でもnetconsdが正確には何をしているのか理解していませんが、ファザーからそのパーサー関数の1つを呼び出すには十分なことが分かりました。

おそらく何も見つからない

Othmanはファジングによってカバレッジ100%を達成したと報告しています。非常に徹底した作業です。

netconsdのコミット履歴を確認したところ、Othmanの作業以降、活動はほとんどありませんでした。記事では明言していませんが、Othmanが発見した脆弱性を修正した変更は、おそらくこれだと思います。

現時点でファジングをしても、大したものは見つからないでしょう。クラッシュが発生しないまま12時間経過したところで、ファザーを停止しました。

未完了の作業

  • Othmanはkleeツールを使って、ファジングコーパス用のエッジケース入力を生成していました。私はそこまで実装しませんでしたが、kleeはすでにNix用パッケージとして提供されているので、ワークフローにうまく組み込めるはずです。
  • Othmanが使っていたAFL++ではなく、honggfuzzを使いました。honggfuzzのシンプルさが好みですが、OthmanはAFL++の細かな設定を十分に理解しているため、より高いカバレッジを達成しています。
    • 試してみたい方のために、最初の実装案ではAFL++を使っていました。

原文は Michael Lynch により に公開されました。

この記事は「gpt-5.6-terra」を使用して翻訳されました。