Thursday, November 29, 2012

UPDATED: Responsible (non)Disclosure

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Tuesday, October 23, 2012

Specifying Preferred Load Addresses for ELF Shared Libraries

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

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

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

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

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

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



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

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

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


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

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

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

0x2abee000 - 0x2aabe000 = 0x13000

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

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




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

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


Tuesday, June 12, 2012

Parsing Email and Fixing Timestamps in Python

I decided to POP out all my Yahoo mail into my Google Apps account so I could stop paying for Yahoo's "premium" service (WTF, it's 2012, and POP is a paid feature--and there's no IMAP?).  I have fetchmail then download all of my messages which get post-processed by procmail and re-served by dovecot.  Since a bunch of really old messages were just downloaded by fetchmail, they appeared to be "new" from dovecot's perspective.  This is because the name of the message files stored in the Maildir format used by dovecot starts with a number representing when the messages were downloaded.  So years-old messages that were just downloaded will have a very recent timestamp encoded in their filenames.

The file names look like this:

1339506150.22834_0.hoth:2,Sb
1339506889.22952_0.hoth:2,Sb
1339507621.23058_0.hoth:2,Sb
1339509572.27344_0.hoth:2,Sb
1339510487.386_0.hoth:2,Sb

To fix this, I wrote a little python program to parse out the dates the messages were originally received, and rename the message files.  It also updates the file system's atime and mtime timestamps.  Since several new "Received" headers were attached to the message when Google POPed the messages from Yahoo, and then when fetchmail downloaded them from Google, I needed to figure out which ones to disregard.  I decided to compare the date the message was originally sent to each of the Received: dates, and use the most recent Received: header that was no more than 24 hours after the message was sent.

I made a backup of ~/Maildir/cur/ first.
You can loop over the message files like this:

$ for file in $(ls -1); do ~/bin/timestamp.py $file; done

I'm not really sure what the implications are for dovecot while mucking around in ~/Maildir, so I stopped that, and also fetchmail while doing it.

Here's the script.  Use at your own risk: