Сегодня, пока начинается наш курс по 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 hawkndives 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#
От основ — в глубину
А также