Skeptikal.org

Monday, November 16, 2009

XSS Kiosk Busting

You know those kiosks that you find in bookstores for looking up inventory? The idea of XSS-ing one occured to me a few years ago, but I never really got a chance to play with any and forgot about it until recently. I was at Sur La Table last weekend, trying to figure out which kitchen supplies I haven't bought yet (turns out, it was more knives), and noticed the wedding/gift registry...



Mostly, I just think this is funny, but there are potential malicious applications for this kind of thing. For example, Wal-mart's job applications are done through a web application running on a kiosk in the customer service area. If you can inject javascript into that application, you could rewrite the whole thing to log personal information from applicants.

Presuming that those computers are connected to the internet (and I expect they are), it would only require that you inject a single <script> tag, and you could do all the rest with BeEF. Since it's a kiosk, nobody is able to look at the address bar or status bar and see that anything is wrong.

Labels: ,

Saturday, November 14, 2009

Adobe Responds... Sort Of

Adobe has published a response to the latest issues I've been talking about. Somehow, they have managed to neatly dodge the issues in question and fixate on the Same Origin Policy. Is that policy news to anybody? Of course not. That's not the point. That's not even the issue, though I do believe the policy is flawed, which I'll explain in a few paragraphs.

Adobe continues to compare this to uploading Javascript files. Here's the difference:

If I upload a .js file to a webserver, I cannot execute it in the context of that server. Javascript alone will not execute.

If I upload a .html file to a webserver, I can execute Javascript within it in the context of that server, because my browser recognizes the text/html content-type header that the webserver sends.

If I upload a .html file to a webserver, but an application/zip header is sent by the server, it will not render at all.

If I upload an HTML file with a non-html extension to a webserver, and the server does not send a text/html content-type when serving the file, I cannot render HTML or execute Javascript.

If I upload a ZIP file with HTML prepended to it, I cannot render HTML or execute Javascript.

If I upload a .swf file to a webserver, I can execute it in the context of that server.

If I upload a SWF file with a non-SWF extension to a web server, I can execute it in the context of the server.

If I upload a ZIP file with a SWF file prepended to it, and the server sends an "application/zip" content-type, I can execute it in the context of the server.

Flash's handling of potential code is clearly MUCH more permissive than Javascript's.

This makes it far easier to upload an object to a webserver- a Flash file can look like anything to the server and still be executable, as long as it starts with the right sequence of bytes. In many cases, simply changing the file's extension is enough to bypass upload restrictions. In other cases, you have to get crazy with it, but as noted in the original post, the entire ZIP family of files can have a SWF embedded in them while still being valid. Checking whether the file is a valid ZIP file will do you no good. The only way to be sure that the file does not contain a SWF is to specifically look for a SWF header. Any security professional will tell you that a technology that requires a blacklist approach to input validation is poorly designed.

There are some solutions for the security administrator. They aren't easy to implement. The best thing to do is place all your user-generated content on a separate server. For large web applications, this is probably already happening. But do you think that every prebuilt forum, ecommerce, blog, and gallery application out there is going to get redesigned to fix Flash's problem? Do you think the hobbyists and mom-and-pop shops are going to set up a separate server for holding this content? As most of them don't even have one dedicated server, this is not just unrealistic to expect, it's virtually impossible. Again, I'll pull out the example of bugs.adobe.com, a prebuilt issue tracking application that stores files on... bugs.adobe.com. I reported this issue several days ago, and not only have they not moved all user-generated content off the server, they haven't even disabled the file upload feature.

The other solution for administrators is to serve user-generated files with the content-disposition: attachment header. This is relatively easy to do, and it's the only reasonable thing they've suggested. It is still hardly an ideal solution though. First off, some user-uploaded content shouldn't be served with this header. Images that people expect to be able to inline in other web pages are one example. Validating images is obviously easier (and more common) than validating zip files, but the point stands.

Now, let me be clear: The Same Origin Policy is a completely separate issue from the execution of the content, but since Adobe won't stop talking about Flash's Same Origin Policy, allow me to demonstrate exactly why it is designed wrong.

If a Javascript file hosted on foo.com is included in a web page on bar.com, that file can only affect the bar.com domain. Same origin policy. Woot.

If an HTML file hosted on foo.com is iframed into a web page on bar.com, that file can only affect the foo.com domain. Same origin policy. Woot.

If a Flash file hosted on foo.com is embedded in a web page on bar.com, that file can run Actionscript on foo.com, as well as execute Javascript on bar.com.

All the attention to this point has been on uploading malicious files, but let's take a look from another angle. What if victim.com has its own Flash objects, which use Javascript calls to interact with the web pages they're included on? This is not an unreasonable assumption- it's the very reason that a Javascript interface is built into Flash player. Here's the problem: these Flash objects can be embedded in evil.com's webpage. evil.com can run his own Javascript which modifies function prototypes (again, only in the context of evil.com), poisoning the functionality that victim.com's Flash object relies on. When that Flash object then uses data from the Javascript side of things to communicate with its origin server, you again have cross-origin interaction.

What kind of Same Origin Policy allows code to execute on multiple origins? A seriously flawed one.

From Adobe's response: "[The Same Origin Policy] states that two pieces of content hosted on the same domain and loaded by the same protocol trust each other. Conversely, two pieces of content hosted on different domains do not trust each other and cannot interact." If this was the way it worked, we would have no problem. In my examples, I used 2 pieces of content (a SWF and an HTML page with Javascript), on two domains (foo.com and bar.com), using the same protocol (HTTP), and I made them trust each other. By their own definition, Flash's policy does not work. Adobe's response is dead wrong.

Labels: ,

Friday, November 13, 2009

Flash Origin Attack FAQ

Okay, people are looking at this Flash issue. Neat. A lot of people don't fully understand it, which may be my fault. Here, I'm going to try to respond to some of the questions and comments that I've received from various parties.

This is not a single issue

While it is a single, basic issue that enables this exploit, it is the
intersection of that and several others that makes it critically bad.

Specifically, the fact that an uploaded file can attack a server is hardly news. As mentioned in my original post, Adobe has acknowledged this issue with advisories multiple times. If you were already aware of it, good on you. However, it still is new to most website administrators, and more importantly, these are the people that Adobe expects to fix it.

The part that is new, is the focus of this research, and admittedly could have been described better, is that the Flash player will execute any file it is asked to execute. The HTML <embed> tag is used to include objects that the browser may not be natively able to handle. Arguably, this may be a browser issue as well, as the content-type supplied by HTTP headers should take precedence over the type attribute specified in the HTML page, but the plugin itself should also verify that the proper content-type is sent in the server's response HTTP headers before executing the plugin. Flash's plugin does not do so.

If Flash's plugin did handle this correctly, the other issue documented here- that of overloading various filetypes, primarily ZIP, would be nearly useless. The point of that work was to demonstrate just how difficult it is for administrators to filter uploaded content by file validation, and to provide various examples of how to bypass such validation with 100% legal files, which are still potentially malicious. More on that in a moment.

This is not a cross-site scripting attack

The end result of the attack can indeed be XSS, as Actionscript may execute Javascript through the "ExternalInterface" method, but the source of this problem is not necessarily input sanitization. It is a core design flaw in Flash's same-origin policy, combined with the weak content ownership management that is already common on the majority of websites and prebuilt web applications on the internet.

Calling this attack XSS, when it involves no Javascript (arguably, not really a requirement), is not cross-site (again, not really a requirement, despite being in the name), and involves no HTML injection, is a stretch, but the similarity is certainly there, bringing me to the next point:

This attack abuses the user to attack the server

This is where it is very similar to XSS. The whole point is to hijack the user's browser and have the ability to issue requests to, and read the results from the server. In the context of a user's session, this can be a very bad thing. Neither the server itself nor the client's computer is being compromised directly; The web application, and any data or functionality within, is now accessible to the attacker.

Adobe does not intend to fix it

As they have made abundantly clear, Adobe considers this to be the web administrators' problem. Regardless of whether you agree with them or not on this, it is hard to dispute that Adobe's expectation of administrators to prevent this issue is unrealistic.

In fact, Adobe does not appear to be able to manage this issue on their own web properties. For example, photoshop.com is an interactive image library application. Uploaded images are not validated fully, and are stored on (and executable from) api.photoshop.com. This is indeed a separate domain from the rest of the application, and should be safe (though I'd point you to my paper on cross-subdomain attacks and say it is still poor practice), but www.photoshop.com's crossdomain.xml policy specifically allows access from *.photoshop.com.

Next, take a look at bugs.adobe.com. This third-party issue tracking system allows users to upload screenshots (or zip files of screenshots) of bugs. These files are hosted on bugs.adobe.com, and can be used to exploit not only bugs.adobe.com, but again through crossdomain policies, www.adobe.com, www.acrobat.com, www.photoshop.com, and other Adobe web properties.

You'll never guess where www.photographersdirectory.adobe.com keeps its uploaded images. Or where forums.adobe.com keeps users' uploaded avatars.

Clearly, expecting website administrators to understand, not to mention be able to fix this issue is ridiculous and unrealistic. I originally compared this to the GIFAR exploit, which uses very similar attack techniques against the Java plugin. Unlike Adobe, Sun took responsibility and fixed their plugin. Whether they are wrong or right, Adobe is uniquely in a position to create a client-side fix for the Flash users. Until they do so, many websites will remain vulnerable.

Labels: , , ,

Friday, September 25, 2009

Inside the LiveJournal Worm

On Wednesday morning, LiveJournal was hit by a Flash worm. It was brought to my attention by Dan Goodin over at the Register, and I discussed it briefly with him as he wrote an article about it. Because I've been looking at Flash in depth lately (more on that coming soon), I decided to take a deeper look at the attack. I was able to track down the HTML side of the malware, but couldn't find a copy of the malicious SWF. An email to the LiveJournal staff fixed that, and they were kind enough to also include their own analysis of the attack. Their earlier post generally covers it, but I'll go into a bit more detail here.

It's really a fairly simple worm. As noted by the LiveJournal staff, the payload did much less than it could have.

The real source of the vulnerability was an overly permissive crossdomain.xml file on www.livejournal.com. This is a well-known, but surprisingly common issue- Jeremiah Grossman came up with some basic statistics for this issue in May of 2008- Some 18% of websites (from a very limited, but high-value set of sites) have crossdomain policies that I would consider "permissive." Coincidentally, I have more research on that coming up soon, but for the moment, I'll just say that only a year and a half later, the numbers are considerably worse.

At any rate, LiveJournal's crossdomain policy allowed Flash objects from their lj-toys.com sandbox domain more access than it should have, and allowed this worm to perform requests across domains. From there, it is pretty simple- embed malicious objects in a post, and have those objects make requests to www.livejournal.com, propogating to the profile of any user that views them. The exact steps that the worm takes are as follows:

  1. Perform a blind request to bit.ly (more on this in a moment)
  2. Check whether a user is logged in by requesting and parsing http://www.livejournal.com/manage/profile/
  3. Extract username and email address from that page
  4. Extract last post ID from http://www.livejournal.com/editjournal.bml
  5. Request the contents of that last post
  6. Check whether the post is already infected
  7. Perform another blind request to bit.ly
  8. Infect the post, appending the SWF payload to the body
  9. Perform requests to one of three outside servers (chosen at random), submitting the following as GET variables: username, email address, and the data from the last post

The requests to bit.ly are interesting. Each time the malware is run, it sends a request to bit.ly. Just before infecting another account, it sends a request to another bit.ly link. The results of these requests are discarded, so I believe that they are only made to provide tracking data for the malware author via bit.ly's "info" page for each link. Based on the information from those pages, I estimate that the payloads were executed 9,700 times, and around 3,300 accounts were infected (accounting for a handful of "false clicks" from myself, the malware author, and others). The data on the bit.ly page doesn't provide enough granularity to generate a useful profile of the attack's timing, so I've contacted bit.ly staff to see what further information can be provided. While they are being helpful, I'm not sure I'll be able to get much useful data (I sure wouldn't give it to me).

What lessons can we learn from this? For a user, Flash can be dangerous. It should be disabled by default. Is this news? No. But this is a very clear sign that the attackers know it as well, and it is being exploited. We, on the good guys' side, should be paying attention. For the administrators of a website, there are a few lessons. First, the crossdomain.xml policy is a major failure point, and many sites are vulnerable. Know when you are allowing access. Second, embeddable content can be dangerous. While LiveJournal's system for embedding content is actually quite good, there are really too many things that can be done with active content like Flash to allow it without seriously considering the consequences.

On the plus side, a few things were really done right. Within minutes of receiving reports of strange account activity, LiveJournal staff determined that active content was the culprit and disabled it throughout the site. A crude whitelist of trusted sources (such as YouTube) were enabled soon thereafter, and within a few hours, the faulty crossdomain.xml file was found and fixed.

That fast of a reaction is really impressive, and the corrective measures were pretty much spot on. What's more, LiveJournal decided to be transparent about the whole issue, releasing informative alerts to their users and working with them to fix compromised accounts. Tupshin Harper, director of Engineering and Operations, was particularly helpful to me in analyzing the attack and providing useful data. My hat is off to them- if more people reacted to breaches this way, the web security community would be in a lot better position to deal with attacks.

A few questions are still left unanswered- primarily about the attacker and his motives. The data that was logged by the malware really wasn't particularly sensitive- an email address and a username, basically. I suppose it could be useful for future phishing and spamming attacks, but given the wealth of other presumably-useful information available in a LiveJournal profile, I'm not sure that this was the goal. The code in the SWF isn't particularly refined, so I think that "Proof of Concept" is the most likely explanation. It's also worth noting that the SWF's code is in English, and while psychological profiling isn't really my strong suit, I get the impression this was intended to be neither subtle nor malicious. The servers that received user data to were all cPanel mass-hosting servers, running vulnerable instances of phpBB, Joomla, and other commonly-attacked software. One of the servers is located in Washington, one in Hungary, and one in the Ukraine. I've requested information from those hosting companies, but don't really expect a response. It is also interesting that the "logging" scripts do not actually exist on any of those servers (nor could they, being ASP scripts and the servers running PHP), but the data is sent as GET variables. If the attacker intended to retrieve that data, he would need to compromise either the FTP account or the cPanel account in question to get it from the access logs- a reasonable assumption, but not (by me at least) a provable one.

I'll leave it as an exercise to LiveJournal, bit.ly, and the hosting companies involved to locate the "patient zero" LiveJournal account and, presumably, the attacker. I have no doubt that the data required to locate him is there, but getting it all into one place will probably prove tricky.

Labels: , , ,

Tuesday, August 11, 2009

PHP Casting Errors in Wordpress

Did you see the Wordpress vulnerability that was published last night?

While Wordpress vulns aren't really news, this one was fascinating. All it does is allow an attacker to reset the adminsitrator's password- locking him out of the account. Annoying, but not fatal. I'm interested in the vuln itself, as it stems from PHP's flexible casting. In particular, the following lines of code (paraphrased for context and clarity):

$key = preg_replace('/[^a-z0-9]/i', '', $_GET['key']);

if ( empty( $key ) ){
return new WP_Error('invalid_key', __('Invalid key'));
}

$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s", $key));

This code can be exploited by passing the vulnerable script an empty array rather than a string for $_GET['key']. You can pass an array in a query string using the [] syntax:

wp-login.php?action=rp&key[]=

Go back and step through the vulnerable code again. The value of $_GET['key'] would look like this in PHP form:

$_GET['key'][0]='';

The array is handed to preg_replace, which, when given an array to work with, will perform the regex substitution on each element of the array, then return that array. Again, this array contains one element, an empty string, so when it hits the "if(empty($key))" line, it returns false (as the array is not empty). This, in turn, is important because the wpdb->prepare() statement receives an array when it is expecting a string, flattens that array out, and gives you the following query:

SELECT * FROM `users` WHERE user_activation_key = ''

Since the admin user is the first row in the database, and his activation key is blank (assuming nobody has performed a password reset on the account yet), that user is returned, and his password is changed.

That probably wasn't the best explanation, but if you're still with me, that brings us to the question of "what did they do wrong?" The first problem was assuming that $_GET['key'] was a string. While the programmer checked that string for malicious characters (in the preg_replace), he didn't check the type of the variable. Flexible casting of variables is common in PHP apps, but as this example demonstrates, this can be dangerous. As part of your input validation process, you should be either checking or forcibly casting the type of that input. I suspect that the programmer thought he was forcibly casting the input with preg_replace(), but was not aware of how it handles arrays.

Here is the official fix:

if ( empty( $key ) || ( is_array( $key )){
return new WP_Error('invalid_key', __('Invalid key'));
}


Can you see the problem here? This is a classic bad approach to fixing security bugs- patching the exploit, not the vulnerability. Instead of checking whether the input is what you expect (is_string), they are making sure that it isn't what they don't expect (is_array). While this does fix the issue, it is a blacklist approach, not the whitelist approach that would be recommended. What will happen if an attacker figures out how to pass another data type to this function? It may break, it may not. Either way, it's not very fault-tolerant coding.

The reason I'm bringing it up is that this is an excellent case study of an underappreciated programming bug. As useful as PHP's loose casting and overloaded functions can be, you still need to validate your inputs and explicitly verify that they are what you expected.

Thanks to Rafal Los for making me look at this, and working through the mess that is the Wordpress codebase with me.

Labels: , ,

Tuesday, June 9, 2009

Strongwebmail Contest Won

StrongWebMail announced yesterday that we officially won their $10k contest. Surprisingly, they don't appear to have learned from this last round of bad publicity and intend to launch another contest- once they've patched some holes and tightened the rules.

Assuming that the new rules aren't ridiculously restrictive, I'll probably participate in the next round- I've still got a few tricks up my sleeve. However, I must say I feel a bit dirty for feeding this publicity machine. These hacking contests, frankly, are a joke. If nobody gets in, marketing will hail their product as unbreakable. If somebody does get in, they call foul for breaking the rules. While some structure is necessary for any organized contest, the whole point of hacking is finding ways to bend rules and manipulate the system.

StrongWebMail's press release said "It is important to note that the frontend protection offered by StrongWebmail.com was not compromised. In fact, Lance and his team were forced to find a way around the phone authentication." That's not entirely true- we simply took the easiest route. With the webmail app riddled with holes, we saw no point in bothering with the front end. Considering it took us less than a minute from registration to find the hole we used to compromise the app, can you blame us?

I understand that StrongWebMail was created to demonstrate Telesign's 2-factor authentication system, but this is a perfect demonstration that security needs to be addressed holistically. When you claim to have "The Most Secure Email Accounts on the Planet", nobody cares that it's the third party app that is vulnerable- they care about the fact that the email accounts are indeed vulnerable.

The exploit that we used to break in involved an XSS hole in the email preview feature. We sent a message to the CEO's email account, and when viewed, his web browser made several AJAX requests to the server, slurping the contents of his inbox and then depositing it on a logging script under our control. Lance did an interview in which he discussed the details of the exploit further, and I recommend you read that for more details.

Finally, I want to give another big thanks to Lance James and Aviv Raff for working on this with me. Not only was it very fun, but it made some very good points (that will likely be forgotten soon) about web application security: Escape outputs, be careful with what third-party software you use, and don't taunt the hackers.

Labels: , , ,

Wednesday, May 20, 2009

Thoughts on HTTP Parameter Pollution

Luca Carettoni and Stefan di Paola presented at OWASP Appsec Poland, speaking about HTTP Parameter Pollution. The short version is this- by mangling the inputs for a HTTP request, you can cause all kinds of strange behaviors. On a high level, this isn't too different from SQLi, XSS, and plenty of other attacks. What sets HPP apart is that the quirks you can generate aren't all data sanitization issues- they are often logic bugs, which are much harder to test for, easier to introduce into an application, and more fun to exploit.

The presentation involved a few very different attacks, which makes it a bit difficult to summarize, but essentially, it involves overwriting HTTP parameters. A few examples:

PHP applications (and others) primarily get their user inputs from COOKIE, GET, and POST. If the application reads input from the generic REQUEST parameter, the data could conceivably come from any of these, and developers don't always have a clear understanding of how that decision is made. By abusing the order in which inputs are handled, an attacker can generate unexpected behavior in the application- expecting data to come from POST but instead reading it from GET, for example.

This really isn't new- the register_globals mess in PHP stems from a very similar issue. While register_globals is dying a well-deserved death, similar attacks can still be made against the $_REQUEST parameter, which many developers (usually the same ones that used register_globals) rely on. Java, perl, and ASP have all seen the same issues, and are at varying levels of fixed-ness.

The more interesting and sneaky attack: If you pass a query string with multiple copies of the same parameter (e.g. index.php?foo=bar&foo=baz), the application may handle it in unexpected ways. PHP will use the last occurence of that parameter, JSP will use the first occurence, mod_perl converts it to an array, and ASP concatenates the parameters into a comma-separated string. Custom-buit parsers on embedded hardware can be even more surprising.

Now, if the developer is doing his job right- being paranoid about where his inputs come from, validating, and escaping, this should not be a major problem. However, no developer is perfect, and this being a fairly unknown behavior, it is quite likely to pop up. Quirks are edge cases, and edge cases are where you find security holes.

I recommend you go over the slides, and the whitepaper when it comes out (which should soon). Some very interesting, very cool real-world attacks are outlined there (I especially like the ASP SQL reconstruction), but I won't go into them here. In summary, you can leverage these parameter processing quirks against both the server and the client, in a lot of interesting ways:

  • Bypassing input validation

  • Bypassing WAFs

  • Manipulating application flow

  • Manipulating mod_rewrites

  • Forcing/spoofing cookies

  • Manipulating client-side applications

  • Manipulating and polluting page content

As a pentester, I absolutely love these kinds of attacks- they exploit seemingly-benign quirks in the application. They rely on the attacker knowing more about how the application works than the person who wrote it. Besides that, they're wicked fun to play with. I see HPP as yet-another useful tool in my arsenal. Like CSRF and XSS, it is (and will continue to be) extremely common in poorly built applications. Well-designed apps will have minimal attack surface, defense in depth will further limit their exposure, and what holes do exist will be quickly remediated.

HTTP Parameter Pollution isn't an entirely new attack, but it is a much more in-depth revisiting of older flow-control and input parsing issues, specifically at the border between the application and its back-end engine. I expect to see a surge of HPP-related vulnerability reports in the future. From the defender's perspective, though, it is the same story: Know your inputs, know where data flows through the app, validate before you use it, and escape it on the way out.

Labels: , ,

Tuesday, May 12, 2009

Owning Ubuntu with CSRF

When the latest version of Ubuntu was released, it came with a new version of the Transmission bit torrent client. One of the new features of Transmission was a web interface, which would allow users to manage torrents from their web browsers. The service is ip-restricted to localhost.

Why the service should be enabled by default, or why the local user (the only one able to access it by default) would ever want it, I'll never know, but it should be no surprise to anybody that I immediately poked around for CSRF holes.

As it turns out, the holes were there, and though a bit tricky to exploit- it required mangling the form inputs and using the text/plain encoding, Transmission was quite vulnerable. Here's a proof-of-concept. Basically, it allows me to first change the download destination to one of my choosing, then download a torrent of my choosing. This is bad- I could force a user to download a new .bashrc file or overwrite their entire home directory (I actually did this by accident while testing the exploit. Backups are great).

Other problems do make it harder to exploit. First, when you start the torrent, it pops up a box asking the administrator what he wants to do with it. Many people, including myself, have it configured to skip this step, as it's extremely annoying.

When you make the CSRF requests, the result is returned in JSON format, and browsers without handlers for it will pop up a box asking if you'd like to save the file. When this box pops up, it is already too late, as the request has already been processed by the server, but it does at least keep the attack from being silent.

This isn't really a new exploit- Nate McFeters talked about doing the same thing through an XSS hole in the Azureus web interface in his talk, "the Internet is Broken", at Black Hat 2008.

The hole is fixed in today's release, so go ahead and upgrade, then disable that web server.

Please, let's start taking CSRF seriously.

Labels: , , ,

Friday, May 8, 2009

PCI Smackdown: Looking Forward

I've been publishing a lot of holes in security companies' websites, and more are coming next week. While I'll continue to point out these flaws, I'm hoping that we can turn these disclosures into industrywide changes.

I know I've pissed some people off. I'm pretty sure McAfee isn't going to be giving me much love in the future. I personally think that too much attention has been paid to them in particular. Though their official response was pretty lame and not entirely true, they definitely aren't the worst offenders. I must admit, however, if it hadn't been for that issue making big headlines, I don't think as many people would be listening to me now.

At this point, I want to issue an industry-wide challenge- any ASV wants me to evaluate their PCI scanning service need only contact me. I will perform rigorous tests, find whatever issues I can, and publish them in brutally honest fashion. I will provide recommendations to the vendors on how to improve the services, and if I'm impressed with them, I will certainly make that known publicly as well. I will give credit where it is due, but I will happily call you out if you've done something stupid. I have no love or hate for any PCI companies outside my own experiences, and I have no agenda beyond improving the industry.

Do I expect any vendors to take me up on this challenge? No. I am skeptical by nature, but I would love to have somebody take the lead and prove me wrong.

I'm out for the weekend, but I'll leave you with one last batch of screenshots. These are error messages from a handful more PCI ASVs, none of which are critical security issues, but all of which disclose information about the internal workings, directory structure, or configuration of their respective applications. As before, all of these would be found with a simple website audit.

An SQL error in ControlScan's trustmark validation script
SQL error in ControlScan's Trustmark Validation Script

Counterpane CGI Error with file path disclosure
Thanks to Russ McRee for this one
Counterpane CGI Error Path Disclosure

onestoppciscan.com Error Page
onestoppciscan.com Error Page

secureconnect.com ASP errors with stack trace
secureconnect.com Stack Trace

Symantec included file manipulation and file path disclosure
This script actually throws about half a dozen different errors, depending on how you manipulate it
Symantec Filepath Manipulation and Path Disclosure

Labels: , ,

Thursday, May 7, 2009

How to Fix the ASVs

McAfee has been hit very hard this week, and the vulnerabilities in the other ASVs that I published are starting to make waves as well. While it's fun (and it really is) to point a finger and say "LOL! McAfee Fail!", this really isn't helpful. It's time we take this as an opportunity to look at things that are seriously wrong with PCI and the way that it is implemented.

I don't claim to be an expert on the PCI standards. I am just one of many people who is trying to improve the security of his company and the internet as a whole. In my view, achieving compliance should be an afterthought. While any business executive worth his paycheck should understand and value security from a risk-management perspective, the fact is that most respond better to industry requirements. Regulation is a dirty hack, but it at least gets the attention it needs.

Since the service providers already understand that they need to comply with these regulations, we may as well fix them so that they are effective. In my view, here are the major changes that need to be made:

Better Education
For many small service providers, the PCI testing process is the first time they look seriously at their own security. Having them sign a few forms and running a scan on their servers does not educate them, and it does not prepare them to deal with security properly. This sets a poor precedent for a growing company, and in my experience, it invariably causes problems down the road. Having an expert consultant educate the service provider about how to design a security program would do more to protect cardholder, customer and company data than any set of prescriptive security regulations. This phase of the process is usually skimmed over by a company trying to get the not-so-elusive compliance certificate. In my opinion, it may be the most important part.

Better documentation
Without clear definitions of the standards and recommendations for compliance, we'll never get far. Most service providers do not even have a clear understanding of which standards they are expected to comply with, much less how to do so. Instead, they speak with the sales department at the cheapest ASV they can find, perform a scan, and send the vulnerability reports to their system administrators.

To be fair, there is documentation out there, but there's a lot of misinformation too. The official PCI FAQ (which is itself vulnerable to XSS) doesn't provide much useful information beyond the standards themselves and a few supporting documents. Several unofficial forums have sprung up, but the information contained within isn't always reliable.

More Responsibility
To my knowledge, this week's McAfee issues, as well as the issues with other ASVs, have not affected their status as a PCI scanning vendor at all. Given that some of the ASVs' XSS holes have still not been fixed, I find this extremely shocking. PCI companies need to treat customer data responsibly, and need to be held responsible when they do not. Revoking their ability to perform PCI scans would be disastrous to their business, but the stated goal of the PCI standards isn't to keep poorly managed companies in business. If the true goal of these standards is to "help organizations proactively protect customer account data", then the ASVs need to be held responsible when they do not.

PCI ASVs should be held to much more rigorous standards than the Service Providers they certify. I was shocked to find out that regular third-party penetration tests are not a requirement for ASVs. From what I understand (and I may be misinformed), they essentially fill out paperwork and assure the PCI board that they are themselves compliant. Does this strike anybody else as insane?

More Transparency
While the PCI Council provides documentation of proper scanning procedures, they do not go into much depth. In particular, they barely touch on web application scans, while in my biased opinion, this is one of the most vulnerable and therefore critical parts of most Service Providers' systems.

No data is available to the public regarding the relative efficacy of the scans. I'm not aware of anybody with a truly effective web app scan, but I've run several on the same servers (in a rather unscientific fashion), and come up with vastly different results. The free PCI scan offered by nCircle took less than an hour, and only did a cursory inspection of my web application. By contrast, McAfee's scan took close to 3 hours, most of which was spent testing the web application. Neither found the rather basic XSS and SQLi holes that I deliberately put in.

While neither app was up to par, the McAfee scan was clearly superior- at least at finding web application holes. At the time, I was more interested in finding problems with the scanning services, rather than doing a direct comparison of the two. However, it would not be difficult to design a system for measuring the effectiveness of ASV scans. The PCI council should do so. They should make the results of these tests public, and should make scanners' status as an ASV dependent upon them.

Better Enforcement
An end user has a right to know whether the company he is doing business with is PCI compliant or not. A verification process, even as simple as a list of compliant companies on the PCI website, is essential to an effective certification program. Of course, when problems are found, the Service Provider in question should have their certification revoked.

I have come across many companies with poor security practices, and many simply do not care. The financial institution that I bank with used to have its access logs publicly accessible. I first alerted them to the issue over a year ago, and no action was taken. In the course of my PCI research, I coincidentally found out who their auditor was, and after alerting them to the issue, the logs were removed almost immediately.

Ideally, I should not be able to find out who performs the auditing on a company (lest I perform attacks through the ASV). However, only by reporting this issue to the auditor was I able to get it fixed. If I were able to report it directly to the PCI board, and a system were in place for getting that report to the right people, this would not have been a problem.

Better Testing
Finally, we arrive at the elephant in the room: the testing performed by the ASVs sucks.

Scanning has a place in security- it can find unpatched software, poor configuration, and other issues that often go unnoticed. However, until we have strong AI in the scanners, it will never have the ability to detect logic flaws or reliably fuzz for application vulnerabilities.

James Lester (Senior Security Analyst for McAfee, of all places) touched on this last month, and I think he's right- scanning is not effective in and of itself, and should not be relied on as the sole method of testing for PCI compliance. A full-scale audit will find issues that no scanner can, and more importantly, it will give auditors a reliable "feel" for the security of a Service Provider. Any provider that builds their own applications for payment and customer data management should be required to perform a QSA audit, regardless of the scale of the application.

Those Service Providers that cannot afford a full audit should not be allowed to build their own applications. Instead, they should use one of the already approved applications, on a sandboxed or private system. Scanning should still be required, but this way we can limit the scope of this scan to finding out-of-date software, unpatched holes, and configuration issues- things that the scanners are already very good at.

Labels: , , ,

Wednesday, May 6, 2009

Abusing PCI Scanners

My company has a client with a small but successful ecommerce site. This site is a prime example of what I'd like all ecommerce sites to look like- thoroughly tested code, FTP disabled and no other unnecessary services running. The client is careful to make sure that patches stay up to date, and system logs are regularly reviewed.

It's one of the few companies that I would trust to handle security themselves. Unfortunately, this client needs to have his website tested for PCI compliance. He signed up with an ASV, and they started running scans. When the results came back, it showed every port on the server as being closed. A bit of research determined that the IDS had kicked in during the initial portscan and blocked the scanner from accessing his website at all- exactly as it should have. I received an email from the client:
They told me that [their server] needs to be 'whitelisted' - Their IP address needs to be listed as 'friendly'.

Essentially, we had to whitelist their IP on both IDS and firewall in order to get the PCI compliance certificate. This is pretty common throughout the industry, and I've heard this request from clients using a variety of ASVs.

Any security person should notice the problem though- the scanning system could not get past the IDS, so we opened the door and invited it to come in and break things.

I don't think many people have looked into the implications of this. Security administrators routinely poke holes in their own systems for the purpose of achieving PCI compliance. If that scanner were to be compromised in any way, it would leave my client's system (and thousands of others) vulnerable.

On Monday, I published details about a critical McAfee CSRF hole. Yesterday, I disclosed vulnerabilities in a handful of PCI ASVs' web sites and customer portals. Compromising the security administrator's account with web exploits is just one way to abuse the scanning service. Here are a few more-

  • Client credentials can be compromised through offline attacks. In a recent weekend trip, I was driving by an ASV's office. On the top of their dumpster was a stack of customer signup forms with usernames, passwords and contact info- faxed in, entered into the system and discarded without even a trip to the paper shredder.

  • The auditors themselves can be compromised in the same way- next to that customer information were printed pages from the administrator side of the ASV's website. Sales scripts, emails, and everything necessary to perform a social engineering attack were there too.

  • Once the client or auditor accounts are compromised, the attacker gets lists of servers-including "secret" database, backup, infrastructure, development servers and others that shouldn't be publicly known. Along with the servers, they get nicely-formatted reports of all the vulnerabilities found

  • In general, A few servers will perform the scans on all an ASV's clients. If compromising accounts isn't to your taste, you could just sign up and pay for the service. In most cases, all that's keeping you from scanning systems other than your own is a service agreement. As one employee at an ASV noted: "I am...waiting for a rogue account to use an ASV to scan sites that they don't have privileges to scan...to assist them with identifying vulns." Would they know if it had happened? With IDS disabled and scans already performed at random intervals, who would notice? It may not have happened yet, but it's bound to happen eventually.

  • Knowing the source IP of the scanner (and knowing that it has full access to the target system), packets may be spoofed and a malicious payload delivered.

  • Many ASVs use Nessus to perform these scans. It would be theoretically possible to piggyback a targeted, malicious payload with a normal plugin update. This probably wouldn't be worth the effort, but the idea of subverting the entire security community to execute a single attack appeals to me in a sick way.

I understand the good intentions and even the necessity of performing website scans. I should be clear: I am all for the testing of applications and systems, and I think that by and large, most systems are better off because they perform these PCI scans. The problem is that when we are trying to get that compliance certification, we approach it with an engineer's mindset ("How can I make it work?") rather than an auditor's mindset ("How can I make it fail?"). Even in the process of securing our systems, we need to stop at every step and consider the implications of our actions.

Assuming that the PCI ASVs treat clients and data with due care, these attacks are mostly not practical. Considering how irresponsible these security companies often are, inviting them to attack your server is likely a Bad Idea.

Labels: , , , ,

Tuesday, May 5, 2009

Risky.biz Podcast Interview

I just finished an interview with Patrick at Risky.biz for a podcast about my McAfee CSRF and the other PCI ASV vulnerabilities. If you're into this kind of thing (and the traffic spikes I've seen this week indicate you probably are), go give it a listen.

http://risky.biz/netcasts/rb2/rb2-mcafee-bug-finder-mike-bailey-speaks-riskybiz

Labels: , , ,

Most PCI Companies Are Insecure

The McAfee XSS got slashdotted. I think that all this attention is a good thing, putting a spotlight on XSS issues, but I have to say, I'm surprised by it. It's not like XSS attacks are news anymore, and it's not as if this is the first McAfee XSS to be published. Last night, I found an XSS hole in the verification script for their SiteAdvisor service (for extra irony).

McAfee SiteAdvisor XSS

But really, focusing on these XSS holes is missing the point. I never thought I'd say this, but in my experience, McAfee is one of the better ASVs out there. This isn't a compliment to them, it's an insult to the entire industry. Here are a few examples of other ASVs.

Until last week, atsec.com was vulnerable to XSS.

Until last week, secureconnect.com was vulnerable to XSS.

Until last week, ncircle.com was still vulnerable to XSS.

sungard.com is still vulnerable to XSS.

controlcase.com is still vulnerable to XSS.

support.foundstone.com (McAfee's premium brand) is still vulnerable to Cross-site Framing.

Up until a few weeks ago, there were also open redirects on the websites of Qualys, SecurityMetrics, and others. Is it any wonder I'm not at all shocked at a few XSS holes in McAfee's web site?

Some of these companies should be commended for handling the vulnerabilities correctly- nCircle, SecureConnect, Qualys, and even McAfee responded admirably- sometimes the issue was fixed within minutes of my vulnerability report. Others- Foundstone, ControlCase, and Sungard, belong in the doghouse- none of them even responded.

However, the glaring fact is that the entire PCI scanning industry is, frankly, bad at scanning for vulnerabilities. Most of these websites use their own scanning service on their own websites. While I still hold that in-depth audits for these sites should have taken place long ago, the scanners should have caught the problems as well. Some of these domains contain the portals for customers to manage their PCI compliance scans.

People, let's take the focus off of McAfee, and put it where it belongs. The PCI scanning industry as a whole is a joke, and across the board, these Web Security companies are themselves bad at security.

Edit 5-6-2009: nCircle was one of the fast-responders.
I mistakenly listed them as one of the "doghouse" ASVs.

Labels: , , , , , , , ,

Monday, May 4, 2009

Epic Failure from McAfee

When you outsource all your PCI scanning to another company, you'd expect that company to be careful with your data. First off, there's the fact that security is what they do- if that data were to get leaked, you'd expect the damage to reputation alone to be crippling.

Second, (and probably the least important, really), the PCI ASV validation requirements (section 4.5.1, if you're interested) make it pretty clear that client data should be kept very confidential.

Finally, the data contained on those servers- lists of vulnerabilities on all their clients' systems, along with security administrators' passwords and more, is pretty high on the list of Things You Don't Want Getting Out.

You know what's coming.

We've found problems with McAfee time and time again. I was saving this for a post later this week, but given recent events, I think the time is right.

Until last week, McAfee Secure was vulnerable to critical CSRF holes. Not little ones, or ones that were difficult to exploit- basic, zero-kowledge, classic GET-based total-account-compromise holes. I think the pictures tell the story:

Logged in, 3 Accounts

iframed CSRF Attack

Malicious User Added

Account Confirmation Email

I sent a vulnerability report to a contact at McAfee and they responded quickly, communicated with me, and fixed the issue. They also began reviewing their entire codebase for similar holes. I commend them for that, but I cannot overlook the fact that this vulnerability never should have existed in the first place.

It's not going to be a surprise to anybody, but this is solid proof that McAfee Secure is mis-named. Their failure here is on an epic scale:

  • They did not comply with PCI requirements for ASVs

  • They did not use a secure software development lifecycle in building this application

  • An in-depth penetration test should catch an issue like this, so I presume that no such audit has taken place

  • Until I reported it, they had never performed a full code review for web vulnerabilities

  • As you can see in the 1st and 3rd screenshots, the application was itself certified as McAfee Secure when I performed this demonstration.

  • At no point in five weeks from me finding the vulnerability and it being fixed was that McAfee Secure logo removed from their own website.

The ultimate and obvious irony, however, is that McAfee Secure is in the business of testing others' web applications. I'll be the first to say that they are not equipped to do so.

I have a lot more information coming on this and related issues. Try the veal, tip your waitress, I'll be here all week.

Labels: , , , , , ,

Tuesday, April 28, 2009

Full Disclosure: Terms of Engagement

As part of my research, I have been reporting a lot of web-based vulnerabilities lately. I've been using the following procedure to report those vulnerabilities, and I think that I should make this procedure known.

When I publish a vulnerability, I will make what I feel is a reasonable effort to inform a website or application's maintainer about it before making it public. I enjoy breaking websites, but I have no intention of causing any particular company or website harm. Having reported hundreds of issues over the past few years, I've found that often, they are only fixed when there is a threat of them being made public. My goal is to promote quick patching of holes, to fix what I see as widespread poor security practices, and to educate system maintainers about the risks that they face.

Before submitting a report, I will check several vulnerability tracking services. If unfixed issues that are over 1 month old exist, I will assume that the site's maintainers do not take these security issues seriously, and I will publish the vulnerability at my discretion. I may or may not attempt to contact the affected site's owner.

If no old vulnerabilities exist, I will check the website for a contact email address. I will not submit vulnerability reports through web-based contact forms, customer portals, or by speaking with a salesperson. If an email address is not available on the website, I will do a whois search for this information. Barring that, I will attempt to email the report to abuse@, info@, root@, security@, and webmaster@yourdomain.com.

Once a vulnerability report has been submitted, I will wait one week for a response before publishing at my discretion. If the website's maintainers are responsive, acknowledge the issue and keep me informed with regards to the patching process, I will attempt to coordinate my disclosure so that it is published after the issue has been fixed, and may postpone the publishing to do so.

I will note that I only provide notice as a courtesy, to give website maintainers an opportunity to address the issues before they go public. While no website is perfect, I expect website owners, particularly those with business-oriented websites, to act responsibly in handling these issues efficiently.

Some researchers are more generous with timeframes and will even attempt multiple contacts over several weeks. In my experience, a site owner that is unresponsive for the first week will rarely improve in the next. My own time is valuable and I have no intention of wasting it in contacting an unresponsive party.

When I do make a vulnerability public, I may choose to do so through a public vulnerability tracking service, on my own website, or in the form of other writing, speaking, or consulting engagements. If the response and interaction I recieve from the site owner is positive, I will generally attempt to make that known at the time of publishing. The corrollary is also true- if my report is met with disinterest, threats, or negative feedback, I will make every effort to ensure that it is publicly known. Frankly, you don't want to go there- controversy tends to make headlines.

As noted previously, I am here to help, but I'm not necessarily here to help you.

Labels: ,

Monday, April 13, 2009

Photobucket Private Album Access via CSRF

I've been playing a lot with CSRF lately. As I find ways to manipulate more and more services with what is probably the most basic type of attack possible, I keep getting surprised by the insanely cool things that one can do with it.

Photobucket allows users to make albums either "Public" or "Private", the latter of which will enable access only with a guest password. While chatting with a friend online recently, I tried to view one of her private albums. Knowing what I do for a living, she gave me permission to do so, but said I'd have to find my way in without her help. So I did.

The form for setting a private album's password, as well as the one for making an album public, both are vulnerable to CSRF. In fact, both use GET parameters to do their magic, so it's actually pretty trivial to pull off a successful attack. I wrote a proof of concept, but it's really not that complicated.

Not only can users' albums be made public, but variations on this exploit can be used to change passwords on albums, delete photos, and compromise account passwords. This really is a serious issue- while Photobucket's TOS may protect them from liability (and may or may not hold up in court), there are a lot of extremely private photos stored there.

I emailed a vulnerability report to Photobucket on the morning of 4-9-2009, but have not received a response.

Labels: , , , , ,

Wednesday, April 8, 2009

Solving Semantic CAPTCHAs with Google

This came up in a discussion with a developer quite a while ago, and I've been meaning to write a proof-of-concept. So far, I haven't had a chance to, but I think the idea is interesting enough to talk about alone.

The idea of using semantic CAPTCHAs has been discussed quite a few times over, and even implemented in a few cases. So far, these implementations have worked reasonably well, but that is only because they aren't worth the trouble yet.

One example of a semantic captcha is found on php.net, the online bible for PHP developers. Each PHP function's manual page has a "comments" section where people can leave helpful tips for using the function in question. This comments form is a particularly poor implementation of a semantic CAPTCHA (it's vulnerable to replay attacks, has a very limited number of possible solutions, among other things) and also contains an open redirect hole. Let's focus on solving the captcha without using those flaws.

PHP.net semantic captcha

This captcha asks the user to solve a math problem, but substitutes words for mathematical symbols. In this example, the question is "two minus one". Anybody who has ever used the Google calculator can solve that one with a single request to http://www.google.com/search?q=two+minus+one:

Google Calculator breaking Semantic Captcha

It's a simple matter of plugging the data into google and parsing the output. It could be argued that this isn't really a semantic CAPTCHA, just a mathematical one with a semantic output format. Other developers suggested asking pop culture or trivia questions. The example that was given to me was "Is Paris Hilton A Slut?". The obvious flaw with this question is that it has a boolean solution, and 50% isn't a very good success rate for a CAPTCHA. However, if we wanted to improve our chances, we could turn to Google again:

Google Results: Is Paris Hilton a Slut

Just by parsing the titles of the returned results pages, we get two titles with negative operators. If we parsed the result descriptions, we'd get a few more, but statistically, it's pretty clear that Google thinks Paris Hilton is a slut. The AI to do this type of language processing has been around since 1966.

Labels: , , ,

Monday, April 6, 2009

cPanel Root CSRF: Round 3

Readers who have been with me from the beginning (as well as the guy that read my entire site yesterday) will recall that last fall, I posted several XSS and CSRF vulnerabilities with the cPanel WHM interface. Essentially, these vulnerabilities would allow me, as an attacker, to root a cPanel server simply by having an authenticated administrator browse my website. At the time, the vendor did not respond to my vulnerability reports, and the problems went unfixed until I resubmitted them to Secunia in February.

cPanel finally took action, fixing the XSS hole that I had found. However, the CSRF issues (which were much more critical in this case) were ignored. Their response to these issues was that CSRF can be prevented using the "XSRF Protection" feature in the WHM administration interface. I double checked and sure enough, there was such a feature. It was obscure, disabled by default, nowhere to be found on the cPanel documentation pages and FAQ (which ironically has its own XSS holes), and had verbage next to it that would discourage most administrators from enabling the feature. Essentially, cPanel treats these critical CSRF holes as a feature:

cPanel XSRF Protection Setting

I didn't have all that much time to look into it until today, when I decided to actually test this feature. Digging into the code, the first thing I noticed was that all the "XSRF Protection" does is check the referrer that your browser sent- if it doesn't match one of the known domains for the server, the requested action is not allowed to take place.

The first way around this was obvious. If your browser does not send any referrer, the XSRF protection does not kick in. Referrers can be suppressed several ways, but the first one that comes to mind for me is SSL. Many browsers will not send referrers when coming from an SSL page. This morning, I wrote a proof of concept that bounces the user off an SSL-encrypted open redirect (there's plenty of them out there). A few tests with the latest version of cPanel confirmed that Firefox 3 does not send a referrer, and the XSRF Protection feature had no effect.

Assuming that the browser did send referrers, there are still plenty of ways to bypass it. The next thing that comes to mind is simply using a domain on the whitelist to execute the attack. With a few hundred users on most cPanel servers, finding an open redirect, file upload, XSS, or cross-site framing hole is usually trivial. If you combine that with the mod_userdir attacks I posted last week, you can increase the effectiveness of this attack even further.

The next idea I had was to add my domain to the list of allowed domains. It requires access to a local account on the server (legitimately or not), but any user can add extra domains and subdomains to his site- subdomains which are considered "allowed" by cPanel. This provides yet another effective way to avoid the XSRF protection feature.

The back end code for the cPanel interface is an absolute mess- it's amazing that it works as well as it does. Not just the WHM interface, but the entire package is vulnerable to CSRF and XSS attacks at nearly every level. This software manages hundreds of thousands of websites.

This is bad.

But preventing CSRF would break your third party billing software, so we should probably allow it by default. That's a great idea.

Edit: cPanel did, in fact, mention the XSRF Protection feature on their blog about a year ago. This post calls the CSRF issues "security issues, which range in severity from trivial to medium-critical"

Labels: , , , , , , ,

Thursday, April 2, 2009

Opening Doors With XSS

This is the first in a series of posts on "cool things I broke with web exploits."

A few weeks ago, I demoed an access control system from ADT. Being the bad person that I am, I was less interested in the system's features than I was in the ways that it could be broken, and as soon as I heard it had a web-based administration interface, I knew I was going to have fun.

Like any good hacker, I paid careful attention through the demonstration, probing for more information about the system ("How many customers use this system? Banks too, huh? Which banks? Do they all use the same admin interface?"), slyly jotting down the username and password from the post it note on the demo kit, and making careful note of the admin login's URL. After the presentation, I did a bit more online research, and came up with the following-

The system in question (Brivo ACS) is widely installed by ADT, but was designed by a company named Brivo Systems, LLC. Brivo runs the servers and maintains the application. ADT, as well as a wide range of other companies, function as dealers, resellers, and installers. Roughly 25,000 doors are controlled by one server, with users ranging from financial institutions to IT datacenters. The system runs the logic behind HID and other token-based authentication mechanisms- You scan your card, the server decides whether you are allowed in, logs the request, and opens the door.

So I set out to find an exploit. It being a web app, I was in my comfort zone. Probing for input validation holes, I was pretty impressed with the thoroughness of the filtering.... until I found an error page.

I love error pages, they tell you all kinds of useful information, including account data, a stack trace, and internal application variables. For bonus points, they print it all out without any escaping. Once I found the error page, I was just one request away from a working XSS exploit:



The consequences of this are huge- while it may not be a simple exploit to pull off, this gives an attacker the ability to steal sessions and manipulate a building administrator's browser. An attacker can easily add his own keycard to the list and walk around secured areas uninhibited. That's a pretty Big Deal.

So, for all those people that think XSS is a minor issue, I present this as Exhibit A.

On the plus side, Brivo's response to my emailed vulnerability report was exemplary. Almost immediately, I had a call to let me know they were looking into it. The next day, a developer spoke with me about it, and by the end of the week, a patch was being tested. I have to give them credit- they responded quickly and professionally. They're currently doing a full review of their systems for other configuration issues (like the error page) and input validation holes. They even invited me to poke around some more once the review process is complete.

Lessons learned- Web-based administration is tricky stuff to do right, XSS does very cool things, and I like companies that listen.

Labels: , , , , ,

Wednesday, December 3, 2008

Redirecting Safely

I don't think this is news to the other security people, but as a developer, I had never heard of this issue. As far as I know, none of the developers I regularly work with had heard of it either (though using the code as recommended by the php.net manual will prevent it).

In many PHP applications, there is an admin side and a public side. It is common for developers to have an "admin check" in the code header of the admin side, which essentially evaluates whether a user is authorised to view a resource and either redirects them to the login page, the public page, or lets them through to the resource.

What many developers don't realize is that a browser doesn't have to terminate a connection as soon as it receives a 302 redirect. If you are relying on the following call to keep the riffraff out of your admin pages, you may be vulnerable:

header('Location: login.php');

I can't tell you how many times I've been able to access reports full of user logins, order information, or even account modification functionality, simply by asking my browser to continue loading a page after receiving a redirect. If you need a testing tool to see if you are vulnerable, I whipped up this perl script one day to allow me to simply snag admin pages or post content to them during a penetration test.

In case it isn't obvious, you can prevent this hole simply by halting the flow of the application. If you aren't using more advanced templating and flow control (which I'd recommend anyways), this will work:

header('Location: login.php');
die('Kindly piss off.');


While obvious, this issue is incredibly widespread, and I have to wonder how many developers are unaware of it.

Labels: , , ,

Monday, October 6, 2008

Diary of a Hacker - Part 1

Here's the first of many writeups for my "Hacker Challenge". Keep in mind, this isn't a penetration test- it's just a train-of-thought writeup of how I cracked an application. The idea is to demonstrate instances of various attacks in use, rather than the theoretical proof-of-concepts that appear in most security web sites.

The site is a file repository- basically customers can pay a monthly fee to have access to a virtual filing cabinet-type-thing. I don't think that's a fabulous business model, but that's not the point of this blog. After familiarizing myself with the site, my first attempts were file upload attacks (naturally, given the purpose of the site). Fortunately, the site used several layers of protection for uploaded files- first, it only allowed a whitelist of filetypes, preventing malicious files from being uploaded. Next, it stored those files in a non-web-accessible directory. Even if I could get a malicious file uploaded, I could not access it directly. Finally, the filenames were randomly generated- if I found a way to circumvent the access control, I still would not know the name of my malicious file.

Basically, this type of attack didn't work; I moved on.

Throughout the site, inputs were validated thoroughly (excessively in some cases). No matter where I looked and how much I mangled the inputs, I could not find an SQL injection hole. I did find a reflected XSS hole in an obscure stock script, so I decided to work with that. My goal was to
steal an admin session using Javascript, and after setting up my evil little javascript-session-stealing kit (I'm quite proud of it), found out that this also wouldn't work so easily. The developer had added the following directive to php.ini:
session.cookie_httponly = 1
This directive made it so that session IDs were inaccessible to client-side Javascript. I could have still used the XSS hole for other things, such as forcing the administrator to perform actions on my behalf, but this would require work and inside knowledge to code, and would have a relatively low chance of success.

I'm rather lazy, so I moved on.

I went to myipneighbors.com and found a list of sites on the server. It didn't take me long to find one with some known vulnerabilities, and next thing I knew, I had filesystem access. Faithful readers already know where I'm going with this, but mass-hosted servers are a Bad Idea. Even so, it is possible to configure file permissions and code a site so that an attacker can't simply walk in and read your configuration files.

I whipped up a quick script and ran it on the compromised account (The server runs FreeBSD and cPanel). This script monitored the output of `ps -aux` while fetching a page from the target account. Because of suexec, I immediately knew the username of the targeted website.

With this information, I tried to read files from the public_html directory, but the permissions were set up (mostly) correctly and prevented access. While I couldn't list the files in the directory, I could guess at their filenames, and eventually landed on one file that was readable- php.ini.

Reviewing the site's php.ini file, I could tell the server was relatively locked down, but one line in particular caught my attention:
session.save_path = /home/theSiteUsername/tmp/
I tried to list the files in that directory and was able to view a list of open sessions' IDs. This was the hole I needed to compromise the account:
$ ls -la /home/theSiteUsername/tmp/ | grep sess
-rw------- 1 theSiteUsername theSiteUsername 5068 Sep 18 09:20 sess_1a1aexxxxxxx5e282e1a5747694ec8e2
-rw------- 1 theSiteUsername theSiteUsername 5023 Sep 18 09:19 sess_462fexxxxxxx13dafa331bc15e962e22
-rw------- 1 theSiteUsername theSiteUsername 5109 Sep 18 10:51 sess_717edxxxxxxx653df341f91d096e0484
-rw------- 1 theSiteUsername theSiteUsername 5079 Sep 18 09:14 sess_91850xxxxxxxef480524c23412b23dc1
-rw------- 1 theSiteUsername theSiteUsername 5011 Sep 18 10:38 sess_9246dxxxxxxxe6e710a9e623af23ca95
-rw------- 1 theSiteUsername theSiteUsername 5079 Sep 18 09:25 sess_a4cdcxxxxxxx065ede6ecb062d443f86
I then manually set the SESSID cookie in my browser to those found in the session filenames, and confirmed that I could hijack other accounts' sessions. Unfortunately, none of those sessions were administrators. I wrote a shell script to watch the directory in question and send a text message to my cell phone when a new session is created, but no admins logged in over the 50-something
hours that I waited.

While this tactic would eventually work, I wanted to speed things up. I sent the following email to the programmer:
Log into the admin section and check the 'edit_users.php' page.

;)
The developer and I have done a fair amount of trash-talking about this account in the past, so worried that I had successfully hacked the site, he logged in to check the admin section. As soon as his new session was created, I hijacked it, accessed the admin page, and snagged a screenshot as proof.

So what could have been done to prevent this attack? A few little things.

First, making the ~/tmp directory globally unreadable would have prevented me finding session IDs. This isn't failproof, as there are other ways I could have found them, but every little bit helps.

Second, adding further session validation would have made hijacking the session very difficult. This can be as simple as storing the source IP address in the $_SESSION array on login, then comparing it on each pageload to make sure the user isn't suddenly coming from the other side of the world. Admittedly, there are legitimate uses that would have issues (web proxies and Tor, specifically), but it would have closed the hole. If the site's user base are likely to be behind proxies, there is other information that can be used to identify the browser uniquely- client's user agent, supported protocols, OS, connection latency, etc.

The biggest lesson here, though, is to follow the 'defense in depth' mantra.

Labels: , ,

Thursday, September 18, 2008

Diary of a Hacker - Introduction

I work for a web development and hosting firm, where have an ongoing competition. Our webapp developers submit their newly-built sites for a voluntary cracking attempt. If I cannot in some way compromise, abuse, DOS, or gain escalated privileges, the developer in question gets a monetary prize.

So far, I have not failed, and the prize keeps getting bigger.

Of course, it isn't really a code audit or even a penetration test. Primarily, it's a way for me to hone my own skills while informing our developers about web security issues. The contest has a somewhat limited scope- I must get in by abusing a hole in the code or configuration, so social engineering, server configuration, and other attacks are out (at least as the primary attack vector, though I may use them as leverage against another hole). It also is limited to single-developer applications, so they tend to be small in scale.

I'm writing about this here for two reasons. First, I think it's a very good idea. We have had an extremely positive response from the developers. They code better than ever. They are actively engaged in maintaining the security of the applications, rather than building and then forgetting about them. The contest has sparked many insightful discussions about various security concepts, including CAPTCHA, PHP session management, and XSS filtering. If anybody out there manages a team of developers, I highly recommend holding a similar competition.

The second reason is because I've received permission from the higher-ups to publish some of the post-exploitation writeups on this blog. I hardly consider myself to be the best web application hacker out there, and I don't think I'm a definitive authority on the subject, but I've found (and I'm not alone) that very few non-security people, particularly the developers in charge of building the applications, know how an attacker works.

I'm hoping that by showing the thought process and techniques that I use, I can enlighten a few developers, project managers, and maybe even a few other security-folk.

Labels: , ,

Tuesday, September 9, 2008

A Grain of Salt

From time to time, I'm asked to evaluate a particular application for use on my company our our customers' servers. This is often depressing, as most of the ready-built web apps out there are poorly written at best. This is pretty much the status quo, it would seem.

I evaluated V3 Chat, a web-based instant messenger service, about a year ago for a client. Based on the high number of XSS and other holes in the software, I strongly recommended against it. The client found another solution, and life went on.

Today I was asked to look at it again, as another client wanted to use it and a new version has since been released. Within seconds, I found the first of many holes in their demo.

Normally, this wouldn't irritate me so much- recommend that they not use it, move on with life, etc. But the vendor's web site states the following as a bullet point:

"New! - Improved User Security. Greater safety and security for private chat conversations. Increased protection against XSS and MySQL attacks."

The really irritating part to me here is the fact that they are using improved user security as a sales point, when not just the original, but the "improved" version of the software would not pass basic PCI compliance testing. They haven't even fixed the XSS hole that I emailed to the vendor several weeks before sending it to XSSed.com about a month ago (this was partially the inspiration for my Open Letter to the Internet at about the same time). While this software is, in my professional opinion, lousy, this is nothing new to the web. Unfortunately, there is a lot of broken software out there, and very few vendors, much less their customers, realize this.

What would it take to fix the web? A lot, I'm afraid. Bruce Schneier keeps telling people that it starts with legal accountability on the vendor's part, which I'm inclined to agree with. In the meantime, you can secure your own web services with a healthy dose of skepticism (hence, the title of my blog). It's common enough that it's not even news anymore, but I've seen far too many instances of encrypted, unbreakable, or "improved" software turning out to be insecure.

Whenever my company is looking to use some commercial software, they run it by me first. I talk to the sales representative and am always told that the product is perfectly secure, will solve all my problems and whiten my teeth while I sleep. Invariably, I get a demo copy and find holes in the software.

This in itself isn't always enough to get a negative recommendation; I send the vendor my findings, and watch how quickly the issues are resolved. After evaluating the vendor's response to the problems, I can finally make a recommendation. Usually, we end up building whatever we needed in-house. The times that we don't, we usually wish we had.

Often, the vendor is the most surprised to find out that their magical software is full of holes. At least, they act surprised. Don't trust the marketing, don't trust the reviews in ad-supported-magazine weekly. If it's going to be used somewhere important, it's worth your time to look for yourself. If the vendor won't let you demo a copy, move on. If you haven't the time or the knowledge to evaluate it, I have both, but less money than I would prefer.

That's my rant for the day.

Labels: , ,