DF-2609 / verdict.json
{ "finding_id": "DF-2609", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "REPRODUCED on the stock INVARIANTS guest: sysctl net.inet6.icmp6.nodeinfo defaults to 3 (in6_proto.c:398, live-confirmed) and a single unauthenticated ICMPv6 NI query (RFC 4620) to any of the host's unicast addresses returns the system hostname (QTYPE FQDN, no-subject oldfqdn path icmp6.c:1182-1186, bit-0 gate icmp6.c:1275) and the complete IPv6 address inventory across all interfaces incl. link-local (QTYPE NODEADDR, ni6_store_addrs icmp6.c:1660-1806). hostname 'dfbsd' and all 4 addresses disclosed; negative control (foreign dst) silent; sysctl=0 silences the responder (live fix matrix 0/1/3). Recon-grade info disclosure, no memory-safety involvement; NI replies carry no uninit/pad bytes (exact lengths).", "exploit_chain": "", "evidence": "run.log: 'FQDN ttl=0x00000000 name=dfbsd' after a 16-byte query to ::1; 'NODEADDR count=4' listing fe80::5054:ff:fe12:3456/2001:db8::1/::1/fe80::1 exactly matching ifconfig; queries to 2001:db8::1 (global unicast) answered; 2001:db8::99 -> 'NO REPLY (timeout)'; sysctl matrix: nodeinfo=0 -> all queries time out, =1 -> FQDN only, restored 3 -> 5/5 replies. env.txt: 'net.inet6.icmp6.nodeinfo: 3' on uname 'DragonFly dfbsd 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 UTC 2026'.", "kernel_refs": [ "sys/netinet6/in6_proto.c:398", "sys/netinet6/icmp6.c:632", "sys/netinet6/icmp6.c:1142-1159", "sys/netinet6/icmp6.c:1182-1186", "sys/netinet6/icmp6.c:1275", "sys/netinet6/icmp6.c:1279", "sys/netinet6/icmp6.c:1660-1806", "sys/netinet6/raw_ip6.c:326", "sys/netinet6/raw_ip6.c:393-418" ], "poc_changes": "Standalone raw-socket NI query tool written from scratch (no seed). Two fixes during verification: (1) raw ICMPv6 sockets deliver replies WITHOUT the IPv6 header - parser offset auto-detection added; (2) nodeaddr queries require a 16-byte subject equal to the queried destination because ICMP6_NI_SUBJ_IPV6==0 (icmp6.h:165) - subject added.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 120, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o niq niq.c", "run_cmd": "sh run.sh (as root on the DF guest; canonical matrix in run.sh/run.log)", "code_hash": "8b07a5b9eb41826e31905959ff38f1cb69a5caef78e7c2374e9b25be3e5b2390", "notes": "Query injection needs a raw socket (root) only as a test convenience; the responder itself serves any remotely-routed packet with no auth/capability/scope check - the threat is the remote unauthenticated peer. Guest left clean (vm.sh reset with-src after run; kmem/sysctls were not touched by this PoC).", "recommended_fix": "Default icmp6_nodeinfo to 0 in in6_proto.c:398 (match FreeBSD); defense-in-depth: restrict responder to link-local destinations in ni6_input.", "fix_status": "fixed", "fix_kernel_uname": "", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Operational fix validated live without a kernel rebuild: the fix.diff only changes the compiled-in default of the exact sysctl variable exercised at runtime. Baseline (default 3): hostname + full address inventory disclosed on every query. With net.inet6.icmp6.nodeinfo=0 (the fixed default, set at runtime): 0 replies across all query types (run.log FIX CHECK section). Rebuild of the one-line default flip is trivially equivalent and was not separately booted.", "fix_evidence": "run.log: 'sysctl -w net.inet6.icmp6.nodeinfo=0' followed by './niq ::1 fqdn' -> 'NO REPLY (timeout)' and './niq ::1 nodeaddr 002e' -> 'NO REPLY (timeout)'; restored to 3 -> replies return." } |