Writeup: FlareOn 2020: 001 - Fidler
1. TLDR
2. Input data
The challenge file is here. Password: flare.
The subject of the task is a program written in python. The available files are:
controls.py
fidler.py
fonts/arial.ttf
fonts/courbd.ttf
img/btndown.png
img/btnup.png
img/clock.png
img/coin.png
img/fbi.png
img/kittyelaine.png
Message.txt
fidler.exe
Due to the fact that the program logic is implemented in the file fidler.py
, it is enough to analyze this file.
3. Access to the program
Access to the program is protected: after starting, the user sees a screen where he is asked for a password.
The program is written in python, its code is immediately available.
The password_check()
function is responsible for verifying the password:
def password_check(input):
altered_key = 'hiptu'
key = ''.join([chr(ord(x) - 1) for x in altered_key])
return input == key
In order to obtain the password, it is enough to execute the script:
altered_key = 'hiptu'
key = ''.join([chr(ord(x) - 1) for x in altered_key])
print(key)
Thus, on the standard output, you can get the password written out, which allows you to access the program:
ghost
4. Code analysis
After entering the access password, the appropriate application window appears:
The following functions are responsible for reading and presenting the flag:
- decode_flag:
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])
- victory_screen:
def victory_screen(token):
...
flag_content_label.change_text(decode_flag(token))
...
- game_screen:
def game_screen():
...
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
...
5. Reading the flag
Therefore, in order to read the flag, the code should be executed:
#! /usr/bin/python3
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])
def victory_screen(token):
print(decode_flag(token))
def main():
target_amount = (2**36) + (2**35)
current_coins = (target_amount - 2**20) + 1
while current_coins >= (target_amount + 2**20):
current_coins -= 2**20
victory_screen(int(current_coins / 10**8))
if __name__ == "__main__":
main()
The flag is printed on the standard output:
idle_with_kitty@flare-on.com