CVE-2026-31431 (Copy Fail) Forensics
For those that have missed it, new CVE just dropped. Simple and reliable privesc for every Linux system since 2017. Links and background first. Skip down a section for the forensics. I'll try to update this with other distros and new evidence as things unfold:
- The CVE site: https://copy.fail/
- The Reddit topic: https://www.reddit.com/r/sysadmin/comments/1szajkx/copy_fail_cve202631431_is_a_trivially_exploitable/
- Minimized code: https://github.com/theori-io/copy-fail-CVE-2026-31431
- Un-minimized code: https://gist.github.com/grenkoca/b82281a4706e936072979acf54b608df
Here's the CyberChef for the zlib content, which has a hash of 7ef953069578beef7daf2d984d16351b0c60c6adcbf8062ffbfaac6ce944c1da
The sample is a minimal ELF binary designed for privilege escalation and shell execution. It directly invokes syscalls to set the process UID to 0 (root) via sys_setuid and then executes '/bin/sh' via sys_execve. This behavior is characteristic of a local privilege escalation (LPE) exploit payload or a backdoor designed to provide root access.
And the hexdump, because hexdumps look cool
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 78 00 40 00 00 00 00 00 |..>.....x.@.....|
00000020 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 01 00 00 00 00 00 00 00 |[email protected].........|
00000040 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 40 00 00 00 00 00 00 00 40 00 00 00 00 00 |..@.......@.....|
00000060 9e 00 00 00 00 00 00 00 9e 00 00 00 00 00 00 00 |................|
00000070 00 10 00 00 00 00 00 00 31 c0 31 ff b0 69 0f 05 |........1À1ÿ°i..|
00000080 48 8d 3d 0f 00 00 00 31 f6 6a 3b 58 99 0f 05 31 |H.=....1öj;X...1|
00000090 ff 6a 3c 58 0f 05 2f 62 69 6e 2f 73 68 00 00 00 |ÿj<X../bin/sh...|Artifacts
So what do we see when we run this? I'll be referencing some timestamps, check the next section for the order of events.
/var/log/auth.log
Starting with auth.log. Our exploit was run at 00:36:39. We see the exit of the previous root session at 00:35:08, and the start of the next legitimate one at 00:37:22. There isn't a root session between for our exploit though, since we're bypassing the typical auth methods. If you see root activity during a period where there was no root session, that is in itself an artifact.
2026-04-30T00:35:08.650748-04:00 ubuntu sudo: pam_unix(sudo:session): session closed for user root
2026-04-30T00:37:22.559989-04:00 ubuntu sudo: mike : TTY=pts/0 ; PWD=/home/user ; USER=root ; COMMAND=/usr/bin/su -journalctl
I ran this several times, and each time got the PF_ALG registration and the su launched with empty string. I don't know how common these things are in a live environment though.
Apr 30 00:36:39 ubuntu kernel: NET: Registered PF_ALG protocol family
Apr 30 00:36:39 ubuntu kernel: process 'su' launched '/bin/sh' with NULL argv: empty string added/var/log/kern.log
Roughly the same message we got from journalctl, PF_ALG registration and su launched with empty string.
2026-04-30T00:36:39.557587-04:00 ubuntu kernel: NET: Registered PF_ALG protocol family
2026-04-30T00:36:39.565569-04:00 ubuntu kernel: process 'su' launched '/bin/sh' with NULL argv: empty string addedModified /usr/bin/su file
Easy win, the exploit changes the binary, if it doesn't match what's supposed to be in the repo, something is wrong. In the case of Ubuntu 24.04, for me anyway, the "evil" MD5 hash is consistently 0b8ebf43eed68c716fc345cf55d87284.
user@ubuntu:/var/log/unattended-upgrades$ cat /var/lib/dpkg/info/util-linux.md5sums | grep usr/bin/su
e1e5e66539ac01f221e92d2f287c2983 usr/bin/su
user@ubuntu:/var/log/unattended-upgrades$ md5sum /usr/bin/su
0b8ebf43eed68c716fc345cf55d87284 /usr/bin/su
user@ubuntu:/var/log/unattended-upgrades$ You can also use debsums, on Ubuntu anyway.
user@ubuntu:/var/log/unattended-upgrades$ sudo apt install debsums
user@ubuntu:/var/log/unattended-upgrades$ sudo debsums -s
debsums: changed file /usr/bin/su (from util-linux package)Behavior
Notice in the output below that when I first executed sudo su -, I got a normal prompt with a user and hostname. After the exploit, I got a basic # prompt.
Test Environment
ike@ubuntu:~$
user@ubuntu:~$ date
Thu Apr 30 12:34:24 AM EDT 2026
user@ubuntu:~$ vim copyfail.py
user@ubuntu:~$
user@ubuntu:~$
user@ubuntu:~$ date
Thu Apr 30 12:34:42 AM EDT 2026
user@ubuntu:~$
user@ubuntu:~$ chmod +x copyfail.py
user@ubuntu:~$
user@ubuntu:~$ date
Thu Apr 30 12:34:54 AM EDT 2026
user@ubuntu:~$
user@ubuntu:~$ sudo su -
[sudo] password for user:
root@ubuntu:~#
root@ubuntu:~# date
Thu Apr 30 12:35:06 AM EDT 2026
root@ubuntu:~#
root@ubuntu:~# exit
logout
user@ubuntu:~$
user@ubuntu:~$
user@ubuntu:~$ date & ./copyfail.py
[1] 3071
Thu Apr 30 12:36:39 AM EDT 2026
#
# date
Thu Apr 30 00:36:43 EDT 2026
#
# exit
[1]+ Done date
user@ubuntu:~$
user@ubuntu:~$
user@ubuntu:~$ date
Thu Apr 30 12:37:17 AM EDT 2026
user@ubuntu:~$
user@ubuntu:~$ sudo su -
#
#
# date
Thu Apr 30 00:37:24 EDT 2026
# exit
user@ubuntu:~$
user@ubuntu:~$