Home FlareOn 11 Challenge 1 - Frog
Post
Cancel

FlareOn 11 Challenge 1 - Frog

Frog.py

Opening the archive we are presented with the files for this challenge. Obviously this is a python program and taking a peek into the “img” folder we see some graphical assets. This is probably a game…

Files in the archive Looks like assets to a game

The README.txt file confirms our suspicions :

Readme.txt

Let’s Play a Game

Throwing caution to the wind, we run frog.exe. We are greeted by a game board and a golden frog. We can move the frog with WASD or the arrow keys. The goal is to get to the statue. However, there are blocks in the way and seemingly no way past them.

The game board

Code Review

The creators were kind enough to provide us with the source code. Below are some of the more interesting pieces.

Victory Tile

A vector variable named victory_tile seems interesing…

1
2
3
4
5
6
7
screen = pygame.display.set_mode((screen_width, screen_height))
clock = pygame.time.Clock()
victory_tile = pygame.Vector2(10, 10) #<---victory_tile seems interesting...

pygame.key.set_repeat(500, 100)
pygame.display.set_caption('Non-Trademarked Yellow Frog Adventure Game: Chapter 0: Prelude')
dt = 0

The Block class

We can see each Block object initializes with an x, y and a very interesting parameter named: passable

1
2
3
4
5
6
7
8
9
10
11
12
13
class Block(pygame.sprite.Sprite):
    def __init__(self, x, y, passable):
        super().__init__()
        self.image = blockimage
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.passable = passable #<----Interesting
        self.rect.top = self.y * tile_size
        self.rect.left = self.x * tile_size

    def draw(self, surface):
        surface.blit(self.image, self.rect)

Flag Generation

This function seems to decode our flag. We can see that we need x and y to calculate the key. Presumably this is an x-coordinate and a y-coordinate.

1
2
3
4
def GenerateFlagText(x, y):
    key = x + y*20
    encoded = "\xa5\xb7\xbe\xb1\xbd\xbf\xb7\x8d\xa6\xbd\x8d\xe3\xe3\x92\xb4\xbe\xb3\xa0\xb7\xff\xbd\xbc\xfc\xb1\xbd\xbf"
    return ''.join([chr(ord(c) ^ key) for c in encoded])

Victory Mode

If-statement that seems to generate the flag text if we’ve reached the victory_tile

1
2
3
4
5
6
7
8
9
10
if not victory_mode:
            # are they on the victory tile? if so do victory
            if player.x == victory_tile.x and player.y == victory_tile.y:
                victory_mode = True
                flag_text = GenerateFlagText(player.x, player.y)
                flag_text_surface = flagfont.render(flag_text, False, pygame.Color('black'))
                print("%s" % flag_text)
        else:
            screen.blit(winimage, (150, 50))
            screen.blit(flag_text_surface, (239, 320))

Build the Blocks

This LONG code builds the Block objects. Remember, from the Block Class, that each object gets an x, y and passable parameter.

Click to view the block building code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def BuildBlocks():
    blockset = [
        Block(3, 2, False),
        Block(4, 2, False),
        Block(5, 2, False),
        Block(6, 2, False),
        Block(7, 2, False),
        Block(8, 2, False),
        Block(9, 2, False),
        Block(10, 2, False),
        Block(11, 2, False),
        Block(12, 2, False),
        Block(13, 2, False),
        Block(14, 2, False),
        Block(15, 2, False),
        Block(16, 2, False),
        Block(17, 2, False),
        Block(3, 3, False),
        Block(17, 3, False),
        Block(3, 4, False),
        Block(5, 4, False),
        Block(6, 4, False),
        Block(7, 4, False),
        Block(8, 4, False),
        Block(9, 4, False),
        Block(10, 4, False),
        Block(11, 4, False),
        Block(14, 4, False),
        Block(15, 4, True),
        Block(16, 4, False),
        Block(17, 4, False),
        Block(3, 5, False),
        Block(5, 5, False),
        Block(11, 5, False),
        Block(14, 5, False),
        Block(3, 6, False),
        Block(5, 6, False),
        Block(11, 6, False),
        Block(14, 6, False),
        Block(15, 6, False),
        Block(16, 6, False),
        Block(17, 6, False),
        Block(3, 7, False),
        Block(5, 7, False),
        Block(11, 7, False),
        Block(17, 7, False),
        Block(3, 8, False),
        Block(5, 8, False),
        Block(11, 8, False),
        Block(15, 8, False),
        Block(16, 8, False),
        Block(17, 8, False),
        Block(3, 9, False),
        Block(5, 9, False),
        Block(11, 9, False),
        Block(12, 9, False),
        Block(13, 9, False),
        Block(15, 9, False),
        Block(3, 10, False),
        Block(5, 10, False),
        Block(13, 10, True),
        Block(15, 10, False),
        Block(16, 10, False),
        Block(17, 10, False),
        Block(3, 11, False),
        Block(5, 11, False),
        Block(6, 11, False),
        Block(7, 11, False),
        Block(8, 11, False),
        Block(9, 11, False),
        Block(10, 11, False),
        Block(11, 11, False),
        Block(12, 11, False),
        Block(13, 11, False),
        Block(17, 11, False),
        Block(3, 12, False),
        Block(17, 12, False),
        Block(3, 13, False),
        Block(4, 13, False),
        Block(5, 13, False),
        Block(6, 13, False),
        Block(7, 13, False),
        Block(8, 13, False),
        Block(9, 13, False),
        Block(10, 13, False),
        Block(11, 13, False),
        Block(12, 13, False),
        Block(13, 13, False),
        Block(14, 13, False),
        Block(15, 13, False),
        Block(16, 13, False),
        Block(17, 13, False)
    ]
    return blockset

Solutions

There are many ways you could solve this challenge:

  1. Rip the flag text generation routine from the code and run it yourself
  2. Play the game. No code modification necessary. (My favorite )
  3. Modify the code to remove blocks (or stop them from blocking)

Solution 1 - Rip Flag Generation Routine

We can see that the flag generation routine requires an x and a y value to generate a key that will be used in a xor decryption. It shouldn’t be a stretch to think that the x and y coorespond to the coordinates of the victory_tile.

victory_tile is located at (10, 10):

1
2
3
4
victory_tile = pygame.Vector2(10, 10) #<---victory_tile seems interesting...
.
.
.

Let’s rip this function out and provide (10,10) for the x and y parameters

1
2
3
4
def GenerateFlagText(x, y):
    key = x + y*20
    encoded = "\xa5\xb7\xbe\xb1\xbd\xbf\xb7\x8d\xa6\xbd\x8d\xe3\xe3\x92\xb4\xbe\xb3\xa0\xb7\xff\xbd\xbc\xfc\xb1\xbd\xbf"
    return ''.join([chr(ord(c) ^ key) for c in encoded])

Here is our new python code:

1
2
3
4
5
6
7
def GenerateFlagText(x, y):
    key = x + y*20
    encoded = "\xa5\xb7\xbe\xb1\xbd\xbf\xb7\x8d\xa6\xbd\x8d\xe3\xe3\x92\xb4\xbe\xb3\xa0\xb7\xff\xbd\xbc\xfc\xb1\xbd\xbf"
    return ''.join([chr(ord(c) ^ key) for c in encoded])

print(GenerateFlagText(10,10))

OUTPUT

Solution 2 - Play the Game

…after reviewing the code of course. Looking at the block creation code carefully, we can see that two of the blocks actually have a passable value of true meaning that they are probably…passable :)

1
2
3
4
# These 2 blocks have a passable value of True.
Block(15, 4, True),

Block(13, 10, True),

If the upper left corner of the board is the origin or (0,0).

As we move right->x increases.

As we move down->y increases.

From here, we can easily count to find which block is (15,4) and (13,10).

Moving the frog to these blocks allow us to pass right through to the statue which reveals the flag:

welcome_to_11@flare-on.com

Solution #3 - Modifying the Code

Many ways. I’ll leave this to the reader.

This post is licensed under CC BY 4.0 by the author.