Recently, a new little icon appeared in the text box on Messenger next to the camera icon and payments:
If you click it, a menu shows up and you can play a number of in-browser games. It seems that the games are run without any plugins, so they use HTML5 to run and interact with Facebook’s API, such as setting scores on the leaderboard and whatnot.
In this post, I’ll look at the game TRACK & FIELD 100M. The object of this game is to press the left-foot button and the right-foot button as quickly as possible. Since your final score is the elapsed time, lower scores will outrank higher scores. I will explain how to achieve a score of 0:00.01.
Step 1: Finding the Source Files
It turns out that when Messenger loads the source files for the game (which are *.js files) when you first open the game. This makes it easy to figure out which source files are responsible for the actual game logic. In this tutorial, I’ll be using Chrome, but I’ve confirmed that it works on Microsoft Edge as well.
First, open Developer Tools using Ctrl+Shift+I or F12, and go to the Network tab. There might be a few resources loaded already; delete them with the 🛇 button. Since we are looking for JavaScript files, open the filter view and select JS.
Now, when Facebook loads the JavaScript source files, they will appear in this view. Open the game menu and press the Play button next to the game TRACK & FIELD 100M. Once you have done this, a few files will start to appear.
main.js looks like a pretty good place to
start. Look at the URL: https://apps-1665884840370147.apps.fbsbx.com/instant-bundle/1230433990363006/1064870650278605/main.js
.
Since this resource has already been loaded into the browser, we can find it under the Sources tab of
Developer Tools. Trace the path, starting from the domain like this:
Step 2: Analyzing main.js
Go ahead an pretty-print the minified file, just like it suggests. (for those of you who didn’t get that notification, just hit the {} button next to Line/Column. Since this file isn’t obfuscated, it’s fairly easy to just look through the file and figure out what it does.
I don’t really know how to explain this part well; if you’re familiar with code, you should be able to traverse the file pretty easily. I eventually arrived at this function:
GameScene.prototype.stepEnd_ = function() {
if (this.isStepTimeOver_(2e3)) {
var e = Math.floor(1e3 * this.timeSpeed_.getTime());
FBInstant.setScore(e),
FBInstant.takeScreenshot(),
this.stepFunc_ = this.stepEnd2_,
this.audience_.fadeTo(.5)
}
}
stepEnd_
is the handler for the event where the user finishes
the game. As you can see, it computes the elapsed the time, and multiplies it by 1,000 (probably because
Facebook stores these scores as integers). This is sent to Facebook using the FBInstant
library’s setScore
function. After looking at a couple of these games,
you’ll notice that FBInstant
is pretty much universal
among these games, since it’s required to interact with the Facebook API.
Step 3: The Exploit
The strategy to exploit this is to add a breakpoint at that line, so code execution is paused before that line is executed. Then we are free to change the variable to whatever we’d like to change it to, and then resume execution so that our changed value is sent to the server.
I’d like to point out that setting the variable to non-numerical types will simply cause the upload to fail. I’m guessing they’re doing some type-checking on it server-side. That doesn’t prevent us from simply changing the value to 0 and sending it to the server.
To add a breakpoint to that line, click the line
number where the line FBInstant.setScore(e)
appears. The
blue arrow indicates that a breakpoint has been set, and code execution will stop before this line starts.
Now, start the game and play through it
like normal. It doesn’t matter what score you get, as long as you finish and trigger the stepEnd_
function, the code will stop and wait for you before
submitting your score.
If you are still on the Sources tab, you’ll be able to see the variables in the scope of the deepest function we are in when the code stops.
Open the Console (either by navigating to the Console tab, or just pressing Esc to open it within the Sources tab), and just type
e = 1
We just changed the value of the local
variable e
to 1 (1 millisecond; for some reason it bugs
when I use e = 0
). When the execution continues, it will
use our changed value, and submit that to the score server. Exit the game, and you should see that score
reflected on the leaderboard.
Recap
When you are developing browser-based games, you can never trust user input. As long as the user has control, he can jack the browser logic and change variables during runtime. Ideally, the game logic should be done server-side, and the client is simply a terminal passing inputs to the server and visuals back to the client.
However, this is highly impractical. If you sent a request for every input and waited for the server to respond, you’d get a huge delay, even for very fast connections. This is one of the hardest problems to tackle in real-time RPGs: how can we verify that the user is moving as they should, while still running the game as fast as we can?
That’s all I have today. Thanks for reading!