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#

  1. Start the game by running the following command on a terminal: cd /home/ubuntu/Desktop/TryUnlockMe && ./TryUnlockMe

  2. Exploring 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.so library where some of the game logic is present: frida-trace ./TryUnlockMe -i 'libaocgame.so!*'

  3. If you revisit the game, you can trigger the OTP function on the console displayed as set_otpi

image

Notice the output _Z7set_otpi indicates that the set_otp function is called during the NPC interaction; you can try intercepting it!

  1. Open a new terminal. Go to the /home/ubuntu/Desktop/TryUnlockMe/__handlers__/libaocgame.so/ folder, and open Visual Studio Code by running:

image

image

  1. At this point, you should be able to select the _Z7set_otpi JavaScript file with the hook defined. The i at the end of the set_otp function 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 the log function, specifying the first elements of the array args on the onEnter function: log("Parameter:" + args[0].toInt32());. Now Save.

Your JavaScript file should look like the following:

image

  1. Return to the game until you reach this point:

image

  1. Go back to the terminal which should show this:

image

  1. Use the parameter (in this case 685686) as the OTP. This reveals the flag.

image

TryUnlockMe - A Wishlist for Billionaires#

  1. 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.

  2. This time is a bit more tricky than the previous one because the function buy_item displayed as: _Z17validate_purchaseiii has three i letters 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())

  1. Save the file. Your JavaScript buy_item file will look like this:

image

  1. Return to the game and try to buy the flag again. In the terminal you should be able to log something similar:

image

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.

  1. 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 JavaScript buy_item file so it looks like this:

image

  1. Return to the game and try to buy Flag 2. We can buy the item and the flag is revealed.

image

TryUnlockMe - Naughty Fingers, Nice Hack#

  1. Continue with the game and find the third penguin.
  2. This is what shows in the terminal:

image

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.

  1. By selecting the JavaScript file named _Z16check_biometricsPKc, you can add the following code to the onEnter() function as you did previously to debug the content of the parameter. Save the file. It should look like this:

image

  1. Return and interact with the game. This is what logs in the terminal:

image

  1. 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 onLeave function:

image

  1. Interact with the game again. This will show in the terminal:

image

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?

  1. The following instruction will set it the return value to True: retval.replace(ptr(1)). Add this to the onLeave function, and Save.

image

  1. Return to the game… Success!

image

  1. Notice the terminal is now showing a return value of 1:

image

Answers#

  1. What is the OTP flag? THM{one_tough_password}.
  2. What is the billionaire item flag? THM{credit_card_undeclined}.
  3. What is the biometric flag? THM{dont_smash_your_keyboard}.

Adapted from securechell/tryhackme-labs under MIT.

Find us elsewhere

Merch, stickers, and moreSupport the work at the Solvere Labs shop