Last updated at Tue, 25 Jul 2017 15:50:27 GMT
I joined the Rapid7 team as a Security Researcher back in March. Since I've started, I've been doing a lot of work primarily in the area of remote vulnerability detection for Nexpose, and the work has already varied quite a bit in scope and the challenges I've faced day-to-day. Today, I'm here to talk a little bit about my work last month relating to the detection of CVE-2012-1182, a recent high-profile samba vulnerability
For the unaware, CVE-2012-1182 is a recent, high profile bug in Samba that could possibly allow attackers to perform remote code execution via a crafted RPC packet, possibly via an unauthenticated connection. It affects all the major release series including 3.4.x, 3.5.x and 3.6.x. Samba of course runs as root by default, which magnifies the issue substantially and can make it a truly serious remote vulnerability. Patches were rolled out quickly for most major linux distributions, so if you upgrade, you're very likely OK.
All that said, perhaps the most interesting aspect of this bug in my opinion is the fact this particular flaw was not directly man-made like typical coding errors you see in a C application. Instead, the vulnerabilities in question hid deeply within the confines of auto-generated source code, perhaps hiding the bug for longer than what might have been typical. The source was generated with a tool called PIDL (which is also used by Wireshark.) The amount of generated code is very large - the patch provided by Samba for v3.5.13 to fix this vulnerability is 30,000 lines and weighs in at a hefty 1.8 megabytes. There isn't just one vulnerability here - there are literally hundreds of overflows in the generated code before this fix, and how many of them are robustly exploitable is anybody's guess. I have seen at least 6 POCs for different flaws, however.
A first cut at detection
The basic idea behind the flaw is that we can we can send a packet that specifies both the size of a memory buffer to allocate and the buffer contents - the copy of the contents to the allocated memory buffer however is not checked, so if we send a large amount of input and give it a small buffer size to allocate, we get a pretty classic overflow (the actual data structures are a little more involved than that, but that's the 20,000 foot view.)
From the Samba side, it's actually pretty safe to test for something like this. Samba's architecture is reminiscent of old inetd style services, where a master process accepts incoming connections and forks children processes that handle every client. This doesn't exactly scale magnificently (1 process per client,) but it's a valid design trade off in my opinion, given the date of Samba's design and expected use cases (not absurdly high amounts of concurrent users per share.) But what it does mean is that any sort of interference with the service happens in the context of a child process - no other clients or infrastructure is affected by poking around.
In Nexpose, we have support for communicating over a ton of different protocols, and CIFS (the protocol Samba/SMB uses) is no exception. So I set out to write a check based on some proof of concept code floating around, and so I cut up a check based on a reliable POC. And the jury's verdict is....
Success! I'm done, can go home, and wallow in the success of my accomplishments. Or can I? While I was happy, after all the excitement of this happening I quickly set off to test this against a range of distributions to ensure validity, and the results weren't what I expected: everything was vulnerable, even patched machines.
So why did everything return vulnerable? This was particularly worry-some since I had POC code that *did* correctly detect patched/unpatched machines, but I got it wrong with Nexpose. Could there be another related Samba vulnerability? That's what I thought initially, and it still may be the case (although I haven't done much investigation on this, I still think it's a possibility.)
After looking at a bunch of dumps from Wireshark, I inevitably figured out it was a bug in my code using the CIFS APIs: and that bug caused samba to crash on a NULL pointer dereference! This is completely independent of the patch and actually remarkably easy to do (you can send a CIFS RPC request, fill in a few components of the request headers, and then fill in the body with a bunch of garbage, zeros, whatever.) I felt good about figuring this out and wanted to investigate further, but I still wasn't done with this yet. After a day or two of digging around protocol and API docs, I inevitably figured out what was wrong and fixed it.
So all's well that ends well, right? Nope - I still wasn't done. It turns out that our CIFS code had a *huge* limitation that still made my check fail.
CIFS as a protocol has a concept of fragments. This is completely separate from TCP fragmentation/PDUs, and exists at the application level as part of the CIFS protocol. If you send a big bunch of data and it's not fragmented and exceeds samba's fragment limit, Samba does not like that very much, and forcibly kills the connection. What was the problem this time? Our protocol code did not support CIFS fragmentation at all! And I was sending 'fragments' that were easily 3x the frag limit.
Less is more
(OK, you've followed me this far, so go a little further!) For those of you who aren't aware, CIFS is a somewhat terribly complicated protocol that's aged (not like wine, but you get the idea.) Supporting CIFS fragments in our code would have been a massive, delicate undertaking for this one vulnerability, so I had to find a way to cut down the packet size to below the size of a single fragment: 4kb.
After playing around even *more* for another day or two, and rummaging across 6 POCs all of various kinds, I finally found one that was close to my requirements: it was at 4300 bytes in size, reliably triggered crashes, and was easy to understand. I ported this directly and eventually started playing around with the numbers, basically futzing about with a script until I found the magic numbers that satisfied the 4kb constraint (I wrote this using a little bit of Java/Python to quickly script it.) And it worked!
So what does all this add up to? It adds up to some very nice detection for this flaw in Nexpose:
Juan Vasquez - one of our awesome new exploit developers - has been working on and off on a stable exploit for this particular vulnerability to put into Metasploit; perhaps someone soon I can help him, and then we'll have something else to write about. Or maybe we'll investigate the mysterious Samba crash I invoked further. Until then, stay safe!