Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2026-98432 — Proof-only PoC for CVE-2026-98432, a Linux IPv4/TCP ireq_opt use-after-free: race trigger and heap-reuse oracle that confirms the UAF without code execution. | Kitploit
Tools/GitHubGitHub/alucard0x1/cve-2026-98432
Defensive ToolsVulnerability AnalysisExploitationFuzzingNetwork SecurityPapers & Research
GitHubalucard0x1/cve-2026-98432

cve-2026-98432

Proof-only PoC for CVE-2026-98432, a Linux IPv4/TCP ireq_opt use-after-free: race trigger and heap-reuse oracle that confirms the UAF without code execution.

View Repository
17425 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-98432 — Linux IPv4/TCP ireq_opt use-after-free PoC

Proof-only proof of concept for CVE-2026-98432 (CVSS 9.8): a remotely triggerable use-after-free in the Linux IPv4/TCP stack.

For authorized security testing only. Run it against systems you own or have explicit permission to test.


What it proves

The PoC triggers the race and detects when the kernel copies bytes out of a freed ip_options_rcu object into a SYN-ACK. It does not create users or files, and it does not implement a code-execution chain.

A hit means the server returned another allocation's marker inside its SYN-ACK — a correct kernel cannot do that. In a controlled test on Ubuntu 24.04.5 with kernel 6.8.0-147-generic (listed vulnerable by Ubuntu; fix queued in 6.8.0-149), a 180-second loopback run produced 21 hits in 320,829 attempts, and a 300-second run produced 22 hits in 616,911 attempts. The kernel stayed clean (tainted=0, no oops).

No packet captures or logs from that host are included here; the PoC's own output is the evidence.


1. The bug

A SYN carrying IPv4 options makes the kernel build an ip_options_rcu (72 bytes, kmalloc-96) for the request socket. When the handshake completes, tcp_v4_syn_recv_sock() hands that object to the child socket without copying it, then clears the pointer in the request socket. A second CPU that already looked the request socket up can still be inside tcp_check_req() → tcp_v4_send_synack() → ip_build_and_send_pkt() → ip_options_build(), reading the same object. Child sockets are not SOCK_RCU_FREE, and inet_sock_destruct() frees inet_opt with a plain kfree(), so if the child is torn down in that window the reader dereferences freed memory.

A second variant exists with request-socket migration (net.ipv4.tcp_migrate_req=1 or a BPF reuseport program); the fix uses kfree_rcu() in both inet_sock_destruct() and tcp_v4_reqsk_destructor().

Introduced in Linux 4.4 (079096f103fa); fixed in mainline 7.3 and backported to 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56 and 7.2.10. Affected: Linux 4.4 and later, unpatched.

Impact ranges from a remote crash (DoS) to kernel memory disclosure and, with a full exploit chain, code execution. This repository stops at proving the use-after-free.


2. How the PoC works

Per attempt:

  1. SYN with a 40-byte IPv4 Timestamp option (or Record Route) → request socket with ireq_opt; the target echoes the option in its SYN-ACK.
  2. Duplicate pure SYN sent just before the handshake ACK, so a second CPU runs the SYN-ACK path against the request socket.
  3. ACK completes the handshake; the child inherits inet_opt, the request socket drops its pointer.
  4. RST (with ACK, so it survives the local RST filter) tears the child down, freeing the object while the duplicate-SYN reader may still be using it.

Oracle. Every attempt embeds a unique 32-bit magic plus a check tag at option offsets 16..23. Three rewrites happen before a user-space reader sees the option:

stageslot
server ip_options_compile() on the SYN4..7 (TS) / 3..6 (RR)
server ip_options_build() for the SYN-ACK8..11 (TS) / 7..10 (RR)
receiving host ip_options_compile() on the SYN-ACK12..15 (TS) / 11..14 (RR)

The marker lives past all three. A SYN-ACK that echoes a different allocation's magic (with tag == magic ^ 0x5a5a5a5a) proves the reader copied from a freed-and-reused object.


3. Requirements

  • Linux, root or CAP_NET_RAW; the automatic RST filter needs CAP_NET_ADMIN (root).
  • Target: unpatched Linux with an IPv4 TCP listener that accept()s.
  • Python 3.8+ (tested on 3.12), standard library only.
  • iptables/nftables for the bare-RST filter.

--proof is self-contained on one host: it starts a loopback listener and races it.


4. Quick start

4.1 Offline self-test (any OS, no sockets)

python3 poc_cve_2026_98432.py --selftest

4.2 Kernel check (run on the host under test)

sudo python3 poc_cve_2026_98432.py --check

Prints the running kernel, the fixed-release table, and relevant sysctls.

4.3 One-command proof (recommended)

sudo python3 poc_cve_2026_98432.py --proof 9000 \
     --duration 180 --workers 6 --spray 2 --spray-rate 1000 \
     --pcap /tmp/proof.pcap

Starts a listener on 127.0.0.1:9000, runs the race, prints a verdict, stops the listener, and removes the temporary firewall rule. Nothing is created on the host — only transient TCP state.

4.4 Probe a remote listener

sudo python3 poc_cve_2026_98432.py --probe <TARGET>:<PORT>

One SYN: reports whether the target is an MPTCP listener and whether it echoes the IPv4 option (required by the oracle).

4.5 Remote race (lab LAN)

sudo python3 poc_cve_2026_98432.py <TARGET>:<PORT> \
     --workers 16 --spray 4 --duration 600 --pcap hits.pcap

Public addresses are refused unless --allow-public is given. The bare-RST filter is installed automatically and removed on exit.

4.6 Standalone lab listener

python3 poc_cve_2026_98432.py --listen 9000 --mptcp

Binds to 127.0.0.1; add --listen-any only for a remote attacker host. The listener accepts and immediately closes each connection with SO_LINGER(0), freeing the child quickly.


5. Reading the output

fieldmeaning
attemptshandshakes started
synacksSYN-ACKs observed (about two per attempt)
hitsSYN-ACK carried another allocation's marker → UAF confirmed
anomaliesmarker parsed but tag mismatch (partial corruption)
leakskernel-pointer-looking value in the echoed bytes
nooptSYN-ACK without the echoed option (syncookies/queue full/stripping)
stalelate SYN-ACK retransmission filtered out (not a hit)
malformedSYN-ACK with ihl < 5 (stale-optlen underflow signature)
timeoutsno SYN-ACK within --timeout
sprayheap-spray SYNs sent

Sample hit:

[!] UAF ORACLE HIT #1 at attempt sport=63042 (expected magic f815ca68 tag a24f9032)
    tcp <TARGET>:9000 -> <CLIENT>:63042 seq=c20ed8ef ack=d212b2b1 flags=0x12
    SYN-ACK echoed magic d4bcdcc7 tag 8ee6869d, belongs to another allocation
    ip options:
    44 28 11 00 03 71 b0 b5 03 71 cc 73 03 71 cc 73
    d4 bc dc c7 8e e6 86 9d 00 00 00 00 00 00 00 00

0x8ee6869d == 0xd4bcdcc7 ^ 0x5a5a5a5a: the tag relation proves the echoed bytes are a valid marker from a different allocation.

Exit codes: 0 = evidence observed, 3 = none, 2 = setup error, 1 = usage/runtime error.


6. Tuning

The race is probabilistic. On the test host, --workers 6 --spray 2 --spray-rate 1000 for at least 3 minutes reproduced it; a 60-second run with --workers 4 --spray 1 --spray-rate 500 produced zero hits on the same host. Do not conclude "not vulnerable" from a short run.

  • --duration — more attempts; the published research took tens of minutes.
  • --workers — more concurrent attempts (8–16 on a LAN).
  • --spray / --spray-rate — keeps kmalloc-96 churning so freed option objects get reused.
  • --lead / --rst-delta / --jitter — microsecond timing sweep; start at 20/40/10 and sweep lead 0–40, delta 0–80.
  • Loopback beats LAN; LAN beats the internet.

7. Lab reproduction

A disposable VM is safer for development. Build a vulnerable 6.12.112 kernel by reverting the two fix lines:

curl -LO https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.112.tar.xz
tar xf linux-6.12.112.tar.xz && cd linux-6.12.112
sed -i 's/kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu);/kfree(rcu_dereference_protected(inet->inet_opt, 1));/' net/ipv4/af_inet.c
sed -i 's/kfree_rcu(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1), rcu);/kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1));/' net/ipv4/tcp_ipv4.c
make defconfig
make -j"$(nproc)"
Download Tool