Tuesday, September 23, 2014

Exploit Tunneling and Callback

A few years ago, when I worked for my previous employer, I put together a proof-of-concept that was to be part of a client demo. I thought it was kind of cool, so I recorded a screencast of it in action. I've had the video sitting on my laptop ever since, not really sure what to do with it. I finally decided to post it.

In the video, what you see is a custom exploit script that exploits a buffer overflow in the web interfaces of several D-Link webcams. The neat part is that it tunnels the exploit and callback through each successive webcam. It works basically like this:

  1. Exploit webcam 1.
  2. Webcam 1 phones home, then downloads and executes a two-stage payload.
  3. The payload proxies all packets destined to a certain port between the exploit host and the next webcam in the chain. It does this in both directions.
  4. Tunneling through webcam 1, exploit webcam 2.
  5. Like before, webcam 2 phones home, tunneled through webcam 1, and downloads and executes a two-stage payload.
  6. Again, the payload proxies packets, this time between webcam 1 and the thrid webcam.
  7. Exploit webcam 3, tunneling through webcams 1 and 2.
  8. Webcam 3 executes a traditional payload, resulting in a connect-back shell. The shell connects back through webcams 2 and 1 to the exploit host.
  9. Root prompt on webcam 3.
I put this together pre-Bowcaster, so it's a little raw. But it was all groundwork for that framework, so Bowcaster has much of the same capability shown in the video.

As an aside, one of the nice things about exploiting these inexpensive consumer devices, besides the fact they are soft targets, usually unmonitored, and ubiquitous, is they generally don't have a writeable file system. This means you can reboot them, leaving behind no trace that you were ever there.

Anyway, here's the video. It has cool music.

Friday, May 16, 2014

Infiltrate 2014

Here are some additional resources I may have mentioned in my Infiltrate 2014 presentation.

White Paper: SQL Injection to MIPS Overflows - Part Deux
Slides: SQL Injection to MIPS Overflows - Part Deux

Original white paper from Black Hat USA 2012:
SQL Injections to MIPS Overflows: Rooting SOHO Routers

Proof of Concept Exploit code:
Here's my Github repository for proof-of-concept exploit code.  In it, you'll find the exploit code for the Netgear WNDR 3700v3 that I demoed at Infiltrate, among a few others. The white paper is in there as well.

I talked about my Python API/Framework for developing buffer overflows. In particular it includes payloads for MIPS Linux.

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.


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:
In order to unpack the firmware, I recommend my colleague, Craig Heffner's tool, 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:
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:
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":
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.


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.

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


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,, and neglected to test on the latest, 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,

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_*

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.


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


    #Uh oh. Couldn't start the server. 
    #Do all the payload files exist?

except Exception as e:
    #something went wrong

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