Flare-On 2020: Fidler
Flare-On 7 got off to an easy start with a Windows executable that was generated with PyGame, and included the Python source. That made this challenge more of a Python source code analysis exercise than a reversing challenge. I’ll find the password and the win conditions in the source, and win both by decrypting the flag and by modifying the source.
Welcome to the Seventh Flare-On Challenge!
This is a simple game. Win it by any means necessary and the victory screen will reveal the flag. Enter the flag here on this site to score and move on to the next level.
This challenge is written in Python and is distributed as a runnable EXE and matching source code for your convenience. You can run the source code directly on any Python platform with PyGame if you would prefer.
The file is an x64 binary:
root@kali# file fidler.exe fidler.exe: PE32+ executable (console) x86-64, for MS Windows
As the prompt mentioned, there’s also a Python version with the supporting files:
root@kali# ls 1_-_fidler.7z controls.py fidler.exe fidler.py fonts img Message.txt
Because this is a CTF, it’s worth giving this a run in a Windows VM. A password prompt pops:
Guessing at a password pops up an “FBI” warning:
On a Linux VM, I did
pip3 install pygame and then ran
python3 fidler.py , and I get the same behavior. I’ll work out of this one because if I need to modify the program (and I will want to), it’s just easier than patching compiled Python.
Because I have the source I can take a look. The first two functions defined are
password_check gives away the password:
def password_check(input): altered_key = 'hiptu' key = ''.join([chr(ord(x) - 1) for x in altered_key]) return input == key
I can jump into a Python repl and get the key:
>>> altered_key = 'hiptu' >>> ''.join([chr(ord(x) - 1) for x in altered_key]) 'ghost'
On entering that password, now it goes to the game screen:
Clicking on the cat adds one coin:
If I have at least 10 coins, I can click the Buy button, and then I get 10 less coins, but now my coins increase at a rate of one per second. Buying a second autoclicker will have my coins increase at two per second, etc. Even buying autoclickers as fast as possible, getting to 100 billion is going to take forever.
There’s a function towards the bottom of the code,
def decode_flag(frob): last_value = frob encoded_flag = [1135, 1038, 1126, 1028, 1117, 1071, 1094, 1077, 1121, 1087, 1110, 1092, 1072, 1095, 1090, 1027, 1127, 1040, 1137, 1030, 1127, 1099, 1062, 1101, 1123, 1027, 1136, 1054] decoded_flag =  for i in range(len(encoded_flag)): c = encoded_flag[i] val = (c - ((i%2)*1 + (i%3)*2)) ^ last_value decoded_flag.append(val) last_value = c return ''.join([chr(x) for x in decoded_flag])
This function is called in
victory_screen(token), and the unmodified
token variable is passed into it.
victory_screen is called from
game_screen(), at the top of the main
while True loop:
while not done: target_amount = (2**36) + (2**35) if current_coins > (target_amount - 2**20): while current_coins >= (target_amount + 2**20): current_coins -= 2**20 victory_screen(int(current_coins / 10**8)) return ...[snip rest of the game]...
target_amount variable that is set to 103079215104. To get to the call of
current_coins must be greater than
target_amount minus 220, 103078166528. If
current_coins is more than 220 more than
target_amount, it will subtract 220 from
current_coins until it isn’t. Then,
victory_screen is called, with
token as the floor of
current_coins / 108. That means to get to
current_coins will be between 103078166529 and 103080263679 (inclusive). Anything in that range will result in a
token of 1030:
>>> ((2**36 + 2**35) + 2**20 - 1) // 10**8 1030 >>> ((2**36 + 2**35) - 2**20 + 1) // 10**8 1030
I can solve from here knowing the token and having the
decrpyt_flag function. In fact, I can just import the Python file and call the function:
root@kali# python3 Python 3.8.5 (default, Aug 2 2020, 15:09:07) [GCC 10.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import fidler pygame 1.9.6 Hello from the pygame community. https://www.pygame.org/contribute.html >>> fidler.decode_flag(1030) 'firstname.lastname@example.org'
Modify the Program
Alternatively, I can modify the program to win. At the top of the code, the
current_coins variable is initialized to 0:
import pygame as pg pg.init() from controls import * current_coins = 0 current_autoclickers = 0 buying = False
I’ll just drop 110,000,000,000 in:
current_coins = 110000000000
Now, on running the game, it goes right to the victory screen: