4d0a0e2443
release / build (arm64) (push) Waiting to run
release / build (x86_64) (push) Waiting to run
release / build (x86_64-static / musl) (push) Waiting to run
release / build (arm64-static / musl) (push) Waiting to run
release / release (push) Blocked by required conditions
The newest nftables LPE: a use-after-free in the nf_tables transaction-
abort path. An inverted condition (a stray '!') in
nft_map_catchall_activate() makes the abort path process active catch-all
map elements instead of skipping them; a catch-all GOTO element drives a
chain's use-count to zero so a following DELCHAIN frees it while the
catch-all verdict still references it -> UAF, escalatable from an
unprivileged user (userns + nftables) via modprobe_path/selinux_state ROP.
Fixed upstream by f41c5d1; CWE-416, CVSS 7.8; not in CISA KEV. Public
reproduction by FuzzingLabs.
Takes the corpus to 43 modules / 38 CVEs.
🟡 reconstructed trigger, primitive-only, NOT VM-verified — same contract
as nf_tables (CVE-2024-1086). detect() version-gates (catch-all elems
~5.13; Debian backports 6.1.164/6.12.73/6.18.10, 7.0+ inherits) AND
requires unprivileged user_ns clone (else PRECOND_FAIL). exploit() forks
an isolated child, builds a verdict map with a catch-all GOTO element,
provokes an aborting batch to drive the abort-path UAF, observes slabinfo,
and returns EXPLOIT_FAIL — the per-kernel leak + R/W + modprobe_path ROP
is not bundled. kernel_range table verified drift-clean against the live
Debian tracker (the 6.18 branch / 6.18.10 fix is the real forky/sid
backport; the earlier 7.0.10 figure was wrong).
Wired: registry, Makefile, safety rank (35), 6 detect() test rows (version
+ userns gating), CVE_METADATA.json + cve_metadata.c + KEV_CROSSREF.md
(sorted insert, CWE-416/T1068/not-KEV), README + CVES.md + website counts
(43/38) + yellow pill, RELEASE_NOTES v0.9.11, verify-vm target. Credit:
FuzzingLabs + upstream fix f41c5d1. Version 0.9.11.
63 lines
3.0 KiB
Markdown
63 lines
3.0 KiB
Markdown
# NOTICE — nft_catchall (CVE-2026-23111)
|
|
|
|
## Vulnerability
|
|
|
|
**CVE-2026-23111** — a **use-after-free** in the Linux kernel `nf_tables`
|
|
(netfilter) transaction-abort path. `nft_map_catchall_activate()` carries
|
|
an **inverted condition** (a stray `!`): during a transaction *abort* it
|
|
processes *active* catch-all set elements instead of skipping them. A
|
|
catch-all element in an nftables **map** holds a verdict (GOTO/JUMP)
|
|
referencing a chain; the wrong (de)activation drives the chain's
|
|
use-count to zero, so a following `DELCHAIN` frees the chain while the
|
|
catch-all verdict element still references it → UAF.
|
|
|
|
From an **unprivileged** local user — via **user namespaces + nftables**
|
|
(needs `CONFIG_USER_NS` + `CONFIG_NF_TABLES`) — the UAF is escalatable to
|
|
root: leak a kernel address, obtain arbitrary R/W, ROP over
|
|
`modprobe_path` / `selinux_state`.
|
|
|
|
NVD class: **CWE-416** (Use After Free). CVSS v3.1 **7.8 HIGH**
|
|
(`AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`). Affects current distros (Debian
|
|
bookworm/trixie, Ubuntu 22.04/24.04). **Not** in CISA KEV.
|
|
|
|
The fix removed a single character (the inverted `!`).
|
|
|
|
## Research credit
|
|
|
|
- **Fixed upstream** by commit
|
|
`f41c5d151078c5348271ffaf8e7410d96f2d82f8` ("netfilter: nf_tables: fix
|
|
… catch-all … activate"); reported and fixed through the Linux kernel
|
|
security process (NVD lists the source as `kernel.org`; no public
|
|
individual reporter name in the advisory).
|
|
- **Public reproduction + analysis** by **FuzzingLabs** —
|
|
<https://fuzzinglabs.com/repro-cve-2026-23111/> — which the module's
|
|
trigger reconstruction is informed by.
|
|
- Debian security tracker (authoritative backport versions):
|
|
<https://security-tracker.debian.org/tracker/CVE-2026-23111> —
|
|
bookworm 6.1.164 / trixie 6.12.73 / forky·sid 6.18.10 (bullseye/5.10
|
|
still unfixed at time of writing).
|
|
|
|
All credit for finding and analysing this bug belongs to the upstream
|
|
reporter and to FuzzingLabs for the public write-up. SKELETONKEY is the
|
|
bundling and bookkeeping layer only.
|
|
|
|
## SKELETONKEY role
|
|
|
|
🟡 **Trigger (reconstructed) — primitive-only, not VM-verified.** This is
|
|
one more UAF in the corpus's most-covered subsystem (`nf_tables`,
|
|
`nft_set_uaf`, `nft_payload`, `nft_pipapo`, …), shipped on the same
|
|
contract as `nf_tables` (CVE-2024-1086): a fork-isolated trigger that
|
|
fires the bug class and stops.
|
|
|
|
`detect()` version-gates against the Debian backports above (upstream
|
|
thresholds 6.1.164 / 6.12.73 / 6.18.10; catch-all set elements arrived in
|
|
~5.13, so older kernels lack the path) **and** requires unprivileged
|
|
user-namespace clone — a vulnerable kernel with userns locked down is
|
|
`PRECOND_FAIL`. `exploit()` builds a verdict map with a catch-all GOTO
|
|
element and provokes an aborting batch transaction to drive the
|
|
abort-path UAF, observes slabinfo, and returns `EXPLOIT_FAIL`. The
|
|
per-kernel leak + arbitrary-R/W + `modprobe_path` ROP that lands a root
|
|
shell is **not** bundled (per-build offsets refused), and the trigger is
|
|
reconstructed from the public analysis rather than VM-verified — it never
|
|
claims root it did not get.
|