Thursday, October 15, 2009

Mainlining new lines: feel the burn

Since the blog has been pretty stale for the last couple of months, I've decided to try and spice things up with a couple of war stories from recent web app pen tests. No XSS bugs here. I'm talking about complete, CPU melting, rack busting pwnage and destruction, shock and awe, all delivered over HTTP. OK, maybe I'm being a little dramatic, but at least they won't be XSS bugs. Besides, if you own the box, who needs XSS?

Command Execution in Ruby on Rails app

This RoR application was accepting a user supplied URL which got passed to an external application via IO.popen(). If I could inject a back-tick or escape from the quoted string being passed to popen(), I could execute arbitrary commands. My problem was that these basic injection attacks were failing because the devs did a decent job of validating input. Part of the validation approach relied on passing the user supplied data to Ruby's URI.parse() function. The parse() function would raise an exception any time I injected a "malicious" character, and the script would stop executing before calling popen().

I knew I had to find some sort of filter bypass bug in URI.parse() if I wanted any pwnage, so I fired up irb and after a few manual fuzzing attempts I had it:

nullbyte:~ mikezusman$ ruby -v
ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-darwin9.8.0]
nullbyte:~ mikezusman$ irb
>> require 'uri'
=> true
>> require 'cgi'
=> true
>> u1 = "http://www.google.com"
=> "http://www.google.com"
>> u2 = "http://www.google.com`ls`"
=> "http://www.google.com`ls`"
>> u3 = "http://www.google.com%0A`ls%0A`"
=> "http://www.google.com%0A`ls%0A`"
>> URI.parse(u1)
=> #

>> URI.parse(u2)
URI::InvalidURIError: bad URI(is not URI?): http://www.google.com`ls`
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/uri/common.rb:436:in `split'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/uri/common.rb:485:in `parse'
from (irb):7
from :0
>> URI.parse(u3)
URI::InvalidURIError: bad URI(is not URI?): http://www.google.com%0A`ls%0A`
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/uri/common.rb:436:in `split'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/uri/common.rb:485:in `parse'
from (irb):8
from :0
>> URI.parse(CGI::unescape(u3))
=> #

>> x = URI.parse(CGI::unescape(u3))
=> #


Injecting a URL encoded version (%0A) of a new line (\n) would get my URL encoded back-tick (%60) through the URI.parse() function unscathed. After the successful call to parse(), the data was passed to popen() and my commands would be executed. My attack looked like: http://victim.com/controller?param=http://www.google.com%0A%60ls%0A%60

Lessons Learned

Relying on the result of a call to a third party routine doesn't necessarily equate to "input validation." However, used differently, URI.parse() could have very easily helped to prevent this bug. URI.parse() returns a new object whose members could be used to construct a safe string to be passed to popen().
This would work because everything after the %0A gets dropped:

>> d = "http://www.google.com/%0A%60ls%0A%60"
=> "http://www.google.com/%0A%60ls%0A%60"
>> r = URI.parse(CGI::unescape(d))
=> #

>> r.path
=> "/"
>> new_arg = "#{r.scheme}://#{r.host}#{r.path}"
=> "http://www.google.com/"


If you relied on the above as "input validation", you just would have gotten lucky that the function chopped off everything after the new line. Some times luck is enough. But when dealing with user data being passed to a system command, a little extra scrutiny can go a long way towards protecting your application. URI.parse() makes it easier for us to enforce additional validation checks by letting us look at each piece of the URI (protocol/scheme, host, path).

When fetching user supplied URI's, this sort of fine grained input validation is something we should be doing anyway. For example, simply parsing the URI would not block an attack against the local host, since http://127.0.0.1/ is valid. We might also want to make sure that the protocol is http|https (not ftp, for example) and that our application isn't being used to scan the network on the inside of the firewall (by blacklisting internal IPs and host names).

Moral of the Story

Just like many other bugs, this one could have been prevented with better input validation. Even if you think you're doing a good job validating your input, remember that not all input validation routines are created equal. Stay tuned for my next post, where we'll explore the short comings of relying on static analysis tools to catch similar bugs.

Update 10/22/2009
@emerose filed this bug report.

Tuesday, August 4, 2009

BlackHat 2009 and Defcon 17: EV SSL MITM Demo

For the second year in a row I had BlackHat live demo issues. Shame on me.

Fortunately, the demo worked at Defcon. Had it not worked, however, I was prepared with a video thanks to Camtasia.

You can view the video here.

The demonstration shows a MITM using a regular SSL certificate (Domain Validated) to intercept data sent to a site protected with an Extended Validation (EV) SSL certificate. Since the browser treats the high-assurance EV certificate the same as a low-assurance DV certificate, the user is never warned about any connection downgrade. All they might notice is the "flicker" of the green EV badge.

Tuesday, June 16, 2009

Insecure Cookies and You: Perfect Together

Who uses the secure cookie flag? Web developers who don't want their user's cookies being leaked out over non-SSL protected sockets. These developers realize that protecting user credentials on the wire is only half the battle. If an attacker can sniff a user's cookie off the wire when it's sent in plain text, who cares if the credentials are protected? The attacker still gets access to the application.

Who doesn't use the secure flag? Yahoo! Mail. Microsoft Live Mail. GMail and Google apps. All of these sites, and many others, protect the transmission of credentials using HTTPS. Unfortunately, immediately after you authenticate to one of these sites and get a valid session cookie, the browser is redirected to a plain text HTTP interface of the site. Google at least gives users the option of protecting their entire session with SSL. Others do not. If these companies start setting the secure flag on their cookies, their sites will break.

The "Secure" cookie flag is just a patch for a poorly implemented browser Same Origin Policy. Essentially, it allows a web application to opt-in to a strict interpretation of SOP on the client side that will prevent cookies from being leaked over insecure protocols. Why do we have to do extra work to be secure?

I propose a new cookie flag, called the "insecure" flag. Use of the insecure flag would allow web sites that don't care about protecting session cookies to opt-out of a strict interpretation of SOP, thus exposing their session cookies to the world and allowing their applications to work. If you want to protect your users' credentials over HTTPS, but then expose their sessions over HTTP, this will be the flag for you!

Imagine that. Secure by default. No extra work to do things right. What a concept!

Ah, wishful thinking :-)

Wednesday, June 3, 2009

NYS CSCIC Conference

Last week I presented at the NYS cyber security conference in Albany. My talk was about attacks that leverage publicly available information, such as data indexed in search engines and/or stored in social networks. I also showed how this data can be used in highly targeted spear phishing attacks. My spear phishing demo used my netextender ssl vpn exploit, since it is usually trivial to find a companies SSL VPN gateway. Once you find the ssl vpn gateway, some passive recon of the system can reveal a tremendous attack surface on the victim (client) machine.

At the end, I touched on some problems with commercial PKI, but I didn't really get into it. I'm saving that for some up coming blog posts. I got some great feedback at the end, and also met a bunch of cool folks. Thanks for listening. Slides are available here.

I couldn't stick around for both days of talks, but I managed to see the two key notes on day one. The second one was by Phil Reitinger, Deputy Under Secretary, National Protection and Programs Directorate (NPPD) U.S. Department of Homeland Security.

/me lets his fingers recover from typing that title

During his talk, Mr. Reitinger offered up five priorities for the US as we move forward with our new cyber security initiatives. I'm paraphrasing here, and I didn't take great notes. That's because I'm just some dude with a blog, and not a journalist.

1. We need to build our capacity. DHS needs people. We also need to work with academia to build programs that churn out people with the right skills and knowledge.

2. Establish relationships between public and private sector. Mr. Reitinger joked about the infinite loop of meetings where public & private sector folks agree that they are both willing to share data - starting at the next meeting.

3. Develop (and follow) a standard incident response & recovery plan.

4. Streamline Identity Management. In addition to managing user identities, he also mentioned something to the effect of "being able to better identify who we're connecting to." Maybe this means we'll eventually get something better than SSL site validation.

5. Metrics. Specifically, he mentioned software quality metrics. One thing that keeps popping into my head is the fact that the airforce got a locked-down version of XP. How did the air force quantify the improved security? And when will everyone else benefit?

Tuesday, March 24, 2009

Subprime PKI and SSL Rebinding

I'm on my way out of Vancouver today after an awesome time at CanSecWest 2009. Met alot of awesome people, and learned some cool new tech.

The talk Alex and I gave, "Subprime PKI: EV SSL certs and MD5 Collisions", was also well received. We'll be releasing our paper and source code soon, but until then, here is a screen shot of a MITM attack against an EV SSL protected web site from our live demo (note the presence of the "green glow" in the browser).

Thanks to Garett Gee for the photo. You can check out the rest of his photos here.

Thursday, February 26, 2009

Law.Com SSL VPN Article and Microsoft IAG Hands On Lab

Today I'm out to teach a Microsoft IAG Hands-On-Lab outside of Boston, Mass. It is a basic intro class to IAG, which is Microsoft's SSL VPN technology.

Also, last month Bryan Dykstra wrote a follow up article about my SSL VPN research on Law.com. It's a good read, and provides a nice overview of some of the threats effecting these devices.

Monday, February 23, 2009

Reversing Crypto: SonicWall SSL VPN Flaw

Haroon Meer's SSL VPN ActiveX repurposing attack is number 9 on Jeremiah Grossmans list of the top 10 web hacks of 2008 :-) Congrats to Haroon! I figured this would be a good time to document the details of the Sonicwall flaw I discovered and disclosed last year at blackhat. Some details are in the slides, but I've been meaning to put a detailed description here for some time. So here goes...

In the beginning, there was a flaw...

First, the initial flaw was VERY simple, and easy to exploit. Any web site could instantiate the ActiveX control (NELaunchCtrl), and the very first thing the control would do is send an HTTP request to the invoking server to determine if the control should upgrade itself. If the server sent back an unrecognized response, the control would download an unsigned .EXE file from the server, and execute it on the client. Very basic, and easy to exploit. To find the flaw, you simply had to intercept the ActiveX initiated HTTP requests with an SSL capable proxy, then replay and fuzz them.

This flaw was reported to SonicWALL (with recommendation of using code signing certificates to prevent malicious code execution), and they eventually released a patch for me to test. This is when it got interesting.

Then, there was a patch...

Upon initial testing of the fixed control, the very basic repurposing attack was indeed thwarted. Further interception of the traffic generated by the control showed a series of challenge/response requests between the client and the server.

Example challenge:
https://sslvpn.server.com/cgi-bin/sslvpnclient?validateserver=128248573387261264

Example response (from HTTP response body):
SERVER_CHAIN="NjQ3MjZGNkM2OTZENkY2NzZGNjQ3MjY5NjM3MjYxNzM=";

VALIDATE_DATA="NEQ2NUQ1MzcwNDNBODhDRUFBMDgwMzMxNjAzRDhGQ0U4MDczRjQxOTNGQTdDODgzRUQ5RDdBQTAzQjg3QURFQg==";

Base64 decoding of the VALIDATE_DATA yielded binary data that had to be some sort of cipher text. SERVER_CHAIN, on the other hand, would reveal a stream of hex numbers, that would eventually decode to a 16byte string such as: drolimogodricras

These 16bytes were unique for each validation request, as was the cipher text. Also interesting was the fact that the SERVER_CHAIN and VALIDATE_DATA were unique even when I replayed requests with the same value passed in validateserver.

At this point I knew I was dealing with a stream or block cipher, that SERVER_CHAIN what seemed to be an Initialization Vector, and VALIDATE_DATA held what seemed to be the cipher text. Now I just needed to find out what algorithm was being used and what the encryption key was.

No IDA Skills Required

Next, I started looking at the control itself. I knew there was a new method exposed named ValidateServer(). This method had to be called for the control to continue running, and this is also what triggered the challenge response. Before I jumped into IDA, I ran strings.exe on the binary. Below is what I saw.



In the above image is a red circle, and a red square. The red circle shows the following text: s)3!cW^L1%S&V@N~
It doesn't take much to realize that these 16bytes look an awful lot like a passphrase.

In the red box, we see some encryption related error messages that indicate the encryption method: AES128. For AES128, our 16byte string above would be an acceptable passphrase. Remember that 16byte string we assumed was an IV? Well, 16 bytes is the correct size for anAES128 IV.

Now we've identified all the key parts of the new server validation mechanism SonicWall implemented to attempt to defeat the repurposing of their ActiveX client by rogue sites.

1. The input is a unix time stamp generated by the client, and sent to the server for encrypting.
2. The server generates a pseudo-random IV and encrypts the timestamp with a symmetric encryption key that client already knows. The IV and cipher text are sent back to the client.
3. The client receives the IV and the ciphertext, and attempts to decrypt the cipher using the hardcoded, pre-shared encryption key.
4. If the decrypted plaintext matches what was originally sent by the client, validation succeeds and the control can be used (or attacked.)

The Source Code

To repeat the repurposing attack, I wrote the following C# and ran it on my rogue server. Sorry for the screenshot, but I can't find the actual source file at the moment.



At least they didn't use ECB ;-)

Conclusion

For a second time, I reported everything above to SonicWall. They patched again, and said they fixed it. However, the fix did not include the recommended mitigation of using code signing certificates to validate the .EXE that gets downloaded by the ActiveX. That said, the control still relies on some sort of obfuscated client/server validation routine. That's bad news, since it can probably be broken again by someone with enough time on their hands. But then again, I wonder if they would have gotten a code signing certificate signed with an MD5 hash ;-) Security through obscurity FT(L|W)?