Day 19 Walkthrough
Day 19: I merely noticed that you’re improperly stored, my dear secret!#
Learning Objectives
- Understand how to interact with an executable’s API.
- Intercept and modify internal APIs using Frida.
- Hack a game with the help of Frida.
Game Hacking#
Even while penetration testing is becoming increasingly popular, game hacking only makes up a small portion of the larger cyber security field. With its 2023 revenue reaching approximately $183.9 billion, the game industry can easily attract attackers. They can do various malicious activities, such as providing illegitimate ways to activate a game, providing bots to automate game actions, or misusing the game logic to simplify it. Therefore, hacking a game can be pretty complex since it requires different skills, including memory management, reverse engineering, and networking knowledge if the game runs online.
Executables and Libraries#
The executable file of an application is generally understood as a standalone binary file containing the compiled code we want to run. While some applications contain all the code they need to run in their executables, many applications usually rely on external code in library files with the “so” extension.
Library files are collections of functions that many applications can reuse. Unlike applications, they can’t be directly executed as they serve no purpose by themselves. For a library function to be run, an executable will need to call it. The main idea behind libraries is to pack commonly used functions so developers don’t need to reimplement them for every new application they develop.
Hacking with Frida#
Frida is a powerful instrumentation tool that allows us to analyse, modify, and interact with running applications. How does it do that? Frida creates a thread in the target process; that thread will execute some bootstrap code that allows the interaction. This interaction, known as the agent, permits the injection of JavaScript code, controlling the application’s behaviour in real-time. One of the most crucial functionalities of Frida is the Interceptor. This functionality lets us alter internal functions’ input or output or observe their behaviour.
TryUnlockMe - The Frostbitten OTP#
Start the game by running the following command on a terminal:
cd /home/ubuntu/Desktop/TryUnlockMe && ./TryUnlockMeExploring the game, you will find a penguin asking for a PIN. Terminate the previous game instance and execute the following Frida command to intercept all the functions in the
libaocgame.solibrary where some of the game logic is present:frida-trace ./TryUnlockMe -i 'libaocgame.so!*'If you revisit the game, you can trigger the OTP function on the console displayed as
set_otpi
Notice the output _Z7set_otpi indicates that the set_otp function is called during the NPC interaction; you can try intercepting it!
- Open a new terminal. Go to the
/home/ubuntu/Desktop/TryUnlockMe/__handlers__/libaocgame.so/folder, and open Visual Studio Code by running:
- At this point, you should be able to select the
_Z7set_otpiJavaScript file with the hook defined. The i at the end of theset_otpfunction indicates that an integer will be passed as a parameter. It will likely set the OTP by passing it as the first argument. To get the parameter value, you can use thelogfunction, specifying the first elements of the arrayargson theonEnterfunction:log("Parameter:" + args[0].toInt32());. Now Save.
Your JavaScript file should look like the following:
- Return to the game until you reach this point:
- Go back to the terminal which should show this:
- Use the parameter (in this case 685686) as the OTP. This reveals the flag.
TryUnlockMe - A Wishlist for Billionaires#
Explore the new stage of the game. You will find another penguin with a costly item (“Flag 2”) named Right of Pass. Try to buy it and you’ll be told you don’t have enough money. The game lets you earn coins by using the old PC on the field, but getting 1.000.000 coins that way sounds tedious. You can again use Frida to intercept the function in charge of purchasing the item.
This time is a bit more tricky than the previous one because the function
buy_itemdisplayed as:_Z17validate_purchaseiiihas threeiletters after its name to indicate that it has three integer parameters. You can log those values using the log function for each parameter trying to buy something:
log("Parameter1:" + args[0].toInt32())log("Parameter2:" + args[1].toInt32())log("Parameter3:" + args[2].toInt32())
- Save the file. Your JavaScript
buy_itemfile will look like this:
- Return to the game and try to buy the flag again. In the terminal you should be able to log something similar:
By simple inspection, we can determine that the first parameter is the Item ID, the second is the price, and the third is the player’s coins.
- Let’s manipulate the price and set it as zero, so we can buy any item that we want. Insert
args[1] = ptr(0)into the JavaScriptbuy_itemfile so it looks like this:
- Return to the game and try to buy Flag 2. We can buy the item and the flag is revealed.
TryUnlockMe - Naughty Fingers, Nice Hack#
- Continue with the game and find the third penguin.
- This is what shows in the terminal:
This last stage of the game is a bit more tricky because the output displayed by Frida is _Z16check_biometricsPKc(), so it does not handle integers anymore (notice there isn’t an i at the end of it like _Z17validate_purchaseiii or _Z7set_otpi), but strings making a bit more complex to debug.
- By selecting the JavaScript file named
_Z16check_biometricsPKc, you can add the following code to theonEnter()function as you did previously to debug the content of the parameter. Save the file. It should look like this:
- Return and interact with the game. This is what logs in the terminal:
- This output does not seem very helpful; you may have to consider another way. You can log the return value of the function by adding the following log instruction in the
onLeavefunction:
- Interact with the game again. This will show in the terminal:
So, the value returned is 0, which may indicate that it is a boolean flag set to False. Which value will set it to True? Can you trick the game into thinking the biometrics check worked?
- The following instruction will set it the return value to True:
retval.replace(ptr(1)). Add this to theonLeavefunction, and Save.
- Return to the game… Success!
- Notice the terminal is now showing a return value of 1:
Answers#
- What is the OTP flag? THM{one_tough_password}.
- What is the billionaire item flag? THM{credit_card_undeclined}.
- What is the biometric flag? THM{dont_smash_your_keyboard}.
Adapted from securechell/tryhackme-labs under MIT.