Facebook recently introduced a whole new range of Instant Games that can be played in their Messenger app, whether on your mobile device or on your desktop.

Introduction

Naturally, the ubiquitous introduction of these mini-games have caused every one of my group chats on Messenger to become filled with friends savagely competing for the best scores. The more popular of these games include Endless Lake and Track and Field 100M. The purpose of Endless Lake is to avoid gaps in the path that your character takes by single and double tapping in order for your sprite to jump, whereas Track and Field 100M challenges you to make your track star finish the race as fast as possible by quickly tapping the screen in succession.

The problem

The problem is simple: how do we get to the top of the scoreboard without legitimately playing the game? In other words, how can we hack and exploit the way these games communicate with the Facebook servers that keep track and tally the scores of each player?

The other problem

There's a moral dilemma in hacking anything. On one hand, you're essentially saving yourself a butt-load of time and stress by simply gaming the system, platform, protocol, what-have-you, and finding alternative methods of achieving what many people believe to be success. On the other hand, you have officially become the asshole of the group chat for doing this because it's entirely not fair for the legitimate players who actually do try very hard to get on the leaderboard. I try my hardest not to be that asshole but sometimes having fun should not turn into a debate of morality. Try your best not to lose friends in the heat of the moment, and all should be fine. Onwards!

Networking

The first task is to find out exactly how the game conveys the end score to Facebook's servers. This is easily accomplished using Chrome's network developer tool. From here, we're able to observe, filter, and record any and all network activity, including requests, flowing to and from your browser. We clear all network activity before we start up one of our games and set it to record immediately before the final score is sent to their servers (either upon your character's death or the finish of the race, respectively). The results are as follows:

From this one recorded session, there were 109 requests made. Most of these were for images (.png, .jpeg) files which contained thumbnails of other games and Facebook friends. However, the name of the .xhr files starting with "?doc_id" and "graphqlbatch" are of interest, as these are the only plausible ways that the servers could be receiving some kind of data (.xhr is short for XMLHttpRequest, which is an API used by a variety of languages used to transfer and modify XML data using HTTP between client and server). Looking at the preview of the first .xhr file, we see something promising: payload data.

This payload holds all the information regarding a player, their current score, their leaderboard, their friend's leaderboards, etc. This is most likely the data that we're trying to manipulate before it's sent to the server for validation and insertion. Just to be sure, we take a look at the headers of this request.



We run the request URL through a generic URL decoder, and separate out the parameters given in order to get the following data:

doc_id=903271543141302  
variables={"data":{  
    "client_mutation_id":"0",
    "actor_id":"100000189902487",
    "game_id":"611307059053310",
    "score":11,
    "thread_id":"100000189902487",
    "story_id":null,
    "group_id":null,
    "send_admin":false,
    "session_id":"cf45dd18-0e1b-4bd8-b388-62913bdf75b3"
}}
dpr=1  

Now it's quite clear to see that this request is indeed sending information about the exact game, score, group chat, and other key pieces of data to their endpoint at https://www.messenger.com/webgraphql/mutation/. Of course, one might think to simply make a copy of this request and send it along, with just a slight modification to the variable score. But this requires too much work; we'd have to get the request headers and query string parameters just right, and we're not too entirely sure if the session_id acts as an access token such that each one is uniquely generated to prevent this type of malicious request/score modification. Right, so now we know how the game is communicating with the servers and that it may be using some kind of key to prevent bad or unauthorized requests. This means we need to work with the request that the game generates naturally. How, then, do we stop the original request, modify it, and send it along again?

More Networking

The answer to the previous question can be discovered with a simple Google search for "http modify request". One of these tools is called TamperChrome, and is an add-on/app for Chrome that lets users approve, modify, or decline requests as they are received. In other words, if the game had a phone and dialed Facebook to let them know the score a user received, TamperChrome acts as a redirected circuit on that phone lineā€”it takes the data that was supposed to go directly to the server, modifies it, and sends it along as if nothing ever happened to it. Facebook's servers gladly accept this score as legitimate because everything else about the request is intact, including whatever unique key may have been generated. Running TamperChrome, we modify our score from a pathetic 11 points to an impressive 4011 points and approve this request to be sent along to the server.

The changes are immediate: I've been catapulted to the top of the leaderboards:

Remember: with great power comes great responsibility. Please use this hack with that in mind.