(This resolved 3-22-2014 before I finished writing the report, so it must have been reported before me)
tl;dr : Google documents leak full name and e-mail address via ClickJacking the “request permissions” dialog in a private doc.
Victim visits the evil site.
The evil server uses the google docs API to creates a unique document for the visitor.
The document is named with the unique session id of the victim.
The document is set to private.
A URL to the new document is returned to the server.
An iframe is created with the following page from google:
This page is cropped to only have the “request access button”.
Style is used to make the iframe 100% transparent and always on top of the page.
The resulting “Click Jack” or UI Redressing would look like:
When the user clicks anywhere on the evil page they are actually clicking on the “request access” button. of the google doc.
Once the user click on the link the page starts polling with ajax for an update from the server.
Google sends an e-mail (on behalf of the user including full name and e-mail) to the creator of the document (email@example.com) to request access.
The evil server is running an IMAP client listening for document requests to firstname.lastname@example.org.
The IMAP client receives the request from the google doc that is named by the session id. The evil server can now tie the user session (from the document requesting title) to the “from: “ name and address from the request. The polling request from step 6 will be updated with the identity of the current user.
Nodejs was used for the server which allowed a simple web server (express) and IMAP client to run in the same container. This allowed me to inject directly into the user session. Once the e-mail was received.
The server could have been made better by pre-building a handful of documents and reusing them once a user had clicked for access. The server should also clean up / re-pool the documents once the user leaves or on session timeout.
“Facebook now offers applications the ability to serve canvas pages to users not currently logged in to either Facebook or the application, or the user hasn’t agreed to the Terms of Service for the application.”
This means with a successful attack an app could exploit all users not just those who have already joined our facebook app.
FBJS allows us DOM Element Traversal with functions like getElementById and getChildNodes. This allows us to get info from any object in our canvas sandbox, even those rendered by facebook.
Lets say we use a “Public Canvas Page”, and want want to get info about users who have not yet added our app.
We will use the following FBML:
We use 2 FBML tags “fb:profile-pic”, and “fb:multi-friend-selector”. FBJS does not allow us to access these elements directly, but because we wrap them in a div that we created we can use the element traversal functions:
Reading information is one thing but we really want full control. Facebook does allow us to use flash with the Fb:swf tag, but they render the embed tag for us and always include the allowscriptaccess="never" to prevent unwanted script access from flash. They do however provide: Fb:fbjs-bridge. This allows you from flash to comunicate with FBJS and FBML.
The problem is this item is rendered inside our canvas area therefore the attack mentioned above can be used to actually change the src (with setSrc which i assume is meant for IMG tags) of the “bridge” flash to an swf file owned by us giving us unrestricted script access.
HTML 5 does not do much to solve browser security issues. In fact it actually broadens the scope of what can be exploited, and forces developers to fix code that was once thought safe.
Lets look at the facebook touch page touch.facebook.com (iphone web interface). There are a few things you should notice:
If you are logged in to Facebook, you are automatically logged in to this page. Some awesome magic session lets this happen.
If you click on any URL you see the links dont actually change the page but load them with ajax. http://touch.facebook.com/#profile.php actually loads http://touch.facebook.com/profile.php into a div on the page.
This interface does not do any actual frame breaking only clickjacking protection, which really doesn’t matter for what we want to do.
Because the content of our payload is set with “innerHTML” we can’t just plug in a <script> tag and expect it to work, but other events will fire. In this example we simply make an image with a bad src and an onerror handle.
Now we can load a remote script to do the work for us:
Now when a user views the evil site the hacker has full control over touch.facebook.com. The attacker can:
Know who you are
See your photos
Read sent messages
Read most private data (e-mail, phone, friends)
But lets assume that’s not enough. What if we need access to facebook.com for some reason. Maybe we want to take over a facebook app owned by the user.
This was all done client side. Ajax loaded the payload then we used DOM to load the iframe for the rest of the exploit. The hash part of the url is not sent to the server making it almost impossible for facebook to know what was exploited.
Facebook could simply force all urls to be relative to the base url by adding ‘/’ to the front of all requests before sending ajax.
Also the XHR now supports an origin attribute from the request, so facebook could check that the origin matches facebook.com before loading in the content.
Things to Note
Facebook is not alone in this exploit, I have notified other sites and jquery libraries which suffer from this same attack.
Cross-Origin Resource Sharing is currently available in Firefox 3.5, Safari 4, and Google Chrome 2. IE8 supports CORS with the XDomainRequest function instead of the existing XMLHttpRequest.
UPDATE: This issue was reported on 7/13 resolved by facebook on 7/14 (amazingly fast and unexpected response time!)