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 :
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.
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:
- Rip the flag text generation routine from the code and run it yourself
- Play the game. No code modification necessary. (My favorite )
- 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.