
Dirty Fragは、特権のないユーザーがrootアクセスを取得できるようにするLinuxローカル特権昇格(LPE)脆弱性チェーンに関するレポートです。
Linuxカーネルのローカル権限昇格チェーンに対するエクスプロイト再現・検知ラボ。
ステータス: 検証済み。 ラボ(カーネル 6.18.9+kali-amd64)において、再現、ファイルレス検証、およびシステムコールレベルの検知を完了しました。本ドキュメントはラボログです。以下のすべての記述は再現実行中に観測されたものです。スクリーンショットと成果物はVMからの実際のキャプチャです。
Dirty Frag は、Linuxカーネルにおける2つの決定的なロジックバグを組み合わせたものです。これらのバグにより、権限のないローカルユーザーが読み取り専用ファイル(例: /usr/bin/su)のページキャッシュを上書きし、rootシェルを取得できます:
| バリアント | CVE | シンク | トリガーパス | 非特権ユーザー名前空間が必要か |
|---|---|---|---|---|
| xfrm‑ESP ページキャッシュ書き込み | CVE‑2026‑43284 | esp_input() 内の crypto_authenc_esn_decrypt() | UDP‑encap を使用した socket(AF_INET)、続いて xfrm_input() | はい(CAP_NET_ADMIN) |
| RxRPC ページキャッシュ書き込み | CVE‑2026‑43500 | rxkad_verify_packet_1()(pcbc(fcrypt)) | socket(AF_RXRPC) | いいえ |
両バリアントは、Dirty Pipe および Copy Fail と同じ根本パターンを使用します。splice(2) システムコールは、ファイルのページキャッシュページへの参照を送信側 sk_buff の frag スロットに配置します。攻撃者はこのファイルを読み取り専用でアクセスできます。受信側のカーネルコードは、その frag 上でインプレース暗号STOREを実行します。これによりRAM内のページキャッシュが変更されます。ディスクへの書き込みは発生しないため、ファイル整合性モニタリング(AIDE、Tripwire)では検知できません。この攻撃は決定的です。レースウィンドウはなく、失敗時のカーネルパニックもありません。
cac2661c53f3(2017‑01)から f4c50a4034e6(2026‑05‑05 パッチ適用)まで2dc334f1a63a(2023‑06)から aa54b1d27fe0(2026‑05‑10 パッチ適用)までCVE-2026-43284 = 8.8(高)、CVE-2026-43500 = 7.8(高)Dirty Frag はファイルレスLPEです。ディスク上のファイルではなく、メモリ内のページキャッシュを破壊します。従来のファイル整合性モニタリングでは検知できません。検知はシステムコール層で行う必要があります。このチェーンは以下のシステムコールプリミティブを使用します: socket(AF_ALG)/socket(AF_RXRPC)、splice、および unshare(CLONE_NEWUSER|CLONE_NEWNET)。ESPパスは AF_INET UDP および netlink ソケットも作成します。この層が本リポジトリの検知エンジニアリングの焦点です。
両バリアントは同じシンクを使用します: 攻撃者が splice(2) で配置したページキャッシュページ上にバイトをSTOREするインプレース暗号です。
UDP_ENCAP_ESPINUDP で構成します。vmsplice でパイプに登録し、その後 splice で対象ファイルオフセットの /usr/bin/su から16バイトを登録します。splice がパイプを送信ソケットにプッシュします。splice_to_socket() は MSG_SPLICE_PAGES を設定します。これにより /usr/bin/su のページキャッシュページが skb->frags[0] に直接配置されます。xfrm4_udp_encap_rcv、続いて xfrm_input、続いて esp_input()。脆弱な skip_cow 分岐(!skb_cloned() && !skb_has_frag_list())は skb_cow_data() をバイパスします。ページキャッシュページをソースとデスティネーションの両方としてインプレースAEAD復号を実行します。crypto_authenc_esn_decrypt() はESNの上位32ビットのSTOREを発行します。その値は replay_esn->seq_hi です。攻撃者はSA登録時に XFRMA_REPLAY_ESN_VAL netlink属性でこの値を選択します。攻撃者は場所(spliceオフセット)と値(4バイト)の両方を制御します。認証検証はストア後に実行されるため、暗号層が書き込みをフラグ付けすることはありません。このバリアントは CAP_NET_ADMIN を必要とし、unshare(CLONE_NEWUSER|CLONE_NEWNET) を使用します。
rxkad_verify_packet_1() は、spliceで固定されたskb frag上で直接、単一ブロックの pcbc(fcrypt) 復号を実行します。最初にデータをコピーしません。攻撃者はセッションキー(add_key("rxrpc", …))を選択し、decrypt(ciphertext) が desired_plaintext と等しくなるようにします。これにより8バイトのSTOREが生成されます。このバリアントは /etc/passwd をターゲットにします。ユーザー名前空間は不要です。rxrpc.ko モジュール(Ubuntuではデフォルトでロード)が必要です。
公開PoCは /usr/bin/su をターゲットにします。4バイトずつ48回のESPストア(ファイルオフセット0で192バイト)を書き込みます。最初のページキャッシュバイトを静的rootシェルELFに置き換えます。ELFエントリポイントは setgid(0); setuid(0); setgroups(0,NULL); execve("/bin/sh", …) を実行します。単一の execve("/usr/bin/su") でrootシェルが得られます。
ESPパッチ(メインライン f4c50a4034e6)は、splice() 経由で到着するページfragに SKBFL_SHARED_FRAG フラグをマークします。esp_input() の skip_cow 分岐は現在このフラグもチェックします。共有fragのskbは、インプレースAEAD復号の前に skb_cow_data() を経由します。
RxRPCパッチ(メインライン aa54b1d27fe0)は、既存の skb_cloned() チェックの隣に skb->data_len チェックを追加します。カーネルは、インプレース pcbc(fcrypt) 復号の前に、ページデータを含む非線形skbをコピーします。
| コンポーネント | 詳細 |
|---|---|
| ハイパーバイザー | VirtualBox |
| ターゲットVM | Kali Linux 2026.1(脆弱な状態にスナップショット復元) |
| カーネル | 6.18.9+kali‑amd64(2026年5月の修正より古い) |
| エクスプロイトPoC | V4bel/dirtyfrag(単一Cファイル) |
| 検知 | auditd(detection/dirtyfrag.rules のルール) |
VirtualBoxラボセットアップのスクリーンショット:

.
├── README.md # 本ラボログ
├── detection/
│ ├── dirtyfrag.rules # auditd システムコールレベル検知ルール
│ ├── ausearch_dirtyfrag_observed.txt # 実際のエクスプロイト検知出力
│ ├── sigma/
│ │ └── dirty_frag_exploit.yml # SIEM検知用Sigmaルール
│ └── yara/
│ └── dirty_frag_exploit.yar # ディスク/メモリ上のPoCコード用YARAルール
├── mitigation/
│ └── dirtyfrag_mitigation.sh # モジュールブラックリスト + ページキャッシュフラッシュ
├── poc/
│ └── check_vulnerable.py # 非破壊的な事前チェッカー
├── reports/
│ └── incident-dirtyfrag.md # インシデントレスポンスプレイブック
└── screenshots/ # ラボVMからの実際のキャプチャ
poc/check_vulnerable.py を実行し、カーネル/モジュール/usernsを確認testuser を作成/usr/bin/su ハッシュをキャプチャdrop_caches または再起動)detection/dirtyfrag.rules をデプロイし、auditdアラートを検証reports/incident-dirtyfrag.md)cat /etc/os-release | head -3
uname -r
カーネルバージョン確認のスクリーンショット:

カーネルは2026年5月の修正(f4c50a4034e6 / aa54b1d27fe0)より古い必要があります。その日付以降に apt upgrade を実行した場合、エクスプロイトは失敗します。トラブルシューティングを参照してください。
安全なチェッカーが、VMが対象となり得るかどうかを報告します。実行中のカーネル、esp4/esp6/rxrpc モジュールの存在、非特権ユーザー名前空間が利用可能かどうかをチェックします。ESPバリアントはこれらの名前空間を必要とします。
python3 poc/check_vulnerable.py
期待される判定: [*] potentially vulnerable -- proceed in a disposable VM only
非特権の testuser は、特別な権限のない攻撃者をシミュレートします。
sudo useradd -m testuser
sudo passwd testuser
su - testuser
id
スクリーンショット: id はUID 1001を示します。これは非rootアクセスを確認します。

非特権アカウントから:
git clone https://github.com/V4bel/dirtyfrag.git
cd dirtyfrag
gcc -O0 -Wall -o exp exp.c -lutil
./exp
成功すると、エクスプロイトは /usr/bin/su のページキャッシュをパッチします。4バイトずつ48回のESPストア(ファイルオフセット0で192バイトのrootシェルELF)を書き込みます。その後、forkpty でインタラクティブなrootシェルをドロップします。
モジュールの可用性、ソースレビュー、クリーンなコンパイルのスクリーンショット:

id
whoami
スクリーンショット: ./exp 実行後、id は uid=0(root) を示します。

sha256sum はページキャッシュ経由で読み取ります。エクスプロイトの書き込みがアクティブな間、ハッシュは元のものと異なります。フラッシュ後、ハッシュは元のものに戻ります。この前後のペアは、ディスク上のバイナリが決して変更されていないことを証明します。
sha256sum /usr/bin/su # 1) ページキャッシュが汚染されている間 -> 異なるハッシュ