Level 1 - Slay The Dragon
Last updated
Last updated
The recently launched online RPG game "Slay The Dragon" has been hot topic in the online gaming community of late, due to a seemingly impossible final boss. Amongst the multiple tirades against the forementioned boss, much controversy has been brewing due to rumors of the game being a recruitment campaign for PALINDROME, the cybercriminal organisation responsible for recent cyberattacks on Singapore's critical infrastructure.
You are tasked to find a way to beat (hack) the game and provide us with the flag (a string in the format TISC{xxx}) that would be displayed after beating the final boss. Your success is critical to ensure the safety of Singapore's cyberspace, as it would allow us to send more undercover operatives to infiltrate PALINDROME.
To aid in your efforts, we have managed to obtain the source code of the game for you. We look forward to your success!
You will be provided with the following:
Source code for game client/server (Python 3.10.x)
Game client executable (Compiled with PyInstaller)
Highly recommended that you run it in a modern terminal (not cmd.exe) for the optimal experience:
Windows: Windows Terminal or ConEmu recommended.
Linux: the default terminal should be fine.
Note: If you'd like to make any modifications to the client, we'd strongly suggest modifying the source code and running it directly. The game client executable has been provided purely for your convenience in checking out the game.
Host: chal00bq3ouweqtzva9xcobep6spl5m75fucey.ctf.sg
Port: 18261
This challenge revolved around a game client and server, and the exploit relied upon the insecure use of client-side validation over server-side validation.
Sidenote - nice ASCII art!
The game provides a way to earn gold through mining, which can be spent on swords (which boost our attacks) and potions (which heal our character). This seemed like a great place to start, since having an unlimited amount of potions to heal our character would probably help us to beat the game.
This turned out to be useless - the last boss had a one-hit-kill attack, and we could not buy more than one sword. If we could buy unlimited swords, this exploit would have allowed us to beat the boss by using a one-hit-kill attack of our own.
Nonetheless, this is an interesting vulnerability to discuss!
First of all, there was a chance of "dying to a creeper" when mining for gold. However, this was implemented entirely on the client-side and can be commented out.
Further, there was an arbitrary slowdown implemented by the display_working_screen
function, which sleep
s for a period of time. This is meant to prevent doing exactly what we hope to do - spamming the mining functionality to gain unlimited gold.
Once again, this is entirely client-side and we could comment out the call to this function entirely.
After finding out that the previous exploit was useless unless we could have unlimited swords, I tried looking for ways to end the battle in one turn (since the last boss always kills us on the first turn). This required us to look deeper into how the game server processes commands.
First of all, we need to understand how the client-server traffic is actually encoded. Thankfully, this is pretty simple - all traffic is base64-encoded and each command is delimited by the EOF_MARKER
.
The EOF_MARKER
is defined in config.py
, and is simply the pound sign.
When receiving a command from the client through recv_command_str()
, the server processes the command and stores it in self.history.commands
.
The server then checks the latest command - if the latest command is ATTACK
or HEAL
, then the boss gets to attack and this attack is stored in self.history.commands
. If it is VALIDATE
, then it will process all commands stored in self.history.commands
and compute the battle result.
But if we take a look at log_commands_from_str
, it becomes apparent that the server could receive more than one command at a time.
We could therefore send any number of commands before a final VALIDATE
command, and all the commands will be processed without allowing the boss to attack.
The actual attack is simple - just base64-encode an ATTACK ATTACK ATTACK ... ATTACK VALIDATE
string and send it to the server.
The flag is TISC{L3T5_M33T_4G41N_1N_500_Y34R5_96eef57b46a6db572c08eef5f1924bc3}
.