his insane scientist wants to craft the most powerful android in the world! Help him collect many ๐ฉ to achieve his goal. Also, he needs many ๐ to make it even more strong and pwoerful than any other android. Good luck adventurer!
Category: misc
Solver: 3mb0, nh1729
Flag: HTB{w1th_4ll_th353_b0lt5_4nd_g3m5_1ll_cr4ft_th3_b35t_t00ls}
Writeup
When connecting to the port and ip with netcat
, we get a menu:
1. Instructions
2. Play
>
If we enter 1
, we get the rules of the game:
๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ
๐ฉ ๐ฉ
๐ฉ [*] Help the ๐ค reach the ๐. ๐ฉ
๐ฉ [*] You need to find the shortest route. ๐ฉ
๐ฉ [*] You need to collect 500 ๐ and at least 5000 ๐ฉ. ๐ฉ
๐ฉ [*] The solution should be given in the format: DLR (Down, Left, Right) ๐ฉ
๐ฉ ๐ฉ
๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ
If we enter 2
in the menu, we get a game level that looks like this
๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ
๐ฅ โ ๐ค โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ โ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ โ ๐ฉ ๐ฉ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ โ โ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ ๐ฉ ๐ฉ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ ๐ฉ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ ๐ฉ ๐ฉ ๐ฉ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ โ โ ๐ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ๐ฅ
๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ ๐ฅ
>
with a command prompt. The first approach is to solve it by hand. In the above level the solution is DDRDDRDDLLLDDDRDDDDDDDDRD
As a reward we get bolts and diamonds:
[+] You have 1 ๐!
[+] You have 25 ๐ฉ !
Additionally, we get a new level. The levels are not the same if you connect to the server multiple times and the size of the levels changes. In order to solve this in a reasonable amount of time, we need a script!
Writing the script is not very difficult. We get the level with a python socket and remove all the unnecessary characters. The biggest problem for us is that โ
consists of 6 bytes and is not a single character in a python string. We solve that by replacing it with another character. After generating a grid of the level, we just use a breadth-first-search to find our way to the diamond. In a loop, we solve 500 levels as stated in the instructions and get the final message:
[+] You have 500 ๐!
[+] You have 10084 ๐ฉ !
[+] Congratulations! This is your reward!
HTB{w1th_4ll_th353_b0lt5_4nd_g3m5_1ll_cr4ft_th3_b35t_t00ls}
Our complete script looks like this:
#!/usr/bin/env python3
import socket
import queue as q
HOST = '167.172.49.117'
PORT = 32635
# all special characters: ๐คโ โ ๐ฅ๐ฉ๐
# breadth-first-search
def bfs(level):
# find robot
start = None
for i in range(len(level)):
for j in range(len(level[i])):
if level[i][j] == '๐ค':
start = (i, j)
print(f'[+] ๐ค is at {start}')
if start is None:
print('[!] Could not find ๐ค...')
exit(1)
# https://en.wikipedia.org/wiki/Breadth-first_search
explored = set()
# queue format: (row, column, predecessor, direction to get to this field))
queue = q.Queue()
queue.put((start[0], start[1], None, None))
explored.add(start)
while not queue.empty():
field = queue.get()
if level[field[0]][field[1]] == '๐':
# reconstruct path from the end
path = ''
while field[3] is not None:
path += field[3]
field = field[2]
# reverse the path to get the path from the start
return path[::-1]
else:
# left
left = (field[0], field[1] - 1)
if left[1] >= 0 and left not in explored and level[left[0]][left[1]] != 'x':
explored.add(left)
queue.put((left[0], left[1], field, 'L'))
# right
right = (field[0], field[1] + 1)
if right[1] < len(level[field[0]]) and right not in explored and level[right[0]][right[1]] != 'x':
explored.add(right)
queue.put((right[0], right[1], field, 'R'))
# down
down = (field[0] + 1, field[1])
if down[0] < len(level) and down not in explored and level[down[0]][down[1]] != 'x':
explored.add(down)
queue.put((down[0], down[1], field, 'D'))
print('[!] Could not find path')
exit(1)
def solve_level(s):
# get level
level = b''
while b'>' not in level:
level += s.recv(1024)
# replace weird two character emoji โ with something less weird
level = level.replace(b'\xe2\x98\xa0\xef\xb8\x8f', 'x'.encode())
# decode bytes to string
level = level.decode()
# remove command prompt
level = level.replace('>', '')
# remove trailing / leading whitespace
level = level.strip()
# remove empty lines
lines = [line for line in level.split('\n') if line]
# remove ๐ฅ lines, keep level lines, print other lines
rows = []
for line in lines:
print(line)
if line.startswith('๐ฅ๐ฅ'):
# ignore
pass
elif line.startswith('๐ฅ'):
# remove ๐ฅ and spaces
rows.append(line.replace('๐ฅ', '').replace(' ', ''))
else:
# ignore
pass
# solve level
path = bfs(rows)
return path
def main():
# connect to server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
# receive main menu
menu = s.recv(1024)
# select play
s.sendall('2\n'.encode())
# play game 500 times
for _ in range(500):
path = solve_level(s)
print(f'[+] Path: {path}\n')
s.sendall((path + '\n').encode())
# receive flag
print(s.recv(4096).decode())
if __name__ == '__main__':
main()