Earlier this week, I reported finding a cross-site scripting vulnerability on a facebook.com page. Last night, I asked a friend with contacts at Facebook to let their developers know directly, and the company responded quickly. I confirmed just after midnight that the hole is now patched, which means I will now share technical details.
The problem was a fairly typical XSS issue. In poking around various pages related to application permissions, I noticed that several URI parameters appeared in the source of the page, but Facebook did a good job of filtering out characters which could allow cross-site scripting. Further experimentation revealed that specifying various parameters on one page led to various error messages.
This specific page was www.facebook.com/connect/prompt_permissions.php
, a pop-up that can appear when an application requests extended permissions, such as read access to a user’s stream. A typical use of this page came by issuing a GET request with several parameters: api_key
(the API key of the requesting application), v=1.0
, extern=1
, next
(the next URI to load), channel_url
(the cross-domain receiver file for communicating with Facebook), dialog_id
, locale
(language), and ext_perm
(the specific extended permission requested).
For instance, if an application with API key d41d8cd98f00b204e9800998ecf8427e
wanted to access a user’s stream, it may issue a GET request to this URI:
http://www.facebook.com/connect/prompt_permissions.php?↵
api_key=d41d8cd98f00b204e9800998ecf8427e&v=1.0&extern=1↵
&next=http://uri/&channel_url=http://uri/xd.php&↵
dialog_id=0_0.37541312664788107&↵
ext_perm=read_stream&locale=en_US
Note that the extended permission parameter is simply the text read_stream
. When I tried setting it to a number, say ext_perm=1
, I received a page with this error message:
The application cannot ask you for permission 1
Sure enough, this error message was not filtered. I could then easily craft an XSS link. The trick only had two requirements: the user had to be logged into Facebook, and the API key had to match an application that the user had authorized. Since finding the API key of any third-party application is fairly trivial, one could easily target widely installed applications in an actual attack.
To demonstrate the possibilities of an XSS link, I set ext_perm=%3Cscript%3Ealert(document.getElementById(↵
%22post_form_id%22).value);%3C/script%3E
and saw this output:
Illustration of XSS vulnerability on facebook.com
Those experienced with Facebook code will recognize what can be accomplished with post_form_id
. Facebook uses this code to sign AJAX requests for all sorts of operations when someone uses pages on facebook.com, hence the list of activities I gave in my last post.
Of course, to perform such activities, an attacker would need the user’s Facebook ID, which does not occur in the source code of prompt_permissions.php
. But since we’re injecting code into a facebook.com page, browser security no longer prevents script access to iframes or XHR objects that reference other facebook.com pages, since none of them happen cross-domain. In fact, by setting ext_perm=%3Ciframe+src%3D%22http%3A%2F2Fwww.facebook.com↵
%2Fprofile.php%22+id%3D%22x%22+onload%3D%22alert(↵
frames%5B'x'%5D.document.getElementById('profile_pic').src)↵
%3B%22%3E%3C%2Fiframe%3E
, one would see their profile image URI, which contains their Facebook ID.
Anyone familiar with JavaScript DOM manipulation can already see how much would be possible with such an XSS vulnerability. A malicious link could provide a hacker with nearly every bit of information or capability that a user can access when logged into Facebook. An attacker could also craft a sophisticated phishing scheme, since the page would be coming from facebook.com.
Facebook did act swiftly to correct this problem, as they’ve done with previous cases, and I commend them for their response. However, I would once again note that many Facebook applications, including widely used ones, have this same type of vulnerability. An application cannot be exploited to the same degree as a facebook.com page, but it does allow a hacker to access profile information, send notifications, and publish stories on a user’s wall. Facebook’s recently announced privacy changes should eventually help limit profile access via hijacked applications, but many security issues still remain.