Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/V4bel/dirtyfrag/llms.txt

Use this file to discover all available pages before exploring further.

Neither the xfrm-ESP variant nor the RxRPC variant works universally on its own. The ESP variant needs an unprivileged user namespace, which Ubuntu can block via AppArmor policy. The RxRPC variant needs rxrpc.ko, which is absent from most non-Ubuntu distributions. By running the two variants in sequence and falling back from one to the other, a single binary achieves root on all major Linux distributions: whichever blind spot blocks the first attempt is filled in by the second.

The problem: each variant has a blind spot

ESP variant

Requires unshare(CLONE_NEWUSER | CLONE_NEWNET) to gain CAP_NET_ADMIN for XFRM SA registration.Blind spot: Ubuntu applies an AppArmor policy (kernel.apparmor_restrict_unprivileged_userns = 1) that returns -EPERM from unshare(CLONE_NEWUSER) in some configurations, preventing the ESP variant from running at all. In addition, esp4.ko must be loaded or loadable.

RxRPC variant

Requires rxrpc.ko to be present (loaded automatically by socket(AF_RXRPC, ...)).Blind spot: RHEL 10.1 and most non-Ubuntu distributions do not ship rxrpc.ko in their default kernel build. However, Ubuntu ships and loads rxrpc.ko by default.
The blind spots are complementary: the environment that blocks the ESP variant (Ubuntu with AppArmor namespace restriction) is exactly the environment where the RxRPC variant works. The environments that lack rxrpc.ko (RHEL, CentOS, most non-Ubuntu distributions) are exactly the environments where user namespace creation is allowed and the ESP variant works.

The solution: chain them

Run the ESP variant first. If it succeeds, you are done. If it fails for any reason — unshare returns -EPERM, esp4.ko is not loaded, or SA registration fails — fall back to the RxRPC variant. Because the two blind spots do not overlap on any major distribution, one of the two variants will always succeed.

The chain logic

1. Try the ESP variant in a child process:
     unshare(USER|NET) → register XFRM SA → splice → modify /usr/bin/su

2. Check whether the first byte of the shellcode has been planted at the entry offset of /usr/bin/su.
   On modification success → parent process performs forkpty + execve("/usr/bin/su") → root shell.

3. On modification failure (e.g. unshare(USER) returns -EPERM, or esp4.ko is not loaded, or SA registration fails):
     Fall back to the RxRPC variant:
     /etc/passwd line 1 K search → three splice triggers → passwd field empty
     forkpty + execve("/usr/bin/su") → PAM nullok → root shell.
1

Fork child, attempt ESP exploit

The parent forks a child. The child calls unshare(CLONE_NEWUSER | CLONE_NEWNET), writes identity uid/gid maps, brings lo up, and registers 48 XFRM SAs — one per 4-byte chunk of the root-shell ELF. It then runs 48 vmsplice + splice triggers to overwrite the first 192 bytes of /usr/bin/su in the page cache and exits with status 0 on success or 2 on failure.
2

Parent checks the result

The parent waitpids for the child. If the child exited 0, the parent opens /usr/bin/su and verifies that bytes at file offset 0x78–0x79 are 0x31 0xff (the xor edi, edi at the shellcode entry). A successful verify means the page cache is patched.
3

Execute /usr/bin/su for a root shell (ESP path)

The parent calls forkpty + execve("/usr/bin/su", ...). The kernel maps the patched page cache page. The setuid-root bit elevates the process to euid=0. The shellcode at 0x400078 calls setgid(0), setuid(0), setgroups(0, NULL), and execve("/bin/sh", NULL, envp), dropping into a root shell.
4

Fall back to the RxRPC variant (if ESP failed)

If the child exited non-zero or the verify failed, the parent moves on to the RxRPC variant. It opens /etc/passwd read-only, reads the ciphertexts at offsets 4, 6, and 8, and brute-forces K_A, K_B, K_C in user space using a port of the kernel’s crypto/fcrypt.c. Then it runs three add_key + socket + handshake + splice + recvmsg sequences to write ::0:0:GGGGGG: over characters 4–15 of line 1.
5

Execute /usr/bin/su for a root shell (RxRPC path)

With the root entry’s password field now empty, forkpty + execve("/usr/bin/su", ...) triggers PAM authentication. pam_unix.so with the nullok option accepts the empty password and returns PAM_SUCCESS. su calls setresuid(0,0,0) and execs /bin/bash, producing a root shell.

Coverage table

EnvironmentESP variant worksRxRPC variant worksCombined result
Ubuntu (AppArmor userns blocked, rxrpc.ko loaded)No — unshare returns -EPERMYes — rxrpc.ko is presentRoot via RxRPC
Ubuntu (AppArmor userns allowed, rxrpc.ko loaded)YesYesRoot via ESP (first attempt succeeds)
Debian / generic systemd distroYes — userns allowedLikely yes if rxrpc.ko is builtRoot via ESP
RHEL 10.1 / CentOS (no rxrpc.ko)Yes — userns allowedNo — rxrpc.ko absentRoot via ESP
Arch / Fedora (default config)Yes — userns allowedDepends on kernel configRoot via ESP
Environment with both vectors blockedNoNoNot covered
The only configuration not covered by the chain is one where both unshare(CLONE_NEWUSER) is blocked and rxrpc.ko is absent. This is not the default state of any major distribution as of the disclosure date, but hardened environments (e.g., containers with no_new_privs, custom seccomp profiles) may achieve it.

Why a single binary handles all distributions

The binary embeds both exploit variants and the brute-force engine for fcrypt key search. At runtime it probes its environment by attempting the namespace creation and checking the return value, then selects the appropriate variant. Neither variant is attempted if it cannot succeed: the ESP path exits cleanly if unshare fails, and the RxRPC path is only reached after the ESP path reports failure. No distribution-specific compile flags or separate binaries are needed.
Setting the environment variable DIRTYFRAG_VERBOSE=1 (or passing -v) enables per-step logging from both variants, which is useful for understanding which path the exploit took and at which step it succeeded or failed.

xfrm-ESP Page-Cache Write

Root cause, 4-byte STORE primitive, 48-SA exploit flow, and the SKBFL_SHARED_FRAG patch for CVE-2026-43284.

RxRPC Page-Cache Write

Root cause, fcrypt brute force, three-splice chain for /etc/passwd, and the skb->data_len gate patch for CVE-2026-43500.

Build docs developers (and LLMs) love