
# CVE-2026-74586 の非特権概念実証コード LinuxカーネルのSCTP ASCONF use-after-freeに対する非特権の概念実証コードです。rawパケットトリガー、信頼性メトリクス、および構造体オフセットやスプレープリミティブを含む詳細な武器化分析を提供します。
CVE-2026-74586 用の自己完結型・非特権 PoC。Linux カーネルの SCTP ASCONF(動的アドレス再設定)処理における use-after-free を利用します。
バグ自体の功績は、上流に報告した 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() が戻ると、 が古いポインタに対して動作します。標準カーネルでは、目に見える影響は解放されたばかりのトランスポートのアドレスに向けて HEARTBEAT が送信されることです。KASAN の下では slab-use-after-free レポートとなります。
sctp_sf_do_asconf()ASCONF チャンクは 1 つで十分です:
[Address Parameter L] [ADD-IP G] [DEL-IP G]
gcc -O2 -Wall -o poc poc.c
./poc
root は不要です。PoC はユーザー名前空間とネットワーク名前空間を分離し、その中で 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 します。
これは新しい研究ではありませんが、文書化が不十分なために半日を費やすことになるため、次の人のためにここに記しておきます:
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 bytes) | 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 オフセット(flowi の数え間違いによる 0x68)が含まれていました。BTF が正しい情報源です。
sctp_transport_destroy_rcu)。このパスに double-free はありません。ソケットを閉じて 2 回の解放を得ようと考えていた場合 — sctp_association_free() はトランスポートリストのみを走査し、rm_peer() はすでにゴーストのリンクを解除しています。そのアイデアに夜を費やさないでください。sctp_outq_select_transport() は、チャンクの +0xe8 にある chunk->transport から +0x15c の state を読み取ります。state=1(ACTIVE)でスプレーされた再利用オブジェクトは、解放後にカーネルの動作を変更します。オブジェクトが参照されているのです。sctp_outq_select_transport() が古いトランスポートポインタから state=0xFFFF(slab ガベージ)を読み取るのを捕捉しました。結果: スプレーはトリガーの後ではなく前にキャッシュを事前グルーミングする必要があります。このパスでは、猶予期間が満了する前にオブジェクトが読み取られるためです。*(p+0x288) を p+0x288 と比較します。これは自己ポインタです。slab アドレスを知らなければ、これをスプレーで乗り越えることはできません。つまり、このバグは af_specific 制御が命令ポインタ制御に変わる前に、情報漏洩を必要とします。af_specific 自体は間接呼び出しサイトです(rdi = transport で *(af_specific+0x18))。したがって、情報漏洩が存在すれば、そこが目標となります。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。残りは自由に使用してください。許可されたセキュリティテストおよび研究目的に限ります。