Jump to content
malsploit

How I found a Remote Code Execution bug affecting Facebook's servers

Recommended Posts

XXE in OpenID: one bug to rule them all, or how I found a Remote Code Execution flaw affecting Facebook's servers

Hi, since I don't write much, let me first introduce myself. My name is Reginaldo Silva and I'm a brazilian computer engineer. These days I work mostly with information security, with a special interest in Web Application Security. I.E. if you let me, I'll find ways to hack into your site or application, hopefully before the bad guys do. You'll find a little more information about me going to my home page.

Today I want to share a tale about how I found a Remote Code Execution bug affecting Facebook. Like all good tales, the beginning was a long time ago (actually, just over a year, but I count using Internet Time, so bear with me). If you find this interesting and want to hire me to do a security focused review or penetration testing in your own (or your company's) code, don't hesitate to send me an email at reginaldo@ubercomp.com.

September 22nd, 2012 was a very special day for me, because it was the day I found a XML External Entity Expansion bug affecting the part of Drupal that handled OpenID. XXEs are very nice. They allow you to read any files on the filesystem, make arbitrary network connections, and just for the kicks you can also DoS the server with the billion laughs attack.

I was so naive at the time that I didn't even bother to check if anyone else was vulnerable. I reported it immediately. I wanted to start putting CVEs on my resume as soon as possible, and this would be the first (it eventually got CVE-2012-4554 assigned to it). Only five days later it occurred to me that OpenID was pretty heavily used and so maybe other places were vulnerable as well. I decided to check the StackOverflow login form. Indeed, it was vulnerable to the whole thing (file reading and all).

Then I decided to try to find OpenID handling code running inside Google's servers. I wasn't able to read files or open network connections, but both App Engine and Blogger were vulnerable to DoS. This is how I got my first bounty from Google, by the way. It was a US$ 500 bounty.

After reporting the bug to Google, I ran some more tests and eventually noticed that the bug I had in my hands was affecting a lot of implementations. I won't enumerate the libraries here, but let me just say that this single bug affected, in one way or another, libraries implemented in Java, C#, PHP, Ruby, Python, Perl, and then more... The only reason I'm not publishing the PoC here is that there are a lot of servers who are still vulnerable out there. Of course, the people who know about security will just read OpenID and XXE and then write an exploit in about 5 minutes, but I digress.

So after contacting (or trying to contact) every OpenID library author out there, I decided to write to the member-only security list hosted at the OpenID foundation an email titled "One bug to rule them all: many implementations of OpenID are vulnerable to XXE" to share my findings. I figured most library authors would be members of that list and so patches would be released for everyone very soon. I was right, but only partially.

The persistent readers who are still with me by now are thinking: what does a Facebook Remote Code Execution bug has to do with all this? Well, I knew Facebook allowed OpenID login in the past. However, when I first found the OpenID bug in 2012 I couldn't find any endpoint that would allow me to enter an arbitrary OpenID URL. From a Google search I knew that in the past you could do something like https://www.facebook.com/openid/consumer_helper.php?openid.mode=checkid_setup&user_claimed_id=YOUR_CLAIMED_ID_HERE&context=link&request_id=0&no_extensions=false&third_party_login=false, but now the consumer_helper.php endpoint is gone.

So for more than a year I thought Facebook was not vulnerable at all, until one day I was testing Facebook's Forgot your password? functionality and saw a request to https://www.facebook.com/openid/receiver.php.

That's when I began to suspect that Facebook was indeed vulnerable to that same XXE I had found out more than a year ago. I had to work a lot to confirm this suspicion, though. Long story short, when you forget your password, one of the ways you can prove to Facebook that you own an @gmail.com account is to log into your Gmail and authorize Facebook to get your basic information (such as email and name). The way this works is you're actually logging into Facebook using your Gmail account, and this login happens over OpenID. So far, so good, but this is where I got stuck. I knew that, for my bug to work, the OpenID Relying Party (RP - Facebook) has to make a Yadis discovery request to an OpenID Provider (OP) under the attacker's control. Let's say Ubercomp.

Then my malicious OP will send a response with the rogue XML that will then be parsed by the RP, and the XXE attack will work.

Since the initial OpenID request (a redirect from Facebook to Google) happens without my intervention, there was no place for me to actually enter an URL under my control that was my OpenID identifier and have Facebook send a Yadis Discover request to that URL. So I thought the bug would not be triggered at all, unless I could somehow get Google to send Facebook a malicious XML, which was very unlikely. Fortunately, I was wrong. After a more careful reading of the OpenID 2.0 Specification, I found this nice gem in session 11.2 - Verifying Discovered Information:

"If the Claimed Identifier was not previously discovered by the Relying Party (the "openid.identity" in the request was "http://specs.openid.net/auth/2.0/identifier_select" or a different Identifier, or if the OP is sending an unsolicited positive assertion), the Relying Party MUST perform discovery on the Claimed Identifier in the response to make sure that the OP is authorized to make assertions about the Claimed Identifier".

I checked and, indeed, the openid.identity in the request was Final: OpenID Authentication 2.0 - Final. This is a very common practice, actually. So indeed after a few minutes I was able to make a request to https://www.facebook.com/openid/receiver.php that caused Facebook to perform a Yadis discovery on a URL under my control, and the response to that request would contain malicious XML. I knew I had a XXE because when I told Facebook's server to open /dev/random, the response would never come and eventually a request killer would kick in after a few minutes. But I still couldn't read any file contents. I tried everything on the XXE back of tricks (including weird combinations involving parameter entities, but nothing. I then realized I had a subtle bug on my exploit that, fixed that, and then...

$ bash exploit.sh * About to connect() to www.facebook.com port 80 (#0) * Trying 31.13.75.1... connected * Connected to www.facebook.com (31.13.75.1) port 80 (#0) > GET /openid/receiver.php?provider_id=1010459756371 &context=account_recovery&protocol=http&request_id=1 &openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0 &openid.mode=id_res&openid.op_endpoint=...(redacted)... HTTP/1.1 > Host: www.facebook.com > Accept: */* > User-Agent: Chrome > < HTTP/1.1 200 OK < Cache-Control: private, no-cache, no-store, must-revalidate < Expires: Sat, 01 Jan 2000 00:00:00 GMT < P3P: CP="Facebook does not have a P3P policy. Learn why here: http://fb.me/p3p" < Pragma: no-cache < X-Content-Type-Options: nosniff < X-Frame-Options: DENY < X-XRDS-Location: http://www.facebook.com/openid/xrds.php < X-XSS-Protection: 0 < Set-Cookie: datr=...(redacted)...; expires=Thu, 19-Nov-2015 15:34:24 GMT; path=/; domain=.facebook.com; httponly < Set-Cookie: reg_ext_ref=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.facebook.com < Set-Cookie: reg_fb_gate=http%3A%2F%2Fwww.facebook.com%2Fopenid%2Freceiver.php %3Fprovider_id%3D1010459756371%26context%3Daccount_recovery%26protocol%3Dhttp %26request_id%3D1%26openid.ns%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth %252F2.0%26openid.mode%3Did_res%26openid.op_endpoint%3D...(redacted)...; path=/; domain=.facebook.com < Set-Cookie: reg_fb_ref=http%3A%2F%2Fwww.facebook.com%2Fopenid%2Freceiver.php %3Fprovider_id%3D1010459756371%26context%3Daccount_recovery%26protocol%3Dhttp %26request_id%3D1%26openid.ns%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth %252F2.0%26openid.mode%3Did_res%26openid.op_endpoint%3D...(redacted)...; path=/; domain=.facebook.com < Content-Type: text/html; charset=utf-8 < X-FB-Debug: ...(redacted)... < Date: Tue, 19 Nov 2013 15:34:24 GMT < Transfer-Encoding: chunked < Connection: keep-alive < <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script> function envFlush(a) { function b© { for (var d in a) c[d] = a[d]; } if (window.requireLazy) { window.requireLazy(['Env'], B); } else { Env = window.Env || {}; b(Env); } } envFlush({ "user": "0" }); <title>Facebook</title> <script src="http://static.ak.fbcdn.net/rsrc.php/v2/yR/r/Bx6hq_79BTx.js" crossorigin="anonymous"></script> <script type="text/javascript">window.Bootloader && Bootloader.done(["ASVup"]);</script> </head> <body class="Locale_en_US"> <script type="text/javascript"> Bootloader.setResourceMap({ "\/2NZV": { "type": "js", "crossOrigin": 1, "src": "http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yo\/r\/CAz6i9Uu16e.js" }, "GduTW": { "type": "js", "crossOrigin": 1, "src": "http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yu\/r\/aGXWJInaxrx.js" } }); </script> <script type="text/javascript"> require("InitialJSLoader").loadOnDOMContentReady(["GduTW","\/2NZV"]); </script> <script type="text/javascript"> Bootloader.configurePage([]); Bootloader.done([]); require("InitialJSLoader").handleServerJS({ "require": [ ["OnloadHooks"], ["lowerDomain"] ] }); onloadRegister_DEPRECATED(function () { openid_submit_response({ "__ar": 1, "error": 1428005, "errorSummary": "Error while processing response", "errorDescription": { "__html": " \ There was an error while processing the OpenID response. \ No matching endpoint found after discovering http:\/\/www.ubercomp.com\/...(redacted)... \ <br \/><br \/> OP Endpoint mismatch. Expected http:\/\/www.ubercomp.com\/...(redacted)..., \ got http:\/\/www.ubercomp.com\/...(REDACTED).../?x=\ root:x:0:0:root:\/root:\/bin\/bash\n \ bin:x:1:1:bin:\/bin:\/sbin\/nologin\n \ daemon:x:2:2:daemon:\/sbin:\/sbin\/nologin\n \ adm:x:3:4:adm:\/var\/adm:\/sbin\/nologin\n \ lp:x:4:7:lp:\/var\/spool\/lpd:\/sbin\/nologin\n \ sync:x:5:0:sync:\/sbin:\/bin\/sync\n \ shutdown:x:6:0:shutdown:\/sbin:\/sbin\/shutdown\n \ halt:x:7:0:halt:\/sbin:\/sbin\/halt\n \ mail:x:8:12:mail:\/var\/spool\/mail:\/sbin\/nologin\n \ uucp:x:10:14:uucp:\/var\/spool\/uucp:\/sbin\/nologin\n \ operator:x:11:0:operator:\/root:\/sbin\/nologin\n \ games:x:12:100:games:\/usr\/games:\/sbin\/nologin\n \ gopher:x:13:30:gopher:\/var\/gopher:\/sbin\/nologin\n \ ftp:x:14:50:FTP User:\/var\/ftp:\/sbin\/nologin\n \ nobody:x:99:99:Nobody:\/:\/sbin\/nologin\n \ dbus:x:81:81:System message bus:\/:\/sbin\/nologin\n \ ...(REDACTED)..." }, "payload": null, "bootloadable": {}, "ixData": [] }, 1) }); </script> </body> </html> * Connection #0 to host www.facebook.com left intact * Closing connection #0

That's right, the response contained Facebook's /etc/passwd. Now we were going somewhere. By then I knew I had found the keys to the kingdom. After all, having the ability to read (almost) any file and open arbitrary network connections through the point of view of the Facebook server, and which doesn't go through any kind of proxy was surely something Facebook wanted to avoid at any cost. But I wanted more. I wanted to escalate this to a full Remote Execution.

A lot of bug bounty programs around the web have a rule that I think is very sensible: whenever you find a bug, don't linger on messing around. Report the bug right away and the security team will consider the worst case scenario and pay accordingly. However, I didn't have much experience with the security team at Facebook and didn't know if they would consider my bug as a Remote Code Execution or not. I Since I didn't want to cause the wrong impressions, I decided I would report the bug right away, ask for permission to try to escalate it to a RCE and then work on it while it was being fixed.

I figured that would be ok because most bugs take a long time to be processed, and so I had plenty of time to try to escalate to an RCE while still keeping the nice imaginary white hat I have on my head. So after writing the bug report I decided to go out and have lunch, and the plan was to continue working when I came back.

However, I was wrong again. Since this was a very critical bug, when I got back home from lunch, a quick fix was already in place. Less than two hours after the initial report was sent. Needless to say, I was very impressed and disappointed at the same time, but since I knew just how I would escalate that attack to a Remote Code Execution bug, I decided to tell the security team what I'd do to escalate my access and trust them to be honest when they tested to see if the attack I had in my mind worked or not. I'm glad I did that. After a few back and forth emails, the security team confirmed that my attack was sound and that I had indeed found a RCE affecting their servers.

So this is how the first high impact bug I ever found was the entry point for an attack that probably got one of the highest payouts of any web security bug bounty program. Plus, and more importantly, I get to brag I broke into Facebook... Nice, huh? Oh, by the way, the Facebook security team wrote a post to tell their side of the story.

Join the discussion on Hacker News.

Timeline

All timestamps are in GMT. I omitted a few unimportant interactions about the acknowledgements page and such.

  • 2013-11-19 3:51 pm: Initial report
  • 2013-11-19 5:37 pm: Bug acknowledged by security team member Godot
  • 2013-11-19 5:46 pm: I replied by sending a PoC to read arbitrary files
  • 2013-11-19 7:31 pm: Security team member Emrakul informed me that a short term fix was already in place and would be live in approximately 30 minutes
  • 2013-11-19 8:27 pm: I replied confirming that the bug was patched.
  • 2013-11-21 8:03 pm: Payout set. The security team informed me it was their biggest bounty payout to date.
  • 2013-11-22 2:13 am: I sent an email asking whether the security team had already considered the bug as RCE or just as a file disclosure.
  • 2013-11-23 1:17 am: Security team replied that they did not considered the attack could be escalated to RCE.
  • 2013-11-23 7:54 pm: I sent an email explaining exactly how the attack could be escalated to an RCE (with file paths, example requests and all).
  • 2013-11-24 9:23 pm: Facebook replied that my attack worked and they'd have to work around it.
  • 2013-12-03 4:45 am: Facebook informed me that the longer term fix was in place and that they'd soon have a meeting to discuss a new bounty amount
  • 2013-12-03 7:14 pm: I thanked them and said I'd cross my fingers
  • 2013-12-13 1:04 pm: I found a Bloomberg article quoting Ryan McGeehan, who managed Facebook's incident response unit, saying that "If there's a million dollar bug, we will pay it out" and asked if there was any news.
  • 2013-12-30 4:45 am: Facebook informed me that, since the bug was now considered to be RCE, the payout would be higher. I won't disclose the amount, but if you have any comments about how much you think this should be worth, please share them. Unfortunately, I didn't get even close to the one-million dollar payout cited above. In case you're wondering, I quoted Mr. McGeehan mostly as a joke.

http://www.ubercomp.com/posts/2014-01-16_facebook_remote_code_execution

  • Upvote 1
Link to comment
Share on other sites

Facebook has paid out its largest Bug Bounty ever of $33,500 to a Brazilian security researcher for discovering and reporting a critical Remote code execution vulnerability, which potentially allows the full control of a server.

In September, 'Reginaldo Silva' found an XML External Entity Expansion vulnerability affecting the part of Drupal that handled OpenID, which allows attacker to read any files on the webserver.

As a feature, Facebook allows users to access their accounts using OpenID in which it receives an XML document from 3rd service and parse it to verify that it is indeed the correct provider or not i.e. Receives at https://www.facebook.com/openid/receiver.php

In November 2013, while testing Facebook's 'Forgot your password' functionality, he found that the OpenID process could be manipulated to execute any command on the Facebook server remotely and also allows to read arbitrary files on the webserver.

In a Proof-of-Concept, he demonstrated that how an attacker can read the content of 'etc/passwd' file from Facebook's server just by manipulating the OpenID request with malicious XML code, and in order to extract the essential login information such as system administrator data and user IDs.

"Since I didn't want to cause the wrong impressions, I decided I would report the bug right away, ask for permission to try to escalate it to a [remote code execution] and then work on it while it was being fixed," he said.

After receiving bug reports from Silva, the Facebook Security team immediately released a short term patch within 3.5 hours, described as:

"We use a tool called Takedown for this sort of task because it runs on a low level, before much of the request processing happens. It allows engineers to define rules to block, log and modify requests. Takedown helped us ensure this line of code ran before anything else for any requests hitting /openid/receiver.php."

The Facebook team determined that the vulnerability could have been escalated to a remote code execution issue, and rewarded Silva accordingly after patching the flaw.

Update: Facebook has accepted the flaw as Remote code execution (RCE).

In a post Facebook said, "We discussed the matter further, and due to a valid scenario he theorized involving an administrative feature we are scheduled to deprecate soon, we decided to re-classify the issue as a potential RCE bug".

Source: Facebook Hacker received $33,500 reward for Remote code execution vulnerability - The Hacker News

Pe acelasi subiect mai este si asta.Pare scris mai bine: http://www.securityweek.com/facebook-pays-33500-security-researcher-uncovering-bug

Edited by aelius
Link to comment
Share on other sites

Sa ai acces la datele unei firme care valoreaza in jur de 100 de miliarde de dolari?

Depinde cat si unde ai avea acces. Daca ai face un dump la tabelul facebook_users, valoarea sa ar trece usor de 10 milioane de $. Daca l-ai vinde Chinei sau Rusiei probabil ti-ai lua o insula exotica si cateva mii de virgine.

Bine, nu doar utilizatorii, mai sunt si mesaje private, poze/videoclipuri private si multe alte lucruri utile: liste de prieteni, event-uri, locatii vizitate, adrese IP si cine mai stie ce date o pastra Facebook.

Edited by Nytro
Link to comment
Share on other sites

De curând, un programator brazilian, Reginaldo Silva, a g?sit o vulnerabilitate critic? în Facebook, care permite citirea ?i executarea fi?ierelor de pe serverele renumitei re?ele de socializare. Mai mult decât atât — vulnerabilitatea permite executarea fi?ierelor de pe alte servere (aka Remote Code Execution).

Dac? dori?i s? afla?i mai multe detalii despre vulnerabilitate, vede?i articolul de pe site-ul autorului ?i pagina oficial? Facebook Bug Bounty.

Dup? spusele celor de la Facebook, aceast? vulnerabilitate a fost r?spl?tit? cu o sum? record. Îns?, chiar dac? nu s-a divulgat suma exact?, se pare c? Reginaldo Silva a primit $33500, ceea ce (dup? p?rerea mea) este o sum? jalnic? pentru aceast? vulnerabilitate — practic, omul execut? orice ?i cite?te orice (vede?i /etc/passwd în articolul autorului), iar Facebook îi ofer? $33k. Mdaa...

Sincer, cum naiba s-au gândit ??tia s? ofere $33k pentru un Remote Code Execution, când pentru un XSS s-a oferit ?i $10k?

ps. Dac? tot au oferit a?a sum?, m?car puneau 31337 ?i tot mai dr?gu? ar fi fost.

Link to comment
Share on other sites

Chiar si cercetatorul sustine ca nu a avut suficient timp sa testeze cu adevarat problema. E adevarat ca vulnerabilitatea afecta (aparent) fix main domeniul dar asta nu inseamna neaparat ca acolo putea face ceva cu adevarat. Daca mai inainta putin in testare sau scotea niste informatii mai relevante (nu /etc/passwd) am fi putut intelege si motivul acestei sume foarte mici. Mai trebuie tinut cont si de faptul ca exista si niste limite (superioare) ale Bug Bounty-urilor care la fel, nu pot fi depasite oricand. :-)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...