Files
SKELETONKEY/modules/fragnesia_cve_2026_46300/MODULE.md
T
leviathan a8c8d5ef1f modules: add dirtydecrypt (CVE-2026-31635) + fragnesia (CVE-2026-46300)
Two new page-cache-write LPE modules, both ported from the public V12
security PoCs (github.com/v12-security/pocs):

- dirtydecrypt (CVE-2026-31635): rxgk missing-COW in-place decrypt.
  rxgk_decrypt_skb() decrypts spliced page-cache pages before the HMAC
  check, corrupting the page cache of a read-only file. Sibling of
  Copy Fail / Dirty Frag in the rxrpc subsystem.

- fragnesia (CVE-2026-46300): XFRM ESP-in-TCP skb_try_coalesce() loses
  the SHARED_FRAG marker, so the ESP-in-TCP receive path decrypts
  page-cache pages in place. A latent bug exposed by the Dirty Frag
  fix (f4c50a4034e6). Retires the old _stubs/fragnesia_TBD stub.

Both wrap the PoC exploit primitive in the skeletonkey_module
interface: detect/exploit/cleanup, an --active /tmp sentinel probe,
--no-shell support, and embedded auditd + sigma rules. The exploit
body runs in a forked child so the PoC's exit()/die() paths cannot
tear down the dispatcher. The fragnesia port drops the upstream PoC's
ANSI TUI (incompatible with a shared dispatcher); the exploit
mechanism is reproduced faithfully. Linux-only code is guarded with
#ifdef __linux__ so the modules still compile on non-Linux dev boxes.

VERIFICATION: ported, NOT yet validated end-to-end on a
vulnerable-kernel VM. The CVE fix commits are not pinned, so detect()
is precondition-only (PRECOND_FAIL / TEST_ERROR, never a blind
VULNERABLE) and --auto will not fire them unless --active confirms.
macOS stub-path compiles verified locally; the Linux exploit-path
build is covered by CI (build.yml, ubuntu) only. See each MODULE.md.

Wiring: core/registry.h, skeletonkey.c, Makefile, CVES.md, ROADMAP.md.
2026-05-22 18:22:30 -04:00

4.0 KiB

fragnesia — CVE-2026-46300

🟡 PRIMITIVE / ported. Faithful port of the public V12 PoC into the skeletonkey_module interface. Not yet validated end-to-end on a vulnerable-kernel VM — see Verification status below.

Summary

Fragnesia ("Fragment Amnesia") is an XFRM ESP-in-TCP local privilege escalation. skb_try_coalesce() fails to propagate the SKBFL_SHARED_FRAG marker when moving paged fragments between socket buffers — so the kernel forgets that a fragment is externally backed by page-cache pages spliced in from a file. The ESP-in-TCP receive path then decrypts in place, corrupting the page cache of a read-only file.

Fragnesia is a latent bug exposed by the Dirty Frag fix: the candidate patch cites the Dirty Frag remediation (f4c50a4034e6) as a commit it "fixes". It is the same page-cache-write bug class as Copy Fail / Dirty Frag, reached through a different code path.

Primitive

  1. Build a 256-entry AES-GCM keystream-byte table via AF_ALG ecb(aes) — for any wanted output byte, this yields the ESP IV whose keystream byte XORs the current byte to the target.
  2. Enter a mapped user namespace + network namespace, bring loopback up, and install an XFRM ESP-in-TCP state (rfc4106(gcm(aes)), TCP_ENCAP_ESPINTCP).
  3. A receiver accepts a loopback TCP connection and flips it to the espintcp ULP; a sender splice()s page-cache pages of the target file into that TCP stream behind a crafted ESP prefix.
  4. The coalesce bug makes the kernel decrypt the spliced page-cache pages in place — one chosen byte per trigger.

The exploit rewrites the first 192 bytes of a setuid-root binary (/usr/bin/su and friends) with an ET_DYN ELF that drops privileges to 0 and execves /bin/sh.

Operations

Op Behaviour
--scan Checks unprivileged-userns availability + a readable setuid carrier ≥ 4096 bytes. With --active, runs the full ESP-in-TCP primitive against a disposable /tmp file and reports VULNERABLE/OK empirically.
--exploit … --i-know Forks a child that places the payload into the carrier's page cache and execs it for a root shell. --no-shell stops after the page-cache write.
--cleanup Evicts the carrier from the page cache. The on-disk binary is never written.
--detect-rules Emits embedded auditd + sigma rules.

Preconditions

  • Unprivileged user namespaces enabled. On Ubuntu, AppArmor blocks this by default — sysctl kernel.apparmor_restrict_unprivileged_userns=0 (or chain a separate bypass). This is the scoping question the old _stubs/fragnesia_TBD raised; the module ships and reports PRECOND_FAIL cleanly when the userns gate is closed.
  • CONFIG_INET_ESPINTCP built into the kernel.
  • A readable setuid-root binary ≥ 4096 bytes as the payload carrier.
  • x86_64 (the embedded ELF payload is x86_64 shellcode).

Port notes

The upstream PoC renders a full-screen ANSI "smash frame" TUI (draw_smash_frame + terminal scroll-region escapes). That is not ported — it cannot coexist with a shared multi-module dispatcher. Progress is logged with [*]/[+]/[-] prefixes, gated on --json. The exploit mechanism itself is reproduced faithfully.

Verification status

This module is a faithful port of https://github.com/v12-security/pocs/tree/main/fragnesia, compiled into the SKELETONKEY module interface. It has not been validated end-to-end against a known-vulnerable kernel inside the SKELETONKEY CI matrix.

detect() deliberately does not return a kernel-version-based patched/vulnerable verdict: the CVE-2026-46300 fix commit is not yet pinned here. Instead:

  • preconditions missing → PRECOND_FAIL
  • preconditions present, no --activeTEST_ERROR so --auto does not fire it blind
  • --active → empirical VULNERABLE / OK via the /tmp sentinel probe

Before promoting to 🟢: pin the fix commit + branch-backport thresholds, add a kernel_range, and validate on a vulnerable VM.