## https://sploitus.com/exploit?id=D039E607-9443-53D4-AA20-578FC0282FE1
# CVE-2026-23111 nf_tables LPE: exposure check and safe lab
Defensive tooling and a reproducible **virtual-machine** lab for CVE-2026-23111,
the `nf_tables` use-after-free local privilege escalation in the Linux kernel (an
inverted element-activity check in `nft_map_catchall_activate()`, the "off by !"
bug). An unprivileged local user can escalate to root, and escape a container,
through unprivileged user namespaces.
This repo ships **no exploit**. It contains a read-only exposure checker, a
script to create a genuinely unprivileged user, and VM definitions so you can
reach the bug safely and study the public research. The full root chain is in
the disclosures linked below, not here.
Full writeup: https://techearl.com/cve-2026-23111-nftables-lpe
## Files
- `check-exposure.sh` โ read-only detector: kernel version vs the fixed build, `nf_tables` presence, the unprivileged-userns precondition, and kernel-log crash signatures.
- `setup-unprivileged-user.sh` โ creates a `labuser` with no sudo and proves it is unprivileged. The point of an LPE test is to start from a user that cannot already become root.
- `Vagrantfile` โ disposable Debian 12 and AlmaLinux 10 VMs (the distros Multipass cannot launch).
## Why a VM and not a container
A container shares the host kernel. Running a kernel exploit inside a container
runs it against your real host kernel, so a "test" can compromise the actual
machine. Use a disposable VM with its own kernel.
## Distros and launchers
| Distro | Launch with | Why |
|---|---|---|
| Ubuntu 24.04 / 22.04 | Multipass (Ubuntu only) | Exodus reproduced on both; 24.04 ships the AppArmor userns restriction on by default, so it shows the mitigation. |
| Debian 12 | Vagrant (`vagrant up debian`) | Exodus reproduced on it; unprivileged userns open by default. |
| AlmaLinux / Rocky 10.1 | Vagrant (`vagrant up alma`) | Matches FuzzingLabs' target kernel `6.12.0-124.x.el10`, so their public trigger reproduces as published. |
Multipass launches only Ubuntu, which is why the others use Vagrant.
## Pinning a vulnerable kernel (per distro)
Each distro needed a different trick to boot a genuinely pre-fix kernel that
still has working networking on a cloud VM:
- **Ubuntu (cloud):** use an old `linux-aws`, not `linux-generic`. The generic
kernel lacks the AWS **ENA** NIC driver and loses SSH on a Nitro instance.
`sudo apt install -y linux-image-6.8.0-1028-aws` (below the fixed `6.8.0-1051`),
set it default in GRUB, reboot. On local virt the generic kernel is fine.
- **Debian:** the main repo only carries the current (patched) kernel. Add a
pre-fix snapshot mirror and install the `cloud` kernel (keeps ENA):
`deb [check-valid-until=no trusted=yes] https://snapshot.debian.org/archive/debian/20251201T000000Z/ bookworm main`,
then `apt install -y linux-image-6.1.0-48-cloud-amd64` (`6.1.172-1`, below the fixed `6.1.174-1`).
- **AlmaLinux/Rocky:** the vulnerable `el10_1` kernels are in the 10.1 vault.
Point dnf at `https://vault.almalinux.org/10.1/BaseOS/x86_64/os/` and
`dnf install kernel-6.12.0-124.38.1.el10_1`, then `grubby --set-default`.
## Run it (any VM)
```bash
# 1. Create a real unprivileged user and prove it cannot sudo.
# (useradd, not Debian's adduser, so it works on RHEL too.)
sudo bash setup-unprivileged-user.sh labuser
# 2. Exposure verdict.
sudo ./check-exposure.sh
# 3. As labuser, the precondition, then the public nft trigger inside a netns.
sudo -u labuser unshare -Ur id # uid=0 in a new userns = precondition open
# (denied on stock Ubuntu 24.04 = mitigation working)
# The public FuzzingLabs trigger (catchall GOTO + aborted batch). Inlined here as
# documentation; this repo does not ship an executable exploit/trigger file.
sudo -u labuser unshare -Urn bash -c '
nft add table inet t; nft add chain inet t c
nft add map inet t m "{ type ipv4_addr : verdict; }"
nft add element inet t m "{ * : goto c }"
printf "delete element inet t m { * }\ndelete element inet t m { 1.2.3.4 }\n" > /tmp/b.nft
nft -f /tmp/b.nft; nft flush ruleset'
```
That sequence runs the buggy abort path; it does **not** include a
privilege-escalation chain, and on a stock kernel it is silent (see below).
## What I actually observed (three flavours, genuine)
| Distro | Vulnerable kernel booted | userns default | Verdict |
|---|---|---|---|
| Ubuntu 24.04 | `6.8.0-1028-aws` | restricted (AppArmor) | MITIGATED, not fixed |
| Debian 12 | `6.1.0-48-cloud` (`6.1.172-1`) | open | EXPOSED |
| AlmaLinux 10.1 | `6.12.0-124.38.1.el10_1` | open | EXPOSED |
The honest finding on the trigger: **on a stock production kernel it is silent.**
It runs the buggy abort path with no crash and no `dmesg` output, even looped
with free-and-reuse. The `KASAN: slab-use-after-free` output in the writeups
comes from a KASAN/debug kernel; weaponizing the latent use-after-free needs the
exploit's heap spray (not in this repo). The lab proves the unprivileged user
reaches the bug, shows Ubuntu's default AppArmor restriction blocking that path,
and gives a clear EXPOSED / MITIGATED / fixed verdict. It does not hand you a
root shell, by design.
## Mitigation
Restrict unprivileged user namespaces (closes the realistic path for the public
exploits), then patch the kernel.
```bash
# Ubuntu 23.10+ (AppArmor-based, keeps legitimate userns users working):
echo "kernel.apparmor_restrict_unprivileged_userns=1" | sudo tee /etc/sysctl.d/99-restrict-userns.conf
sudo sysctl --system
# Elsewhere (blanket disable; set both on Debian/Ubuntu):
printf 'kernel.unprivileged_userns_clone=0\nuser.max_user_namespaces=0\n' | sudo tee /etc/sysctl.d/99-restrict-userns.conf
sudo sysctl --system
# Patch (Ubuntu 24.04 generic fixed at 6.8.0-107.107):
sudo apt update && sudo apt install --only-upgrade linux-image-generic && sudo reboot
```
## References
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-23111
- Exodus Intelligence "Off By !": https://blog.exodusintel.com/2026/06/08/off-by-exploiting-a-use-after-free-in-the-linux-kernel/
- FuzzingLabs reproduction: https://fuzzinglabs.com/repro-cve-2026-23111/
- Ubuntu: https://ubuntu.com/security/CVE-2026-23111
- Red Hat: https://access.redhat.com/security/cve/cve-2026-23111
- Debian: https://security-tracker.debian.org/tracker/CVE-2026-23111
## License
MIT. Defensive and educational use.