
Linuxカーネルのページキャッシュ書き込み脆弱性(CVE-2026-31431)におけるalgif_aeadの検出器および概念実証です。非破壊スキャナーとローカル権限昇格エクスプロイトを含みます。
このリポジトリには、Linux algif_aead / authencesn ページキャッシュ scratch-write 脆弱性
CVE-2026-31431 の検出器と PoC が含まれています。
開示記事:https://xint.io/blog/copy-fail-linux-distributions
所有している、または明示的な許可を得たホスト上でのみ使用してください。検出器は非破壊的で、一時ディレクトリ内の sentinel ファイルのみを操作します。PoC および LPE はメモリ内のページキャッシュ状態を変更するもので、実際のローカル権限昇格テクニックであり、許可なく実行することは通常違法行為となります。
algif_aead は AEAD 操作をインプレースで実行します。つまり req->src == req->dst です。入力データが splice() によって通常のファイルから送り込まれると、宛先 scatterlist にはそのファイルのページキャッシュページへの参照が含まれ、カーネルがファイルのページキャッシュコピーに書き込む可能性があります。
authencesn(hmac(sha256),cbc(aes)) は、AAD 内の seqno_lo フィールド(AAD の 4 バイト目から 7 バイト目)に対して 4 バイトの scratch write を実行します。上記のインプレース AEAD と splice() パスを組み合わせることで、攻撃者はこの 4 バイトを読み取り可能なファイルのページキャッシュページに落とし込むことができます。
この変更はディスクに書き戻されず、現在のカーネルページキャッシュにのみ影響します。したがって、ディスク上のファイル内容は変わりませんが、そのページキャッシュを共有する読み取り側は汚染された後の内容を参照することになります。/etc/passwd や /usr/bin/su のような world-readable ファイルがターゲットになり得ます。
ローカルに Rust ツールチェーンと Cargo がインストールされている必要があります。
すべての Rust バイナリをコンパイル:
cargo build --release --bins
コンパイル完了後、以下が生成されます:
target/release/cve_2026_31431_detector
target/release/cve_2026_31431_poc
リポジトリにプリコンパイル済みファイルをコミットする場合は、以下に配置してください:
dist/linux-x86_64/cve_2026_31431_detector
dist/linux-x86_64/cve_2026_31431_poc
dist/linux-x86_64/SHA256SUMS
target/ ディレクトリ全体はコミットしないでください。このディレクトリには Cargo の中間生成物とローカルキャッシュが含まれます。
非破壊検出器のみをコンパイル:
cargo build --release --bin cve_2026_31431_detector
poc.py の Rust 版のみをコンパイル:
cargo build --release --bin cve_2026_31431_poc
Rust 非破壊検出器を推奨します:
./target/release/cve_2026_31431_detector
echo $?
Cargo 経由で直接実行することもできます:
cargo run --release --bin cve_2026_31431_detector
echo $?
Python 検出器の使い方:
python3 test_cve_2026_31431.py
echo $?
終了コードの意味:
| 終了コード | 意味 |
|---|---|
0 | 脆弱性が検出されなかったか、前提条件が満たされていません。例:AF_ALG / authencesn が利用不可。 |
2 | CVE-2026-31431 の影響を受けやすいことが検出されました。 |
一般的な出力の判断:
検出器が実行する操作:
AF_ALG と authencesn(hmac(sha256),cbc(aes)) が利用可能か確認します。sendmsg で AAD を送信し、AAD の seqno_lo を marker PWND に設定します。splice() で sentinel ファイルのページキャッシュページを AF_ALG op socket に送り込みます。recv() を呼び出してアルゴリズムの実行を駆動します。検出器は /usr/bin/su、/etc/passwd、その他のシステムファイルを変更しません。一時的な sentinel ファイルは終了時に削除されます。
Rust 版 poc.py:
./target/release/cve_2026_31431_poc
または:
cargo run --release --bin cve_2026_31431_poc
注意:この PoC は poc.py のロジックに従って /usr/bin/su を開き、脆弱性プリミティブを通じてそのページキャッシュコピーを汚染し、その後 su を実行します。これは非破壊検出プロセスではなく、許可されたテスト環境でのみ実行してください。
python3 exploit_cve_2026_31431.py
python3 exploit_cve_2026_31431.py --shell
このスクリプトは /etc/passwd 内の現在のユーザーの UID フィールドを探し、ページキャッシュ内の UID を 0000 に変更しようとします。ディスク上の /etc/passwd は変更されませんが、システムプロセスがページキャッシュを読み取る際に汚染された後の内容を参照する可能性があります。
制約条件:
1000 から 9999。nscd、sssd、systemd-userdbd などの NSS キャッシュサービスは、/etc/passwd のページキャッシュ変更を隠蔽する可能性があります。/etc/passwd のページキャッシュは、patch と su の実行の間、存在し続ける必要があります。ページキャッシュのクリーンアップ:
python3 -c "import os; fd=os.open('/etc/passwd', os.O_RDONLY); os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED); os.close(fd)"
すでに root シェルを取得している場合は、以下も実行できます:
echo 3 > /proc/sys/vm/drop_caches
再起動でもページキャッシュ状態はクリアされます。
ディストリビューションのカーネル修正が提供されるまで、algif_aead を無効化できます:
sudo tee /etc/modprobe.d/disable-algif-aead.conf <<<'install algif_aead /bin/false'
sudo rmmod algif_aead 2>/dev/null
緩和策を適用後、検出器は通常 检测结论:未发现漏洞 を出力し、トリガーの前提条件が満たされていないことを示し、終了コードは 0 になります。
上流の修正方針は、AEAD 操作をインプレース処理から非インプレース処理に戻し、ページキャッシュページが書き込み可能な destination scatterlist に入らないようにすることです。
| ファイル | 説明 |
|---|
test_cve_2026_31431.py | Python 非破壊検出器。一時的な sentinel ファイルのみを操作し、システムファイルには触れません。 |
src/main.rs | Rust 非破壊検出器。検出ロジックと終了コードは Python 検出器と同一です。 |
src/bin/poc.rs | poc.py の Rust 版。/usr/bin/su のページキャッシュを汚染し、su を実行します。 |
poc.py | Python PoC。 |
exploit_cve_2026_31431.py | Python LPE。/etc/passwd ページキャッシュを汚染して root シェルの取得を試みます。 |
1 |
| テストプロセス中にエラーが発生し、結果を脆弱性の判断根拠にできません。 |
| 出力 | 結論 |
|---|
检测结论:未发现漏洞 | 脆弱性が検出されなかったか、トリガーの前提条件が満たされていません。 |
检测结论:存在 CVE-2026-31431 漏洞 | marker PWND が spliced ページキャッシュページに正常に落ちており、脆弱性が存在します。 |
检测结论:存在疑似 CVE-2026-31431 漏洞 | ページキャッシュが変更されています。marker が期待位置に落ちていなくても、影響を受けていると見なすべきです。 |
测试过程出错,无法判断是否存在漏洞 | 検出に失敗しました。終了コードは 1 で、エラーメッセージに基づいて調査し、再実行する必要があります。 |