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