Reverse engineering games for fun and SSRF - part 1

18th Jan 2019

During this holiday I had some time to try a new game; while I was playing it I asked myself if I could do some digging and found any vulnerability. This is the journey that took me from reverse engineering the game until I found an interesting SSRF.

Foreword

The company that developed the game is not currently running any bug bounty program and asked me to keep this issue private. So, in order to avoid breaking any trust, I'll name the game ACME and I'll try to keep the details as generic as possible, without changing the final sense.

General reconnaissance

Also known as "playing the game as a normal person would do".
ACME is a turn-based game, where you take some actions and the other player will reply to you. Aside the actual match, inside the game you can tune your player and your inventory (skins, avatar etc etc) as well as perform some purchases from the in-game market.
Final note, this is a "proper" game that you actually install on your computer, not a web-based one.

After spending some time playing, I finally decided to remove my gaming hat and inspect the inner logic.

Under the hood

ACME game is developed with Unity 3D, a famous gaming engine. This is actually a good thing, since there are plenty of resources online that would help you in reversing engineering the original game.
For example, the whole main logic is always stored inside a DLL file with a fixed name Assembly-CSharp.dll; you simply have to take a free decompiler such as JetBrains dotPeek and... BAM! Everything is there:

Another nice thing about the Unity3D engine is the lack of obfuscation or encryption: everything is in plain sight. Obviusly you'll be missing all the code comments, but at least you won't have to deal with absurd name classes. Funny story: I found a class named DuctTape :D

After poking around for some time, I realized that the there are a lot debug messages, in the format

Debug.LogFormat("Timer {0} start {1}", (object) key, (object) DateTime.Now.ToString("HH:mm:ss.fff"));

So the developers are producing a very detailed log of what's going on, maybe is it enabled by default?
A quick search for "unity3d log file" revealed that the default output location is C:\Users\username\AppData\LocalLow\CompanyName\ProductName\output_log.txt

Ah! We're lucky once again!
With all these info, we're ready to actually start capturing traffic and fiddle around with params.

Booting Burp

In my setup, I have a Linux computer for work and connect to the Windows box using Remote Desktop when I want to play games. This means that I simply have to change Windows settings to configure a proxy pointing to Burp running under Linux.
After doing that I ran the ACME game and...

Nothing. Zero. Zilch. Nada.
What the ...?

That's not entirely new to me, I already encountered applications that are bypassing system configuration and directly connect to the remote endpoint. In that case we have to setup an invisible proxy; it's not something impossible, but it requires some more work.

Gathering more info

The basic idea of the invisible proxy is to change our hosts file and force the target system to resolve the domain to our proxy listener. But first of all we have to identify such remote domain!
Time to start digging around once again. A quick search on the disassembled code revelaed nothing, but the output_log.txt was way more juicy.
Searching for http or https returned no results, but then I decided to look for the WebSocket procol and I found this:

Connecting to : wss://acme-game.com:1234

WebSockets, you'll be the death of me...

So, in order to actually capture traffic, we have to add an entry in the hosts file and assign my Linux box IP to the acme-game.com domain. Moreover, I have set Burp to listen on the same port 1234, finally Burp must be instructed to redirect any request to the original destination/port pair. Finally, remember to tick the option Support invisible proxy.

As usual, since the connection is encrypted, you have to download and install Burp certificate in the Windows box, otherwise the connection will be dropped.

Booting Burp - take two

With all those settings, I started Burp again and... finally requests are flowing.

As suspected, the game is using WebSockets to communicate: after the initial HTTP request, the connection is upgraded to a WebSocket channel.

Conclusions (for now)

In this first part I described the actions required to successfully proxy an application that doesn't support it by default (a.k.a. Thick client). In the next and final section we will enter in the details of the actual vulnerability: how to reverse engineer custom protocols, identify a vulnerable point and edit WebSocket connections.
I hope you enjoy reading raw binaries because you'll see a lot of them.

Comments:

Blog Comments powered by Disqus.