プロジェクト
実行方法: ./script.sh
GitHub リポジトリ - https://github.com/LaCinquette/practice-22-23
実施手順
-
脆弱性を探すため、FFmpegプロジェクトを選択しました。その中で、要件に一致するコミットを見つけました。具体的には:
- CWE-476(ヌルポインタの参照外し)のタイプに一致
-
以下の内容のDockerfileを作成しました:
- ベースイメージとしてUbuntu 22.04を選択
- パッケージやその他のコマンドのインストール中にコマンドラインとの対話を排除するため、
DEBIAN_FRONTEND=nointeractiveを設定
- 公式wikiに記載されている必要な依存関係をインストール
- 作業場所(workdirフォルダ)を準備
- まだ修正されていない脆弱性を含むコミットをダウンロード、解凍して作業場所に移動
- makeユーティリティを使ってプログラムのビルドを実行
- エラーのある必要なオブジェクトファイルを検索し、workspace/outディレクトリにコピーするスクリプト copy_out.sh を作成
- コンテナ起動時に実行されるべきスクリプト copy_out.sh の実行手順を残す
-
自動化のため、イメージをビルドしてコンテナを起動し、そこからファイルを受け取ってカレントディレクトリに移動するスクリプト script.sh を作成します:
- 現在のoutフォルダを削除(存在する場合)
- ffmpeg_imageという名前でイメージをビルド
- ビルドしたイメージに基づいてコンテナを起動し、以下のパラメータを渡します:
--rm: 終了時にコンテナを自動削除
-v $PWD/out:/workspace/out: オブジェクトファイルがホストに受け渡される一時ディレクトリをマウント
- outフォルダから必要なファイルをコピー
- outフォルダを削除
脆弱性の分析
情報源:
- 修正済みのバグを含むコミット
- 脆弱性に関するGitHubのページ
- 脆弱性に関するセキュリティ研究者のメール
分析:
問題:
ffmpeg -c:v dnxhd -i poc.mov -y output.ts コマンドにより、特別に作成された .mov ファイルがプログラムに入力として渡されます
- DNxHD形式をパースするために、dnxhd_parserファイル内の dnxhd_parse 関数が呼び出されます
- この関数は同じファイル内の dnxhd_find_frame_end 関数を呼び出しますが、特定の条件下では終端を見つけられず、エラーコードではない負の数を返します
- この数値は他のパラメータとともに、フレームを結合するために ff_combine_frame 関数(parserファイル内)に渡されます
- この数値はエラーコードではないため、ff_combine_frame はこれをシフトとして認識し、バッファ内のこれらのバイトを再読み込みしようとします。しかし、その時点でバッファが空であるため、ヌルポインタの参照外しが発生し、Segmentation fault に至ります
アセンブリ内:
0x08000d4e - セクションの開始
-
movsxd rcx, dword [rbx + 0xc]
rcxレジスタで pc->buffer への参照を取得
-
add rcx, rdi
pc->buffer に next を加算
-
add rcx, qword [rbx]
next と pc->buffer に pc->last_index を加算
-
movzx edi, byte [rcx]
rcxのアドレスのバイトを読み取るが、pc->buffer が最初は null のため Segmentation fault が発生
解決策:
例外的なケースを適切に処理することで、未割り当てのメモリ領域へのアクセスを防ぎます。残りバイト数が負の数であることを検出した場合は、ループをスキップしてファイルの処理を続行します。