
Сегодня, пока начинается наш курс по 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 практические задачи вы научитесь на наших курсах:

Узнайте подробности акции.
Другие профессии и курсы
Data Science и Machine Learning
Python, веб-разработка
Мобильная разработка
Java и C#
От основ — в глубину
А также
