Another Python Game [Rev]

For this challenge, a Python-compiled executable and a background file are provided to us.

We can confirm that the executable given is a Python-compiled executable by using strings
strings source.exe
If strings
reveal strings such as python
or py
, it is a huge giveaway that the executable was compiled using Python, specifically with the pyinstaller
library. Therefore, the source code of the executable can be recovered using pyinstxtractor
. pyinstxtractor
can be downloaded here:
From here, just execute pyinstxtractor.py
followed by the executable given, and it will extract .pyc
files which are compiled bytecode of the source code. Compiled bytecode is a type of intermediary code that a compiler creates by translating source code into bytecode.

As a general rule of thumb, locate the .pyc
file that has the same name as the executable that we received from the challenge. In this case, it will be source.pyc
.

The .pyc
file contains the source code of the executable. However, it is not human-readable as mentioned before, they are compiled bytecode. For this reason, decompyle3
is needed to decompile the bytecode into human-readable code. decompyle3
can be installed through pip
:
pip3 install decompyle3
Lastly, execute decompyle3
followed by source.pyc
.
┌──(jigsaw㉿jigsaw)-[~/Desktop/pyinstxtractor/source.exe_extracted]
└─$ decompyle3 source.pyc
Using decompyle3
we managed to recover the source code of the executable!
# decompyle3 version 3.9.1
# Python bytecode version base 3.8.0 (3413)
# Decompiled from: Python 3.11.9 (main, Apr 10 2024, 13:16:36) [GCC 13.2.0]
# Embedded file name: source.py
import pygame, sys
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("CTF Challenge")
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
font = pygame.font.Font(None, 74)
small_font = pygame.font.Font(None, 36)
flag_hidden = True
flag_text = "OSCTF{1_5W3ar_I_D1dn'7_BruT3f0rc3}"
hidden_combination = ["up","up","down","down","left","right","left","right"]
input_combination = []
player_size = 50
player_pos = [screen_width // 2, screen_height // 2]
player_color = BLUE
player_speed = 5
background_image = pygame.image.load("background.png")
background_image = pygame.transform.scale(background_image, (screen_width, screen_height))
def show_message(text, font, color, pos):
message = font.render(text, True, color)
screen.blit(message, pos)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
input_combination.append("up")
elif event.key == pygame.K_DOWN:
input_combination.append("down")
elif event.key == pygame.K_LEFT:
input_combination.append("left")
elif event.key == pygame.K_RIGHT:
input_combination.append("right")
if input_combination == hidden_combination:
flag_hidden = False
if len(input_combination) > len(hidden_combination):
input_combination.clear()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player_pos[0] -= player_speed
if keys[pygame.K_RIGHT]:
player_pos[0] += player_speed
if keys[pygame.K_UP]:
player_pos[1] -= player_speed
if keys[pygame.K_DOWN]:
player_pos[1] += player_speed
player_pos[0] = max(0, min(player_pos[0], screen_width - player_size))
player_pos[1] = max(0, min(player_pos[1], screen_height - player_size))
screen.blit(background_image, (0, 0))
if flag_hidden:
show_message("Find the hidden combination to reveal the flag!", small_font, WHITE, (50,
50))
else:
show_message(flag_text, small_font, WHITE, (0, 0))
pygame.draw.rect(screen, player_color, (*player_pos, player_size, player_size))
pygame.display.flip()
pygame.time.Clock().tick(30)
# okay decompiling source.pyc
Reading through the source code, one of the variables is the flag!
flag: OSCTF{1_5W3ar_I_D1dn'7_BruT3f0rc3}
Last updated