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}

flag.png

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()

Other resources