Skeptikal.org

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: ,

Thursday, April 16, 2009

PHP.net XSS: Mass Carnage with Mirrors

I found a minor hole in php.net the other day. It's a small reflected XSS hole that uses URI parameters. At first, I thought it wasn't a huge deal, and wrote up a vuln report.

Then it occurred to me to look deeper, and I found that there are hundreds of mirrors of the php.net site, spread across the internet in what turned out to be some awfully interesting locations. Many of the domains it is mirrored on are web hosting companies, and most of those have some type of customer portal on the same domain. In addition to these, there are some .gov and .edu sites of interest, and the really interesting one- Facebook.

php.mirror.facebook.com XSS

While Facebook's session cookies are set as HttpOnly and not accessible to javascript, this is still a serious issue. First off, not all browsers support HttpOnly cookies. Second, HttpOnly implementations aren't perfect. Finally, even the non-HttpOnly cookies contain valuable data which can be leaked through the subdomain. I wrote up a proof of concept that will allow me to de-anonymize users by reading their facebook UID off of php.mirror.facebook.com.

In fact, I sent a vulnerability report to Facebook as well, and sent them the wrong link- normally I'd just pop an alert box as a proof-of-concept, but I accidentally sent the link with the weaponized cookie-stealer in it. Much to my surprise, I checked my logs this morning and found that one of Facebook's product managers had clicked the link. I suppose there' a lesson in there about not trusting the link that some random hacker sends you, even if they seem helpful.

Facebook Product Manager's Stolen Cookie

The php.net people responded quickly and fixed this vulnerability, and the fix is slowly propagating to the mirrors, but I have no doubt that more exist. This got me thinking about the possibility of writing a cross-domain XSS worm. It turns out, it's completely possible, though in this case the scope is a bit limited.

Lessons learned: Be careful with where you get your content, and what you put on your subdomains- mirror.victim.com can nearly as useful to an attacker as www.victim.com.

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: , , , , ,

Friday, April 10, 2009

Cgiecho XSS and Information Disclosure

cgiecho is a test cgi script, usually packaged with a formmailer called cgiemail. It's found in the cgi-bin directory of a lot of sites, due to it being a default script in many cPanel installations. The script was written by somebody at MIT some time ago, and so is common on high-profile sites such as mit.edu and
xmission.com.

The script contains XSS and path disclosure holes, one example of which can found on mit.edu, but that's not really the emphasis of this report.

Basically, cgiemail allows a user to specify a template file from anywhere within the web root. When data is posted to it, substitutions are made based on the parameters posted and the content of the template file.

For example, if a template file "/templates/mail.txt" contains the following:

Hello [firstname] [lastname]!

When the parameters firstname=dr&lastname=evil are submitted to http://victim.com/cgi-bin/cgiecho/templates/mail.txt, the returned page will make those substitutions.

Many web scripting languages dereference array values using the [] characters, so the cgiecho script can be forced to return the contents of sensitive files if the index of any one array is known.

If a configuration file is located at /includes/config.php and contains the following:

define('HOME', $_SERVER['DOCUMENT_ROOT']);
define('USERNAME', 'victim');
define('PASSWORD', 'secret');


An attacker can post "%27DOCUMENT_ROOT%27=bork" to http://victim.com/cgi-bin/cgiecho/includes/config.php and read the contents of that file.

define('HOME', $_SERVER[bork]);
define('USERNAME', 'victim');
define('PASSWORD', 'secret');


For testing purposes, a form to generate correct attack parameters is located here.

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, April 1, 2009

Scanless PCI Source Code Leaked

I was just sent this code by a hacker who asked me to call him "bWNrd-A". Apparently he found his way onto the Scanless PCI network and managed to get a copy of the application they use for their audits.

I've been tearing into PCI compliance testing pretty hard lately, but having reviewed the code, I can't see a lot wrong with it.

Application Security Specialist

You've probably noticed that I haven't updated much since the beginning of the year. I've been studying up for a new certification, and as of this morning, I am a certified Application Security Specialist. I'm hoping that being an ASS will give me new respect from my peers in the security industry.