
# CVE-2026-74586 の非特権概念実証コード LinuxカーネルのSCTP ASCONF use-after-freeに対する非特権の概念実証コードです。rawパケットトリガー、信頼性メトリクス、および構造体オフセットやスプレープリミティブを含む詳細な武器化分析を提供します。
Linux カーネルの SCTP ASCONF(動的アドレス再構成)処理におけるユーズアフターフリーである CVE-2026-74586 のための、自己完結型で非特権の PoC です。バグ自体の功績は上流に報告した Qing Ming に帰されます。修正はコミット beb33f8ee1ca("sctp: clear new_transport when removing a peer")で、2026-08-12 に Cc: stable 付きでマージされました — Red Hat はこれを重要と評価し、サードパーティのトラッカーは CVSS 9.8 としています。
このリポジトリがアドバイザリに追加するもの:
sctp_process_asconf_param() は ADD-IP パラメータによって作成されたトランスポートを asoc->new_transport に格納します。同じ ASCONF チャンク内で同じアドレスに対する DEL-IP があると、そのトランスポートは sctp_assoc_rm_peer() を通じて解放されますが、(修正前は)この関数は new_transport をクリアしません。sctp_process_asconf() が戻ると、sctp_sf_do_asconf() がその古いポインタに対して動作します — 標準カーネルでは目に見える影響は、解放直後のトランスポートのアドレスに向けて送信される HEARTBEAT です。KASAN 下では slab-use-after-free のレポートになります。
ASCONF チャンク 1 つで十分です:
[Address Parameter L] [ADD-IP G] [DEL-IP G]
gcc -O2 -Wall -o poc poc.c
./poc
root 権限は不要です。この PoC はユーザー名前空間とネットワーク名前空間を unshare し、その中で SCTP の sysctl を設定し、ループバック経由でマルチホーム関連を確立したうえで、raw ソケットを用いて細工した ASCONF を注入します。
脆弱なカーネルでの想定出力:
[+] Association established (no AUTH)
[+] server_vtag=0x... captured_tsn=0x...
[*] serial=0x... (= initial_tsn)
[+] Injected 60 bytes
[9222->9111 vt=...] ASCONF-ACK(0x80) len=8
[+] ASCONF-ACK -> server processed ADD-IP + DEL-IP
[9222->9111 vt=...] HB(0x04) len=60 <- kernel using freed transport
[9111->9222 vt=...] ABORT(0x06) len=8
[+] GhostTransport UAF TRIGGERED (ASCONF-ACK received)
[+] HEARTBEAT to ghost address observed (dangling transport USED)
ACK の後の HEARTBEAT が興味深い部分だ。このパケットが存在するのは、カーネルがダングリング状態の new_transport を辿ったからにすぎない。ハートビートが突然返ってきたため、クライアントは直後に ABORT する。
これは新規の研究ではなく、単に文書化が不十分で午後を1つ潰す程度のものなので、次の人のためにここに記しておく:
sctp_rcv() がチェックサムを検証し、不一致なら破棄する。チェックサムフィールドをゼロにした SCTP パケット全体に対して CRC32C(多項式 0x82F63B78、反映)を計算すること。sctp_auth_recv_cid() は入力パス上でステートマシンより前に実行され、addip_noauth_enable=1 であっても未認証の ASCONF を破棄する。この sysctl は sctp_sf_do_asconf() 内のチェックを緩めるだけだからだ。回避策は、そもそもソケットレベルで AUTH をネゴシエートしないこと(SCTP_AUTH_SUPPORTED の setsockopt を行わない)であり、これにより peer.auth_capable が false のままとなり、両方のチェックを通過できる。上流コミットの Fixes: タグは 6af29ccc223b("sctp: Bundle HEARTBEAT into ASCONF_ACK")であるため、このコードは古い。mainline で修正され、stable シリーズにもバックポートされている(Debian トラッカー:sid では 7.1.9-1 から、trixie-security では 6.12.107 で修正済み)。2026-09-09 時点の Kali rolling は全スイートで 7.1.5-1kali1 を出荷しており、これはすべてより前のバージョンだ — これがこの PoC の実用的な関連性の主な点である。
さらに進めたい人向け — QEMU 上の 7.1.5 に対して測定し、出荷されている sctp.ko の objdump -d から得たオフセット:
| フィールド | オフセット |
|---|---|
| flowi(88 バイト) | 0x30 |
| ipaddr | 0x88 |
| af_specific | 0xa8 |
| asoc | 0xb0 |
| dst | 0xe0 |
| state | 0x15c |
| rcu | 0x2b0 |
sctp_association->new_transport は 0x6b0 にある。この表は実行中のカーネル上で pahole -C sctp_transport /sys/kernel/btf/vmlinux から得たものだ — この表の以前のリビジョンには誤った ipaddr オフセット(0x68、flowi の数え間違いによるもの)が記載されていた。BTF が真実の源である。
sctp_transport_destroy_rcu)であり、この経路で二重解放はない。ソケットを閉じて 2 回の解放を得ようと期待していたなら——sctp_association_free() はトランスポートリストを走査するだけで、rm_peer() はすでにゴーストをアンリンクしている。それに一晩費やすな。sctp_outq_select_transport() はチャンクの +0xe8 にある chunk->transport から +0x15c の state を読む。state=1(ACTIVE)でスプレーされた再確保オブジェクトは解放後のカーネル挙動を変える——そのオブジェクトは参照されている。sctp_outq_select_transport() が古いトランスポートポインタから state=0xFFFF(スラブのゴミ)を読むのを捉えた。帰結:スプレーはトリガーの後ではなく前にキャッシュを事前グルーミングする必要がある——この経路ではグレースピリオドが期限切れになる前にオブジェクトが読まれる。*(p+0x288) を p+0x288 と比較する。これは自己ポインタである。スラブアドレスを知らずにスプレーで突破することはできない。つまりこのバグは af_specific 制御が命令ポインタ制御に変わる前に情報リークを必要とする。af_specific 自体が間接呼び出しサイト(*(af_specific+0x18)、rdi = transport)なので、リークが存在すればそれが賞品である。setsockopt(SCTP_AUTH_KEY) は同じ kmalloc-1k キャッシュに着地する。ヘッダは struct sctp_authkey { assoc_id; keynumber; keylength; key[] } であり、AUTH はまずソケットごとに SCTP_AUTH_SUPPORTED と sctp_assoc_value で有効化する必要があることを忘れるな——単なる int では EINVAL になる。これはトリガー/クラッシュ PoC である。権限昇格ではなく、この リポジトリはそれを主張しない。VM 内の自分のカーネルに対して実行せよ。
テスト済み: 7.1.5+kali-amd64 (Kali rolling) および 7.0.12+kali-amd64。
ロジックのカーネル由来部分は GPL-2.0。残りは好きにしてよい。 認可されたセキュリティテストおよび研究専用。
acklock.c — ASCONF-ACK ソフトロックアップ(全 7.1.x で未修正)同じコード経路にある 2 つ目の未パッチのカーネルバグで、7.1.5 で実証された:
sctp_verify_asconf() は最小長のない ERR_CAUSE TLV を受け入れ、パラメータを PAD4 整列で走査する一方、
sctp_get_asconf_response()(ASCONF-ACK のコンシューマ)は生の長さで進む。
ERR_CAUSE TLV の長さが 5 の細工された ASCONF-ACK はコンシューマを 3 バイトずらし、
次の 4 バイトが length = 0 のパラメータヘッダとして読まれ、asconf_ack_len -= 0 が
永遠に回り続ける——softirq 内の無限ループ(ksoftirqd が 100% に張り付き、CPU が枯渇、
7.1.5 での実験室実行 3/3 で clocksource-watchdog タイムアウトにより確認済み)。
メインラインでは 2cb0b0b1ed69(「sctp: fix soft lockup from unpadded
ASCONF-ACK parameter iteration」、2026-08-30)で修正済み——linux-7.1.y の
HEAD(7.1.13)には存在しないため、リリースされたすべての 7.1.x カーネル、
Kali の最新版を含め、影響を受ける。リモートで、確立済みのアソシエーションと
net.sctp.addip_noauth_enable=1(または同じウィンドウ内の AUTH バイパス)が必要。
poc.c と同様にビルドして実行する:
gcc -O2 -Wall -o acklock acklock.c && ./acklock
VMを監視します。ポイズンACKから数秒以内にCPUが固まります
(clocksource watchdogのタイムアウト。perf-NMI-watchdog有効なカーネルでは、
sctp_get_asconf_response でおなじみの BUG: soft lockup スプラットが発生します)。