5 I played on Saturday and Sunday, on both days about 7 hours, but I found the challenges either quit difficult or much guessing. So I lost a lot of time to find an interesting challenge for me. The `catch the flag` challenge was interesting, but I just started it a view hours before the end of the CTF and had not time to finish it.
7 ### catch the flag (not solved)
9 Given was a client (`client.py`) and a server (`game.py`) program which communicated over sockets. There was another python script (`world_generator.py`) which generated a random world for the game. This script was executed only once at the beginning, so the _world_ was every time the same. The `flag_char.py` script was only a helper script for the server (`game.py`).
11 A world looks something like that:
26 The real world was much bigger! We can navigate through this world with the directions **up**, **down**, **left** and **right**. We always start on the top left corner. If we _crash_ into a **1**, we lost. The **twos** are the flag which we have to _collect_. We cannot leave the game world.
28 Additionally we receive as response from the server the following _information_:
30 - `i\x00breeze`: horizontally or vertically next to us is a **1**.
31 - `i\x00smell`: horizontally or vertically next to us is a **2** (flag char).
32 - `iw`: we move onto a wall.
33 - `e\x00<some text>`: a message.
34 - `f\x00<some char>`: we found a flag char.
37 The client program is just a wrapper which does some fancy stuff on the different responses from the server - we do not really need it.
39 The tricky part now is that each character of the flag, initially in the center of the world, moves every second turn randomly one field up, down, left or right. So we cannot just easy navigate to the flag and collect all the characters from it.
41 I wrote the following script to explore the world a little bit:
44 #!/usr/bin/env python3
58 mapp = [[9 for i in range(WIDTH)] for j in range(HEIGHT)]
59 with open("exploit_map", "r") as f:
60 lines = f.read().strip().split('\n')
61 for y, line in enumerate(lines):
62 for x, c in enumerate(line):
67 with open("exploit_map", "w") as f:
69 f.write(''.join(map(str, line)) + "\n")
71 def receive_until_prompt(sock, prompt=b"\n"):
73 buf_size = len(prompt)
75 new = sock.recv(buf_size)
77 for i in range(1, len(prompt) + 1):
78 if received.endswith(prompt[-i:]):
82 buf_size = len(prompt) - i + 1
84 raise Exception(f"Connection closed before {prompt} was found.")
87 data = receive_until_prompt(sock)
89 data = data.split(b"\x00")
92 def set_curr_pos(mapp, val):
97 def parse(data, mapp):
100 print(f"c-text={data[1]}")
101 elif data[0] == b"e":
102 print(f"e-text={data[1]}")
103 elif data[0] == b"i":
105 set_curr_pos(mapp, 0)
110 if data[1] == b'breeze':
113 elif data[1] == b'smell':
116 print(f"breeze and smell: {data}")
119 print(f"???? {data}")
120 elif data[0] == b"iw":
122 elif data[0] == b"d":
124 set_curr_pos(mapp, 1)
126 elif data[0] == b"f":
127 set_curr_pos(mapp, 0)
128 print(f"flag char={data[1]}")
129 flag_chars.append(data[1])
133 def set_pos(direction):
138 elif direction == "w":
140 elif direction == "a":
142 elif direction == "d":
152 pos = (x, HEIGHT - 1)
154 def move(s, direction, mapp):
156 s.sendall(f"{direction}\n".encode())
158 return parse(data, mapp)
163 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
164 s.connect((HOST, PORT))
172 for d in range(WIDTH):
173 way = "d"*d + "s"*HEIGHT
174 #way = "s"*d + "d"*WIDTH
175 for direction in way:
176 res = move(s, direction, mapp)
180 elif res == "breeze":
181 res = move(s, "a", mapp)
186 print(f"flag_chars={flag_chars}")
189 But obviously this does not really help us, because even if we find every flag character, we do not know the correct order. So I looked again to the scripts and found the following line in the `flag_char.py` file: `random.seed(int(time.time()))`. So we know the seed and can thus predict the position of the flag characters.
191 So a solution could be the following:
193 1. Explore the whole world to know where the **ones** are.
194 2. Move randomly around to find all the flag characters to know the length of the flag.
195 3. Predict the position of each character with the known seed.
197 As I said at the beginning, the time was over after I found out all this information.
199 ### flag concat (not solved)
201 Given was a program which took two flags as input and concatenated them. If a flag included the string `hxp{`, it ignored the characters before this part. So e.g. if flag 1 is `aaahxp{flag1}\n` and flag 2 is `bbbhxp{flag2}\n` the output is `hxp{flag1}\nhxp{flag2}\n`.
203 I looked for a while at the source code and to the man pages to find something for a buffer overflow. With gdb I found out, we have to change the return address from `0x4009cf` to `0x4007b6`. The behavior with the packed_strings struct was somehow weird to me. Everything I tried to overwrite the return address on the stack did not work.