- Published on
EHAX CTF 2025 - Reverse challenges
Introduction

Table of contents
RACEAGAINSTTIME


procexp64.exe
and create Full Dump 

EH4X{r4c3_4g41nst_t1m3_4ppl3_p13}
PIZZATRON 3000

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

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.

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.

And we found our flag EH4X{I_M1S5_61UBPENGUIN}
PIZZATRON 9000

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

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");
}
};

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

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

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.

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