Сегодня, пока начинается наш курс по Fullstack-разработке на Python, рассказываем о стартапе Hacker.gifts, который отвечает на вопрос в заголовке. Автор оригинальной статьи приобрёл головоломку для себя, чтобы помочь читателям разобраться, понравиться ли она кому-то ещё. Под катом вы найдёте решение, общие впечатления и ссылку на задачу посложнее.


В посте нет моих подсказок и файлов, потому что я не знаю, повторяются ли головоломки и не нарушаю ли я какое-то соглашение. Такие данные скрыты символом X.

Решаем головоломку

Разместив заказ на сайте, вы получите виртуальную открытку с первой головоломкой, вроде той, что ниже. Вы можете задать имя на открытке, её дизайн и сообщение, которое появится после решения всех головоломок.

Отсканировав QR, вы получите что-то вроде этого:

U2VjcmV0IGhleGR1b..............YzMS00NTQyKQo=

Строки, которые заканчиваются символом =, я обычно видел в алгоритмах, работающих с base64, поэтому решил начать именно с base64. Тогда же я подумал, что декодирование можно автоматизировать, поэтому придумал программу, чтобы декодировать QR и конвертировать base64:

from pyzbar.pyzbar import decode
from PIL import Image
import base64


def solve():
    # let's see what's inside the QR
    qr = decode(Image.open('../puzzle/card.png'))
    data = qr[0].data.decode("utf-8")
    print(f"QR data: {data}")

    # the last "=" in data looks like it's base64
    # let's try that
    base64_message = data
    base64_bytes = base64_message.encode('ascii')
    message_bytes = base64.b64decode(base64_bytes)
    plain_msg = message_bytes.decode('ascii')
    print(f"Base64: {plain_msg}")

Декодированный текст содержит ссылку на сайт и некий код доступа. Ссылку и код я скрыл символами X, о которых говорил выше.

Секретный hex-дамп: https://XXXXX.XXXXX/ (XXXX-XXXX-XXXX)

После ввода этого кода на сайте по ссылке вас ждёт замечательный hex-дамп. Когда до него дошло, я отметил для себя, что не хочу автоматизировать просмотр сайта. А вот выдержка из дампа:

Первый важный момент — дамп начинается с rar, так что файл, должно быть, сжат и, вероятно, защищён паролем из-за текста внизу. Похоже, что пароля просто нет. Сначала я подумал, что это какая-то ошибка, попробовал несколько раз и заподозрил, что пароль каким-то образом скрыт. Например, в комментарии.

Итак, мы знаем, что файл rar защищён паролем, так что следующий шаг — найти пароль — провести реверс-инжиниринг дампа. Именно это и сделает представленный ниже метод:

def reverse_dump():
    newFileBytes = []

    with open("../puzzle/hex.txt", "r") as txt_file:
        lines = txt_file.readlines()

        for line in lines:
            if line.startswith("0"):
                parts = line.split(" ")

                for i, p in enumerate(parts):
                    if i > 0 and p != "" and not p.startswith("|") and not p.startswith("."):
                        newFileBytes.append(int(p, base=16))

    with open("../puzzle/hex.rar", "wb") as rar_file:
        for byte in newFileBytes:
            rar_file.write(byte.to_bytes(1, byteorder='big'))

После распаковки одного файла вы получите ещё два:

instr.txt
key

Файл инструкций Instr.text содержит:

  • Цель — залогиниться на каком-то сервере.

  • Стихотворение хайку, в нём зашифрован IP.

  • Незашифрованный пароль от SSH.

  • Инструкции, как брут-форсом получить другой пароль, чтобы расшифровать файл ключа SSH и залогиниться на сервере.

Начнём с IP-адреса. На него указывает этот хипку:

This hipku will point to a server:

The placid XXXXX hawk
dives in the XXXXX river.
Jasmine XXXXX drop.

Опечатка в слове "хайку" [haiku — hipku] намеренная. Это подсказка, что IP скрыт в стихотворении. Но как его интерпретировать? Вначале я подумал, что это может быть известным стихотворением с изменениями символов, например «placid» — это place. Но, немного погуглив, я обнаружил программу hipku, которая преобразует IP в стихотворение. Быть может, намёк прозрачнее, чем я думал. Расшифровка оказалась довольно простой: 

from pyhipku import decode


def reverse_haiku():
    print(decode('The placid XXXXX hawk\ndives in the XXXXX river.\nJasmine XXXXX drop.\n'))
167.XX.XXX.XXX

А теперь перебором найдём пароль. В инструкциях сказано, что он состоит из семи цифр, а ещё даётся подсказка — начало хеша пароля (SHA-256):

from hashlib import sha256
from brute import brute


def brute_force():
    # replace "XXXXXXXXXX" with your real SHA-256 hint                     
    expected = str.lower("XXXXXXXXXX")

    for pwd in brute(length=7, letters=False, numbers=True, symbols=False):
        hashed = sha256(pwd.encode('utf-8')).hexdigest()
        # print(hashed)

        if hashed.startswith(expected):
            print(pwd)

Теперь разберёмся с ключом. Файл key выглядит примерно так:

-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
                      
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END EC PRIVATE KEY-----

В прошлом я часто пользовался PuTTY и знаю, что этой программе нужны ключи в формате ppk, поэтому догадался: чтобы получить пароль, нужно что-то сделать с текстом в key. Здесь мне помог PuTTYgen:

В этом окне нужно ввести полученный перебором пароль, и кликнуть на Save Private Key.

Когда я залогинился на сервере, меня приветствовала консольная версия игры Space Invaders. Пройти нужно было только первый уровень. И вообще это несложно, но игра через SSH немного подтормаживала.

И вот оно! Моё секретное сообщение появилось!

Следим за друзьями

Сделав заказ, вы получите URL-адрес и сможете отслеживать, что делает ваш друг. И это одна из причин, почему в головоломке есть посещение сайта и вход на сервер. Ещё важнее, что вы сможете направлять друзей, если они где-то застряли.

Как видите, есть подсказки. Именно это мы и сделали, но воспользовались другими инструментами. На решение и записи для поста я потратил около 4 часов. Начал я ночью, а затем ушёл спать. Это объясняет "18 часов" на скриншоте.

Стоило ли оно того?

С точки зрения той части, которую получат ваши друзья, — совершенно точно стоило. Покупка прошла хорошо, платёж был простым, всё пришло сразу же, сайт отслеживания отработал и т. д. 

Что касается цены, сделать вывод сложно: о развлечениях у всех нас разные представления. Также всё зависит от ваших прошлых впечатлений и от того, сколько времени займёт решение головоломки. В любом случае вы можете судить об этом по моему решению. Неплохо было бы иметь больше вариантов по длине или по сложности.

И последнее

Надеюсь, что вы получили удовольствие. Если вам нравятся такие головоломки, я рад предложить кое-что посложнее: Tom’s Data Onion. Я просто взорвался, пока решал её. Это было нелегко, но я узнал несколько интересных вещей.

А решать на Python практические задачи вы научитесь на наших курсах:

Узнайте подробности акции.

Другие профессии и курсы

Комментарии (2)


  1. Ar0x13
    12.12.2021 22:52

    Прикольная тема - в прошлом году как раз дарил другу:)). Но я бы сказал тут надо немного шарить во всем(программирование/сети и тд)


  1. artebel
    15.12.2021 03:11

    Прикольно, но мне кажется, что этап с пониманием игры слов hipku - просто уцуцуга, решается неочевидно