team-logo
Published on

EHAX CTF 2025 - Reverse challenges

Authors

Introduction

We solved 4 out of 7 tasks. More info about this CTF is here Revs

Table of contents

RACEAGAINSTTIME

raceagainsinstime Writeup author: kerszi
Run game: alt text
Use procexp64.exe and create Full Dump alt text Find flag in dump alt text Flag: EH4X{r4c3_4g41nst_t1m3_4ppl3_p13}

PIZZATRON 3000

Writeup author: Cappybara img

After extracting zip we can see many files, including game.swf, which is game made in Flash.

img

Let's open txt file with instructions.

I named my puffle Dodo and suddenly he speaks...........
Dodo:"Play the game, edit the Pizzatron."
Dodo:"Listen to me carefully."

After opening the game in ruffle, playing and making pizza's with penguin, game ends, and we're stuck with broken button.

img

So now we're gonna proceed with the edit instruction, for it we're using JPEXS a Flash decompiler. Instead of fixing the button, let's search for a flag. We'll start with the texts directory.

img

And we found our flag EH4X{I_M1S5_61UBPENGUIN}

PIZZATRON 9000

Writeup author: Cappybara img

Again a pizza game, in the challenge description there is a flip switch mentioned, that we can find in game's menu.

img

Clicking on it doesn't change anything, so let's open the game in JPEXS again and search for this flip there. In the title frame i found a code

function getCoins()
{
   if(coins == undefined)
   {
      coins = 0;
   }
   var _loc3_ = new Object();
   _loc3_.score = coins * 10;
   _loc3_.coins = coins;
   _root.showWindow("Game Over",_loc3_);
   _global.pizzatron_dl.stopGame(candyMODE);
   if(quit)
   {
      _global.pizzatron_dl.sendGameScore(candyMODE,"quit",_loc3_.score,_loc3_.coins);
   }
   else
   {
      _global.pizzatron_dl.sendGameScore(candyMODE,"lose",_loc3_.score,_loc3_.coins);
   }
}
if(_global.dlearning_learner_id == undefined)
{
   var SHELL = _global.getCurrentShell();
   _global.dlearning_learner_id = SHELL.getMyPlayerId();
}
stop();
com.clubpenguin.security.Security.doSecurityCheck(this._url,this._parent);
_root.LocaleText = com.clubpenguin.util.LocaleText;
var SHELL = _global.getCurrentShell();
var gameDirectory = com.clubpenguin.util.LocaleText.getGameDirectory();
var localeDirectory = "files/";
var loader = new MovieClipLoader();
loader.loadClip(gameDirectory + localeDirectory + "title.swf",title_mc.titlescreen_mc.titleImage);
title_mc.ui_play.text = _root.LocaleText.getText("ui_play");
title_mc.ui_instructions.text = _root.LocaleText.getText("title_instructions");
title_mc.titlescreen_mc.switch_mc.switch_handle.onRelease = function()
{
   if(candyMODE)
   {
      candyMODE = false;
      title_mc.titlescreen_mc.switch_mc.gotoAndStop(1);
   }
   else if("key" != "g1ow")
   {
      trace("Access Denied. Edit the code to enable Candy Mode.");
   }
   else
   {
      candyMODE = true;
      title_mc.titlescreen_mc.switch_mc.gotoAndStop(2);
      trace("Game mode: Candy Mode");
   }
};
var penguinColor = SHELL.getMyPlayerHex();
var colorObject = new Color(title_mc.titlescreen_mc.penguin_mc);
colorObject.setRGB(penguinColor);
candyMODE = false;

We can see that we're asked to modify the code to enable Candy Mode. Statement "key" will always be not equal to "g1ow" so let's patch it.

<----------------------->
{
   if(candyMODE)
   {
      candyMODE = false;
      title_mc.titlescreen_mc.switch_mc.gotoAndStop(1);
   }
   else
   {
      candyMODE = true;
      title_mc.titlescreen_mc.switch_mc.gotoAndStop(2);
      trace("Game mode: Candy Mode");
   }
};
img

Now as we can see the flip works, now just play the game. After finishing the game, audio plays with flag. EH4X{1_MI5S_F1A5H_G4M3S}

MATH-MOVES

Writeup author: Cappybara img

In this challenge we'are asked to solve some logic puzzle with slides. We have single math-moves.exe file, lets run it.

img

But we don't know how to move those slides, we'll have to reverse engineer it. I recognized the Tkinter icon, so i knew that this program is a compiled python. I also found in strings that it was compiled using pyinstaller. That's good because we can extract source files using pyinstxtractor.

python pyinstxtractor.py math-moves.exe

Then enter the math-moves.exe_extracted directory and find math-moves.pyc. I decompiled it using this website https://www.pylingual.io/ I found a function that handles our input, so let's see what values are correct.

def handle_input():
    try:
        input_value = float(entry.get())
        moves = {UP_VALUE: 'up', DOWN_VALUE: 'down', LEFT_VALUE: 'left', RIGHT_VALUE: 'right'}
        for val, direction in moves.items():
            print(input_value, val)
            if abs(input_value - val) < 0.001:
                move_empty_space(direction)
                break
        if is_solved():
            messagebox.showinfo('Congratulations!', 'Puzzle solved!')
    except ValueError:
        print('Invalid input. Please enter a float.')
root = tk.Tk()
root.title('Sliding Puzzle Challenge')
images = load_images()
labels = [[None for _ in range(2)] for _ in range(2)]
for i in range(2):
    for j in range(2):
        labels[i][j] = tk.Label(root, image=images[puzzle[i][j] - 1] if puzzle[i][j] != 0 else images[3])
        labels[i][j].grid(row=i, column=j, padx=5, pady=5)
entry = tk.Entry(root)
entry.grid(row=2, column=0, columnspan=2, pady=10)
tk.Button(root, text='Submit', command=handle_input).grid(row=3, column=0, columnspan=2, pady=10)

So our input should be in float, then it would subtract from our input one of the moves map values, after that the slide would move. We can find variables declared earlier for those moves. They are loaded from Moves.dll and then deobfuscated. I set a breakpoint after deobfuscation and got the values.

img

After that input correct values, to move slides and those moves is your flag. EH4X{4.0_13.7015_9.1757_878.6}