
Название: 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.