How Access Control issue in the Facebook game turned me from the dev to the security researcher

Hello. Since it is my first blog post, I’ll start my stories from the beginning – from the first bug, which made me seriously think about infosec career.

It was the May 2016, and I played with friends in the online game, located on the

https://apps.facebook.com/xxxxxxx

(I can’t disclose game title, but I will try to highlight as much info as possible) on Facebook that time. It was the usual strategy, with economics, clan system, tower defense/attack modes, PvP, PvE, etc. And, for sure, a premium store system, where players could buy premium cash, boosters, items, and other stuff. All payments were made through the Facebook payment gateway.

Because I had a lot of free time, I started to research, how the game works (authentication, request/response format, etc). Using Chrome’s Web Debugger, I discovered, that application uses XML format (nope, XXE didn’t work) for data exchange. At the authentication phase it used Facebook profile ID in combination with unique authentication_key to obtain the session_key:

<authenticate fb_id="[facebook id]" authenticity_key="[32-symbol static md5 signature, unique for the each Facebook user]">

And the response was:

<response>
<session>[32-symbol md5 session signature]</session>
</response>

All next requests simply used this session value.
Most of the game actions used next schema:

<command fb_id="[facebook id]" authenticity_key="[key signature]" session="[session signature]">
<action>[some ingame action]</action>
</command>

On this stage, I was able to automate some simple boring resource crafting actions (if you are familiar with social games, you know what I mean), using custom written PHP script – so no more need to be online, script will do crafting job 24/7, using cron (authentication->making actions->finish).
Next, I started thinking, how the game client knows, which action it needs to send to the server? Obviously, there was some database with request schemas on the client. Because debugger didn’t find anything, I decided to reverse the game client to figure out how things work. It was a flash application, so reversing to the Action Script didn’t take much time.
I was familiar with Action Script and Flash apps in the past, so quickly found what I looked for. Upon the game initialization, there was a request to the ZLib-compressed file on the game server, which was then decompressed, and used to issue the requests.
So, I downloaded that file and decompressed it using 7-Zip File Manager, which support ZLib. The file was 1Mb compressed and became around 102Mb decompressed. After looking inside I was surprised – it contained schemas for all possible actions and requests, in XML format. Some of this commands were never issued by the game client, so couldn’t be discovered in another way. Manual inspection could take weeks, due to the big amount of the information inside, so I went short way – I created the C# script, which extracted all possible strings from the file, formed the new file from them (with each string from newline) and implemented the loop, to issue requests to the game server with each string (there was around 100k of total). Here is a piece of C# code:

StreamReader rs = new StreamReader("scripts.txt"); //file with extracted strings
StreamWriter ws = new StreamWriter("out.txt"); //output file
fbid = "[myid]";
key = "[mykey]";
while (!rs.EndOfStream) {
requests = rs.ReadLine;
authorize(); //auth function, returns and defines session as global var
postdata = "<command uid=\"" + fb_id + "\" authenticity_key=\"" +
key + "\" session=\"" +session + "\"><action>" + requests + "</action></command>";
responsepc = network(postdata, "https://[game host]/", "[api path]");
if (!responsepc.Contains("error")) {
ws.WriteLine(postdata);
ws.WriteLine(responsepc);
}
}
ws.Close();
rs.Close();


public string network(string postdata, string host, string mode)
{
HttpWebRequest request;
HttpWebResponse response;
Stream requestStream;
byte[] postBytes = null;
System.IO.StreamReader responseReader;
System.IO.Stream responseStream;
string responseText = "";
try {
request = (HttpWebRequest)WebRequest.Create(host + mode);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postdata.Length;
request.Accept = "*/*";a
request.ServicePoint.Expect100Continue = false;
request.Method = "POST";
request.AllowAutoRedirect = false;
requestStream = request.GetRequestStream();
postBytes = System.Text.Encoding.ASCII.GetBytes(postdata);
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
response = (HttpWebResponse)request.GetResponse();
responseStream = response.GetResponseStream();
responseReader = new IO.StreamReader(responseStream);
responseText = responseReader.ReadToEnd();
} catch (Exception ex) {}
return responseText;
}

I launched the tool and went to sleep. The next morning I had the huge backlog of successful responses.


After 15 minutes of reading, I was surprised – one response showed, that some command bypassed the game payments system, and credited me the big amount of premium game cash. I repeated this command – and got another portion of cash. Every single command produced game cash, equivalent to the $200 real money – and I could use it without limits! Sounds like the backdoor. Possibly, this command was used by devs on the development stage, and they forgot to remove it after making the payment system. This bug couldn’t be discovered without reversing – because this command was never used by the app.

Well, it was something. The game was popular enough, had more than 100 000 players, and the potential attacker could impact company economic on tens of thousands of dollars by selling the premium cash cheaper… Realize this – if even 5000 of the 100 000 players decide to buy the game cash cheaper (let’s say, for 100$) from the hacker – it’s 500 000$ profit. For sure, such activity had all chances to be spotted and prevented, but still.
After this, I permitted similar technique against other games of this company – and successfully broke 3 more games! Bump.

I reported this bug to the company, and they issued a reward… which was a lot lower from the theoretical profit of attacker:) But I was not a blackhat, and accepted the reward with gratitude. That’s how I first discovered bug bounties.
In the next months, I discovered similar findings in other Flash-based social games – and I must say, that data encryption and format does not matter. Reversing the Flash application will allow the attacker to understand the data format, and how encryption works – and then permit fuzzing against the game server. It can be hardened/mitigated in several ways…But it is a different story.

After this finding, I believed that I can be of use for the security field, and discovered such platforms as HackerOne and BugCrowd. I registered on both but started working on the HackerOne only in the November 2016, after months of learning and practice (since I was a dev before, the learning was not very hard).

 

Sp1d3R