TLDR:
In this post we'll do some static analysis on the game binary and also look at some dynamic approach to learning more about the game itself. Finally, we'll also look at some network requests to get a hint on how things are working behind the scenes.


Video

Watch on YouTube-

Introduction

Before jumping into an exploitation phase, we must have an understanding of the game on a fundamental level. So in this post, we'll do some Information Gathering or Reconnaissance.

Static Analysis

First off, let's check out the official page to see if we can find anything interesting and this could be a good starting point.

Our hackable components all live in their own sandbox, too (the net code and game logic are completely custom), so you won't have to hack the engine (Unreal 4) itself!

The above line does give us something important. We don't have to find and exploit any vulnerabilities within the game engine itself, but instead, all we have to do is to look for bugs in the game logic since most of the components are custom.

Going down a bit, we see that there are three different versions of the game based on the operation systems(Windows, OS X, Linux). This means the code had to be compiled for each one of those operating systems differently. But also probably not every file is different. So it would be interesting to look at the differences and similarities. To do that I wrote a simple python script that simply walks the directory tree to get all the files, and then creates hashes to identify the unique and identical files.

As you can see, there are a lot of identical files, some are DLLs, and some are config files. Nothing sounds too exciting here. Now maybe you're wondering why DLL files are present in the Linux and Mac game clients? It's because this game is based on mono, a Cross-platform, open-source .NET framework. This lets us write Windows .NET applications and compile them to run on Mac and Linux. Finally, the unique files are also not that interesting; you can see different binaries for the different systems. So .dylib is a dynamic library for mac, while on Linux it's an .so file(a shared object).

The actual game files are downloaded during the update process, so after gathering all the updated files, let's run the script again. Each of these fully updated clients are around 2GB, so this will take a while since hashing large files takes a couple of seconds.

The results showed a lot of .ini files and also a bunch of .pak Files. One file GameLogic.dll seems interesting.

$ find . | grep -i logic
./mac_updated/pwn.app/Contents/PwnAdventure3/PwnAdventure3.app/Contents/MacOS/GameLogic.dylib
./linux_updated/PwnAdventure3_Data/PwnAdventure3/PwnAdventure3/Binaries/Linux/libGameLogic.so
./windows_updated/PwnAdventure3_Data/PwnAdventure3/PwnAdventure3/Binaries/Win32/GameLogic.dll
./windows_updated/PwnAdventure3_Data/PwnAdventure3/PwnAdventure3/Binaries/Win32/GameLogic.pdb (ignore)

As you can see, there are three different for three different operating systems, seems like it's worth checking them out, but this time, with a dynamic approach.

Dynamic Approach

Like I said in the first video, I will mostly do this on Linux, so let’s start with that and execute the Launcher. Since the Launcher is not the real game, so let’s just click on play and wait for the actual game to start.

$ pstree -aclp

If we look at the process tree, we see a bunch of children threads.

2

Each thread has a meaningful name, which is helpful. The process ID is 30900, let's check that out in the regular process list.

$ ps aux | grep 30900
... /home/live/clients/linux_updated/PwnAdventure3_Data/PwnAdventure3/PwnAdventure3/
Binaries/Linux/PwnAdventure3-Linux-Shipping

So this binary that was executed lies in the /home/live/clients/linux_updated/PwnAdventure3_Data/PwnAdventure3/PwnAdventure3/Binaries/Linux/PwnAdventure3-Linux-Shipping directory.

Let’s exit the game and see what happens when we call it directly.

We see some debug or log output, and the game is actually starting! So there's a way to start the game without the launcher.

Next, let's look at the /proc file system. So we go to /proc and the process ID of our currently executed game, and with ls we can view the available folders and files. Let's look at the memory map.

$ cd /proc/31041
$ cat maps
...
[libstdc++]
...
[libGameLogic.so]
[libdl]
[libpthread]
...
...
[stack]
...

As we can see from the above-simplified representation, there are memory maps to some interesting files like libGameLogic.so. If we try to search for mono we don't find any references to it, so basically only the launcher is written in .NET using the mono framework and not the game itself.

Analyse the Binary

Let's start with the file command.

$ file /path/to/PwnAdventure3-Linux-Shipping
PwnAdventure3-Linux-Shipping: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), 
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.27, 
stripped

From above

  • Binary here is a 64bit executable.
  • Dynamically linked
  • Stripped (no debug info)

With ldd we can see which dynamic libraries it requires.

lld /path/to/PwnAdventure3-Linux-Shipping

The output of the above command shows all the dynamical libraries and interestingly libGameLogic.so is one of them.

$ file /path/to/libGameLogic.so
libGameLogic.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), 
dynamically linked, not stripped

As we can see, the libGameLogic.so is a shared object, which is also dynamically linked, but this is not stripped, which means we can get a lot of debug information. Before we move on, let's check out the fd folder, which contains a list of all the opened file descriptors and to which file they point.

live@live:/proc/31041$ ls -l fd

In the output, 0, 1 and 2 are stdin, stdout and stderr respectively, but all the others are other files. Most of the files here are .pak resource files.

Now when I tried to play the game, I got an error "Connection Error, Failed to load master server certificate". I confirmed that it works when the game is started using a launched but doesn't work when we directly start it. I looked into the environment variables and checked if there were any command-line arguments passed to the binary, but nothing special. I simply went into the folder where the binary was present and executed it from there, and it worked like a charm.

Network Analysis

After dropping into the game, we'll look at the network connections made by the game.

$ netstat -a -c | grep -i pwn

We start to see connections made to master.pwn3 on port 3333 and 3002, here 3333 is the master server specified in the server ini file and 3002 is the actual game server. Since both the master.pwn3 and game.pwn3 are mapped to the same IP in the /etc/hosts file; we only see master.pwn3.

Now let's exit the game and open Wireshark. Let's try to monitor any interface and filter for all tcp packets to port 3333 and also apply the filter for only the packets that contain a payload.

# Filter for 3333 with payload
tcp.port==3333 && tcp.len>0

If we relaunch the game and drop in as some character, we start to see some traffic in Wireshark.

As we can see, the content of the packets looks like binary. However, there are a few ASCII strings in there, for example, "Ghost in the shellcode" which can be seen in some packets. "Ghost in the shellcode" is also the name of the CTF this challenge was part of.

Now let's switch to port 3002 which is supposed to be the game server.

# Filter for 3002 game server with payload
tcp.port==3002 && tcp.len>0

Here there's a lot more action, the game constantly sends updates to the server and receives some of them too. Of course, it's an MMO so its kind of expected.

At the start, Wireshark tells us that there are some weird packets. Here Wireshark tries to guess and decode certain protocol types, but it looks like it might be something custom. So in order to not get a wrong decoded protocol, I enabled only ethernet, ipv4, and TCP.

Here's the first time the game client sent something to the server that might be worth looking at.

5

That looks like ASCII, so that doesn't look encrypted at all. Moving around inside the game doesn't immediately show a change in the Wireshark dump; however, jumping triggers a slightly larger packet. And actually, it seems to trigger two, one for initiating the jump, and one for getting back onto the ground, kinda like key down and key up events.

I think we already learned a lot about the game today. But I just wanted to show you that it's important to do some investigation and slowly learn more about the game so that this helps in the exploitation phase. And also making notes is also important. While performing this recon, I was writing down what I did and what I found, because this way, I don't forget a week later what I already discovered. That's all for this post, in the next one we will open the disassembler.

Resources