
Название: Bypass
Категория: Reversing
Сложность: Easy
Ссылка: https://app.hackthebox.com/challenges/Bypass
Краткое описание
Описание челенджа гласит: «The Client is in full control. Bypass the authentication and read the key to get the Flag.» Это сразу же дает нам подсказку, куда двигаться. Нам дан .NET-файл с аутентификацией на стороне клиента. Решение — это целое путешествие через неудачные попытки патчинга в IDA Pro, после чего я переключился на более подходящий инструмент dnSpy. С его помощью удалось извлечь зашифрованный ресурс, расшифровать его с помощью скрипта на Python, чтобы найти пароль, а затем сделать простой патч IL-кода, чтобы обойти первую невыполнимую проверку и наконец-то получить флаг.
Разведка (как я смотрел формат)
Нам дан .exe файл на 9 кб. Первое, что я сделал — закинул его в IDA Pro, чтобы изучить изнутри и обойти проверку. Сразу в глаза бросилось, что это Microsoft .NET assembly. Названия функций тоже порадовали:
__.cctor seg000 00000000 00000006 R . . . . . . . . . _0__0 seg000 00000020 0000002A R . . . . . . . . . _0__1 seg000 00000050 00000029 R . . . . . . . . . ...
Моя теория была, что это и есть шифрование и то, как оно собирается для проверки.
Но при последующем анализе я выяснил, что происходит обфускация строк. Все строки (приглашения к вводу, ошибки, пароль и флаг) зашифрованы и помещены во внедрённый ресурс с именем "0". При запуске программа расшифровывает этот ресурс с помощью AES (RijndaelManaged в коде).
Логика состоит из двухэтапной проверки:
Первая проверка, которую невозможно пройти честным путем (это и есть "Bypass").
Вторая проверка, где нужно ввести правильный пароль.
Ключевой метод '0'::'1' всегда возвращает false вне зависимости от ввода, потому что в IL-коде жёстко прописана инструкция ldc.i4.0 (загрузить константу 0) перед возвратом.
Стратегия
Моя стратегия развивалась методом проб и ошибок, но финальный план был таким:
Попытаться пропатчить бинарник с помощью IDA Pro, чтобы обойти проверки.
После эпичного провала переключиться на более подходящий инструмент —
dnSpy.В
dnSpyизвлечь зашифрованный ресурс.Написать скрипт на Python, чтобы расшифровать ресурс и получить пароль.
Пропатчить IL-код в
dnSpyдля обхода первой проверки.Запустить пропатченный файл, ввести пароль и забрать флаг.
Эволюция скриптов и патчинга (как я думал и исправлял ошибки)
А вот тут начинается самое интересное.
Попытка 1: Патчинг байтов в IDA Pro
Моя первая идея — пропатчить инструкцию brfalse.s loc_36, которая отвечает за проваленную проверку. Я нажал F2, выбрал патч по байтам и увидел это:
2C 0A 00 28 04 00 00 06 00 00 2B 13 00 7E 08 00
Я поменял её на инструкцию nop:
00 00 00 28 04 00 00 06 00 00 2B 13 00 7E 08 00
Затем перешёл ко второй проверке, нашёл brfalse.s loc_C1 и сделал то же самое.
Было: 2C 1E 00 7E 0D 00 00 04 7E 03 00 00 04 7E 0E 00
Стало: 00 00 00 7E 0D 00 00 04 7E 03 00 00 04 7E 0E 00
Сохранил модификацию и... Необработанное исключение: System.InvalidProgramException: Компилятор JIT обнаружил внутреннее ограничение. Ладно, не сработало.
Попытка 2: Ещё немного патчинга в IDA
Может, другой патч сработает? Я нацелился на логику сравнения:
В hex: 06 07 28 04 00 00 0A 0C 08 2C 1E 00 7E 0D 00 00
Мой патч: 17 08 09 00 00 00 00 00 00 2C 1E 00 7E 0D 00 00
В результате... Ничего.
Попытка 3: Ладно, последняя попытка с IDA
Попробуем заменить условный переход на pop (байт 26), чтобы снять результат проверки со стека, и nop (байт 00), чтобы заполнить место.
Первый байт brfalse.s (2C) я поменял на 26 (pop), а второй (смещение) на 00 (nop).
Результат:
Enter a username: ф Enter a password: ф Необработанное исключение: System.InvalidProgramException: Среда выполнения Common Language Runtime обнаружила недопустимую программу. в 0.2() в 0.0()
Опять неудача.
Переломный момент: прощай, IDA
В этот момент мне стало ЛЭНЪ дальше работать с этим IDA Pro, поэтому я решил упростить себе жизнь в 1000 раз и использовать dnSpy, который подходит для этого намного лучше.
В dnSpy код был чистым и понятным. Я сразу нашёл ресурс "0" и сохранил его как resource.bin. Теперь надо расшифровать. Использовал вот такой скрипт на Python:
from Crypto.Cipher import AES def read_net_string(data, offset): length, len_bytes = 0, 0 shift = 0 while True: byte = data[offset + len_bytes] length |= (byte & 0x7F) << shift len_bytes += 1 if (byte & 0x80) == 0: break shift += 7 str_start = offset + len_bytes return data[str_start:str_start + length].decode('utf-8'), str_start + length with open("resource.bin", "rb") as f: encrypted_data = f.read() key = encrypted_data[0:32] iv = encrypted_data[32:48] ciphertext = encrypted_data[48:] cipher = AES.new(key, AES.MODE_CBC, iv) decrypted_padded = cipher.decrypt(ciphertext) padding_len = decrypted_padded[-1] decrypted = decrypted_padded[:-padding_len] strings = [] offset = 0 while offset < len(decrypted): s, offset = read_net_string(decrypted, offset) strings.append(s) password = strings[3] print(f"password: {password}")
И он сработал!
┌──(vt729830㉿vt72983)-[~/6/1/1/1] └─$ python3 1.py password: ThisIsAReallyReallySecureKeyButYouCanReadItFromSourceSoItSucks
Финальный патчинг в dnSpy
Теперь патчим первую проверку. Декомпилированный код был прекрасен:
public static void 0() { bool flag = 0.1(); // Это всегда возвращает false bool flag2 = flag; if (flag2) { 0.2(); } else { Console.WriteLine(5.0); 0.0(); } }
Я попытался просто отредактировать C#-код, поменяв bool flag = 0.1(); на bool flag = true;. Но... снова неудача)) Он выдал миллион ошибок компиляции.
Поэтому я пошёл редактировать IL-код («Edit IL Instructions...»). Нашёл инструкцию brfalse.s и просто поменял её на pop. Скомпилировал, сохранил и запустил.
Enter a username: ThisIsAReallyReallySecureKeyButYouCanReadItFromSourceSoItSucks Enter a password: ThisIsAReallyReallySecureKeyButYouCanReadItFromSourceSoItSucks Please Enter the secret Key:
И вывод... Очень... Очень информативен...? Он просто закрылся. Вероятно, я что-то сделал не так.
Моя догадка была в том, что он выводит флаг и моментально закрывается. Я был прав. Запуск через cmd в Windows решил проблему.
Результат
Запускаю финальный пропатченный .exe из cmd и ввожу найденный пароль:
C:\Users\vt72983\Downloads\Bypass>Bypass.exe Enter a username: ThisIsAReallyReallySecureKeyButYouCanReadItFromSourceSoItSucks Enter a password: ThisIsAReallyReallySecureKeyButYouCanReadItFromSourceSoItSucks Please Enter the secret Key: ThisIsAReallyReallySecureKeyButYouCanReadItFromSourceSoItSucks Nice here is the Flag:HTB{**********}
И вот так я получил ещё один простой флаг.

Это лишь одно из моих приключений на Hack The Box. Больше решений и райтапов вы можете найти в моём репозитории на GitHub: vt72983/HTB-Writeups.
Оригинальный markdown-файл с решением этой задачи лежит здесь: Bypass/README.md.
