by Flavio De Stefano

What I learned hacking the Facebook Messenger Soccer game

1*hPTxPQeHPxLnPBOg8ryWpQ
Summer soccer - Franck Michel - https://www.flickr.com/photos/franckmichel/6384558985

Recently, during last European Football Championship, Facebook introduced a little game in the Messenger app that makes you lose hours and hours despite its simplicity.

If you didn’t notice it, read this article on Mashable.

I have to admit… I totally suck at this game, so my best score was 9.

But, as a Developer, the best thing I could do was to beat my friends by hacking the game.

I really thought this would be simple.

The first way: Listen to HTTP(s) requests

While developing apps, you immediately realize that you need an HTTP debugger tool to analyze incoming /outgoing traffic for you APIs.

Charles is the best tool I’ve found to accomplish this task. It has a very intuitive interface and you can easily use it for debugging and reverse engineering purposes.

It was supposed to end at this point: I would have to analyze the API that the Facebook app used and just replay it with CURL while editing the data and the score sent to the server.

Of course, the API calls are in HTTPS, so they’re encrypted.. but Charles can be used as a man-in-the-middle HTTPS proxy, enabling you to view in plain text the communication between web browser and SSL web server.

1*rHRhqfl0hZSYHdEsrJLF_A
Charles acting as a proxy — with failed requests

Perfect! So I installed the root Charles certificate on the iPhone, and I tried to inspect the traffic. But all HTTP calls to the Facebook servers were denied upfront during the SSL handshake phase.

1*Mjd0P2T-huqFhck7Ii3alA
SSL - image courtesy of cisco.com

Doing some research, I discovered that some company apps like Facebook and Google use an extra layer of security to ensure that the certificate provided by the remote server is the one which is expected. This technique is called Certificate Pinning.

You can easily do this by including the public key of the remote server certificate within the application, so that it’s easy to validate the identity of the client for each HTTPS request.

This technique invalidates the Man in the Middle (MITM) Attack.

Great job Facebook! But…(remember, there’s always a but) there is a way to disable the SSL certificate pinning using some system tweaks only available on a jail broken device.

The first way (enhanced): Jailbreak a device and install iOS SSL Kill Switch

My iPhone is currently running iOS 9.x, so at the time of this writing it was impossible to jailbreak. So I took an old iPad mini running iOS 8.3.x and easily jailbroke it using the TaiG tool.

Searching on the web, I found SSL Kill Switch 2, a Blackbox tool to disable SSL certificate validation within iOS and OS X apps.

Once loaded into an iOS or OS X App, SSL Kill Switch 2 patches specific low-level SSL functions within the Secure Transport API in order to override, and disable the system’s default certificate validation as well as any kind of custom certificate validation (such as certificate pinning).

The SSL Kill Switch uses MobileSubstrate to patch system functions like the Secure Transport API. They are the lowest-level TLS implementation on iOS.

This means that disabling SSL certificate validation in the Secure Transport API should affect most (if not all) of the network APIs available within the iOS framework.

Please, do yourself a favor and follow this blog that covers all these concepts.

So, I connected to the iPad using SSH and installed the package:

wget https://github.com/nabla-c0d3/ssl-kill-switch2/releases/download/0.10/com.nablac0d3.SSLKillSwitch2_0.10.deb --no-check-certificatedpkg -i com.nablac0d3.SSLKillSwitch2_0.10.debkillall -HUP SpringBoard

Once rebooted, I expected to see the plain traffic, but it was an optimistic vision: I got the same errors.

I tried this way for another hour. I read somewhere that Facebook and Twitter use the SPDY protocol for their API calls, and this could be a problem for Charles. So I installed another tweak that (theoretically) disabled the SPDY protocol, but it didn’t work.

Starving.

Looking at the project issues, I noticed that someone else had the same problem (https://github.com/nabla-c0d3/ssl-kill-switch2/issues/13), with no resolution.

1*UlNOgv5rpOId_yvnggV3hQ

Pause.

The second way: Simulate touch events within the application

I realized that there are many game cheats that use a “human” approach: simulate touch events (one of the most popular games that many game cheats utilize this strategy on is Clash of Clans).

Browsing the web for a tool that automates these operations, I found this awesome tweak - AutoTouch. It can record human touch events and store the data in a LUA script. You can then edit this produced script and simulate whatever you want anywhere on your device.

Once installed with Cydia, I saved a BMP screenshot of the Messenger application with the ball visible and obtained the coordinates of where to click.

1*inmRf5q2zYXB4IAMZYvwrw
Screenshot made to obtain the coordinate

What I thought is that, by clicking exactly in the center of X axis of the ball, I only had to simulate repetitive touch events in the same coordinates and then stop the script when I had a score that I was satisfied with.

Here’s what I wrote to accomplish this goal:

adaptResolution(768, 1024);adaptOrientation(ORIENTATION_TYPE.PORTRAIT);
for i=1,2000 do
  touchDown(1, 544, 954);  usleep(66000);  touchUp(1, 544, 954);
  usleep(10000);
end

Nope, it didn’t work.

Probably, Facebook developers introduced a random error on touch coordinates to better simulate the game, or to prevent these type of scripts.

Or, maybe I just clicked at the wrong pixel.

So, for a second chance, I tried to simulate multiple clicks in a larger area, but without luck. Sometimes, I simulated so many touch events that the Springboard just crashed because of memory errors.

Instead of clicking in the same coordinates every time, I tried a better approach.

Reading the AutoTouch documentation, I found the following two methods:

  • findColor (color, count, region) - Search the coordinates of the pixel points matching the specified color on the current screen.
  • getColor (x, y) - Get the color value of the pixel point of the specified coordinate on the current screen.

The idea was to find a unique color inside the ball, and use the findColor method to get the coordinates of the ball in that moment, to simulate a touch event.

adaptResolution(768, 1024);adaptOrientation(ORIENTATION_TYPE.PORTRAIT);
local c = getColor(544, 954);
for i=1,2000 do  local r = findColor(c, 0, {400, 500, 768, 1024});
  for i, v in pairs(r) do    touchDown(1, v[1], v[2]);    usleep(66000);    touchUp(1, v[1], v[2]);    usleep(10000);  end
end

I don’t know why, but it simply didn’t work. Maybe the findColor is too slow to intercept the ball, which then makes the script useless.

The third way: Reverse engineer the app

I don’t have good native skills in Objective C, but I remember (when I played with the jailbreak ~4 years ago) that there was a tool by Saurik that could inject itself into iOS processes.

It is released along with Cydia and was called Cycript. It allowed developers to explore and modify running applications on iOS, by injecting code at run time.

I read some basic tutorials on how to use it, and after a few struggles, I decided to follow this (another) way.

Once you login via SSH into your iOS device, you can easily attach to a process just by typing:

cycript -p Messenger

I tried to inspect some basic UI classes like UIApp, but didn’t find anything interesting. Then I made a complete class dump, filtering it for the keyword soccer.

var C = Object.keys(ObjectiveC.classes);var soccer_classes = []; for (var i = 0; i < C.length; i++)  C[i].match(/soccer/i) && soccer_classes.push( C[i] );

It was a slow process.

I discovered that Facebook Messenger has a very large number of classes.

But, in the end, I got a small list.

1*xiOhf1t00RNyXa_o8m7Hnw
Output of the script

Once I obtained the class names, I used a script to print all methods of the class, and, by inspecting the MNSoccerGame class, the resulting methods were:

1*VnA--gnGj5wO3ZcF4C8EUQ
The methods dump of the MNSoccerGame class
Note: I still don’t understand what is the method wasCheatDetected.

Now that I had a complete list of the class methods, I decided to override the _setScore method, hoping that other methods didn’t notice that.

To do this, I used the MobileSubstrate and its MS.hookMessage method.

@import com.saurik.substrate.MS; 
var _setScore_pointer = {}; MS.hookMessage(MNSoccerGame, @selector(_setScore:), function(arg0) {  return _setScore_pointer->call(this, 9999); }, _setScore_pointer);

Now you can just play, lose, and anyway score a new record.

What I learned

Never stop yourself. Always try and discover new way to accomplish the same thing. I know, it’s just a game, but if you treat the problem you’re trying to solve like a challenge, you’ll get much more than the satisfaction of beating your friends.