First we download the provided file.
We are provided with some files, including
You can use
We are given the hint to use
We can
cd /
cd beginnersquest
cat ctl
echo begin > ctl ;)
After running
We are given the hint: "Ok, you seem to have found the flag... but have you tried writing the flag back to ctl?"
We run
int W = 5, H = 7, o , O[] = {31, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 14, 17, 17, 31, 17, 17, 17, 14, 1, 1, 25, 17, 17, 14, 12, 2, 2, 1, 2, 2, 12, 0, 17, 17, 17, 30, 16, 14, 14, 17, 25, 21, 19, 17, 14, 0, 0, 17, 17, 17, 17, 14, 0, 0, 0, 0, 0, 0, 31, 4, 4, 14, 4, 4, 4, 24, 15, 16, 16, 15, 16, 16, 15, 15, 16, 16, 15, 16, 16, 15, 0, 0, 0, 0, 0, 0, 31, 31, 1, 1, 15, 1, 1, 1, 0, 0, 0, 0, 0, 0, 31, 15, 16, 16, 15, 16, 16, 15, 4, 6, 4, 4, 4, 4, 4, 14, 1, 1, 25, 17, 17, 14, 1, 1, 15, 17, 17, 17, 17, 31, 16, 16, 8, 8, 4, 4, 0, 0, 0, 0, 0, 0, 31, 31, 1, 1, 31, 1, 1, 31, 17, 17, 17, 10, 10, 4, 4, 31, 1, 1, 31, 1, 1, 31, 15, 17, 17, 15, 17, 17, 17, 17, 17, 10, 4, 4, 4, 4, 17, 17, 21, 21, 21, 27, 17, 17, 17, 17, 31, 17, 17, 17, 15, 16, 16, 15, 16, 16, 15, 0, 0, 30, 1, 1, 1, 1, 15, 16, 16, 15, 16, 16, 15, 3, 4, 4, 8, 4, 4, 3}, x[] = {1986356271, 1835229487, 791752549, 1869771365, 29554};int main(void) { if((o = open((char*)x, OWRITE)) , 0) return -1; for (int i = 0; i < sizeof(O)/sizeof(O[0]); i += H) for (int ii = 0; ii < H; ++ii) for(int iii = 0; iii < W; ++iii) fprint(o, "%C", (O[i+ii]>>iii)&1?0x25a0:0x25a1); return 0; }
This is missing imports, so we add them:
#include <u.h>
#include <libc.h>
And we change
We change directory by entering
echo '#include <u.h>
#include <libc.h>
#include <stdio.h>
int W = 5, H = 7, o , O[] = {31, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 14, 17, 17, 31, 17, 17, 17, 14, 1, 1, 25, 17, 17, 14, 12, 2, 2, 1, 2, 2, 12, 0, 17, 17, 17, 30, 16, 14, 14, 17, 25, 21, 19, 17, 14, 0, 0, 17, 17, 17, 17, 14, 0, 0, 0, 0, 0, 0, 31, 4, 4, 14, 4, 4, 4, 24, 15, 16, 16, 15, 16, 16, 15, 15, 16, 16, 15, 16, 16, 15, 0, 0, 0, 0, 0, 0, 31, 31, 1, 1, 15, 1, 1, 1, 0, 0, 0, 0, 0, 0, 31, 15, 16, 16, 15, 16, 16, 15, 4, 6, 4, 4, 4, 4, 4, 14, 1, 1, 25, 17, 17, 14, 1, 1, 15, 17, 17, 17, 17, 31, 16, 16, 8, 8, 4, 4, 0, 0, 0, 0, 0, 0, 31, 31, 1, 1, 31, 1, 1, 31, 17, 17, 17, 10, 10, 4, 4, 31, 1, 1, 31, 1, 1, 31, 15, 17, 17, 15, 17, 17, 17, 17, 17, 10, 4, 4, 4, 4, 17, 17, 21, 21, 21, 27, 17, 17, 17, 17, 31, 17, 17, 17, 15, 16, 16, 15, 16, 16, 15, 0, 0, 30, 1, 1, 1, 1, 15, 16, 16, 15, 16, 16, 15, 3, 4, 4, 8, 4, 4, 3}, x[] = {1986356271, 1835229487, 791752549, 1869771365, 29554};int main(void) { if((o = open((char*)x, OWRITE)) , 0) return -1; for (int i = 0; i < sizeof(O)/sizeof(O[0]); i += H) for (int ii = 0; ii < H; ++ii) for(int iii = 0; iii < W; ++iii) fprint(1, "%C", (O[i+ii]>>iii)&1?0x25a0:0x25a1); return 0; }
' > program.c
We compile the program with
The output looks like ascii art, after resizing our note window we can see the flag letters from top to bottom with the width of 5 and height of 7.
We write a python script to extract the flag:
flag = "■■■■■■□□□□■□□□□■■■■□■□□□□■□□□□■□□□□■□□□□■□□□□■□□□□■□□□□■□□□□■□□□□■■■■■□■■■□■□□□■■□□□■■■■■■■□□□■■□□□■■□□□■□■■■□■□□□□■□□□□■□□■■■□□□■■□□□■□■■■□□□■■□□■□□□□■□□□■□□□□□■□□□□■□□□□□■■□□□□□□■□□□■■□□□■■□□□■□■■■■□□□□■□■■■□□■■■□■□□□■■□□■■■□■□■■■□□■■□□□■□■■■□□□□□□□□□□□■□□□■■□□□■■□□□■■□□□■□■■■□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■■■■■□□■□□□□■□□□■■■□□□■□□□□■□□□□■□□□□□■■■■■■□□□□□■□□□□■■■■■□□□□□■□□□□■■■■■□■■■■□□□□□■□□□□■■■■■□□□□□■□□□□■■■■■□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■■■■■■■■■■■□□□□■□□□□■■■■□■□□□□■□□□□■□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■■■■■■■■■□□□□□■□□□□■■■■■□□□□□■□□□□■■■■■□□□■□□□■■□□□□■□□□□■□□□□■□□□□■□□□□■□□□■■■□■□□□□■□□□□■□□■■■□□□■■□□□■□■■■□■□□□□■□□□□■■■■□■□□□■■□□□■■□□□■■□□□■■■■■■□□□□■□□□□■□□□■□□□□■□□□■□□□□■□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■■■■■■■■■■■□□□□■□□□□■■■■■■□□□□■□□□□■■■■■■□□□■■□□□■■□□□■□■□■□□■□■□□□■□□□□■□□■■■■■■□□□□■□□□□■■■■■■□□□□■□□□□■■■■■■■■■□■□□□■■□□□■■■■■□■□□□■■□□□■■□□□■■□□□■■□□□■□■□■□□□■□□□□■□□□□■□□□□■□□■□□□■■□□□■■□■□■■□■□■■□■□■■■□■■■□□□■■□□□■■□□□■■□□□■■■■■■■□□□■■□□□■■□□□■■■■■□□□□□■□□□□■■■■■□□□□□■□□□□■■■■■□□□□□□□□□□□□■■■■■□□□□■□□□□■□□□□■□□□□■■■■□□□□□■□□□□■■■■■□□□□□■□□□□■■■■■□■■□□□□□■□□□□■□□□□□■□□□■□□□□■□□■■□□□"
letters = [flag[i:i+5*7] for i in range(0, len(flag), 5*7)]
for letter in letters:
for i in range(7):
for j in range(5):
print(letter[i*5+j], end="")
print()
print()
This gives us the flag
We again write our flag to
This provides us with three files:
It seems like we are supposed to use the
Running
After finishing the maze the
It is possible to solve the maze by hand, but we can also write a script to solve it for us:
import pwn
import bitmap
map_data = [['U'] * 300 for _ in range(300)]
def move_in_direction(direction, r, moves, position):
# move in direction
r.sendline(moves[direction])
r.recvuntil(b"cpu%")
if direction == 0:
position = [position[0] - 1, position[1]]
elif direction == 1:
position = [position[0], position[1] + 1]
elif direction == 2:
position = [position[0] + 1, position[1]]
elif direction == 3:
position = [position[0], position[1] - 1]
return position
def move_player_on_wall(left_wall, right_wall, up_wall, down_wall, direction, r, moves, position):
# if there is no wall to the right side of our direction change direction
if direction == 0 and not right_wall:
direction = 1
elif direction == 1 and not down_wall:
direction = 2
elif direction == 2 and not left_wall:
direction = 3
elif direction == 3 and not up_wall:
direction = 0
# if current direction is not open invert direction
if direction == 0 and up_wall:
direction = 2
elif direction == 1 and right_wall:
direction = 3
elif direction == 2 and down_wall:
direction = 0
elif direction == 3 and left_wall:
direction = 1
else:
position = move_in_direction(direction, r, moves, position)
return position, direction
def solve(r: pwn.remote):
moves = ["echo ↑ > dpad", "echo → > dpad", "echo ↓ > dpad", "echo ← > dpad"]
r.recvuntil(b"glenda@gctf dp9ik password:")
r.sendline(b"welcome_to_the_machine")
r.recvuntil(b"cpu%")
# send flags to ctl if not done already to activatge challenge
r.sendline(b"cd /")
r.recvuntil(b"cpu%")
r.sendline(b"cd beginnersquest")
r.recvuntil(b"cpu%")
r.sendline(b"echo begin > ctl")
r.recvuntil(b"cpu%")
r.sendline(b"echo 'FLAG{h3ll0_n4m35p4c3!}' > ctl")
r.recvuntil(b"cpu%")
r.sendline(b"echo 'FLAG{y0u_t33_F_31Gh7_EVERYWH3r3}' > ctl")
r.recvuntil(b"cpu%")
distance = -1
direction = 0
position = [150, 150]
counter = 0
while distance < 1000:
# read maze
r.sendline(b"cat look")
map = r.recvuntil(b"cpu%").decode("utf-8")
map = map[:map.rfind("\n")]
# remove first character
map = map[1:]
r.sendline(b"cat distance")
distance = float(r.recvuntil(b"cpu%").decode("utf-8").replace("cpu%", ""))
# extract walls from map
map_rows = map.split("\n")
left_wall = map_rows[3][2] == '▪'
right_wall = map_rows[3][4] == '▪'
up_wall = map_rows[2][3] == '▪'
down_wall = map_rows[4][3] == '▪'
# save map to map_data
map_rows = map.split("\n")
for i in range(7):
for j in range(7):
if map_rows[i][j] == '▪':
map_data[position[0] - 3 + i][position[1] - 3 + j] = 'W'
elif map_rows[i][j] == '▨':
map_data[position[0] - 3 + i][position[1] - 3 + j] = 'B'
elif map_rows[i][j] == ' ':
map_data[position[0] - 3 + i][position[1] - 3 + j] = 'E'
else:
map_data[position[0] - 3 + i][position[1] - 3 + j] = 'P'
if counter > 20:
# render to BMP
with open("maze.bmp", "wb") as f:
side = 300
b = bitmap.Bitmap(side, side)
for j in range(0, side):
for i in range(0, side):
if map_data[i][j] == 'W':
b.setPixel(j, side-i-1, (0, 0, 0))
elif map_data[i][j] == 'B':
b.setPixel(j, side-i-1, (0, 0, 255))
elif map_data[i][j] == 'P':
b.setPixel(j, side-i-1, (0, 255, 0))
elif map_data[i][j] == 'E':
b.setPixel(j, side-i-1, (255, 255, 255))
else:
b.setPixel(j, side-i-1, (150, 150, 150))
b.write('maze.bmp')
counter = 0
else:
counter += 1
position, direction = move_player_on_wall(left_wall, right_wall, up_wall, down_wall, direction, r, moves, position)
# get flag
r.sendline(b"cat flag")
pwn.success(r.recvuntil(b"cpu%").decode("utf-8").replace("cpu%", ""))
r.close()
def conn():
command = 'drawterm -a localhost -h localhost -u glenda -G'
p = pwn.process(command, shell=True)
return p
def main():
c = conn()
solve(c)
if __name__ == "__main__":
main()
This maze solver just follows its right hand side and will eventually reach the flag.
It also saves the maze to a bmp file for visualization.
Running the script will give us the flag