Решаем HACK ME

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В данной статье мы выполним задание, подготовленное в образовательных целях. В данной статье будут использоваться следующие инструменты:

  • Radare2;

  • Frida.

В ходе выполнения мы познакомимся с CVE-697 и научимся захватывать функции при помощи динамического инжекта в бинарные файлы.

Знакомство с подопытным

Программа, которую мы сегодня будем ковырять, написана на c++ и скомпилирована под ОС Windows. Перед тем как запустить программу, ознакомимся с readme файлом.

Разведка получила программу, которая используется в устройстве дистанционного управления. На обезвреживание устройства отведено меньше одной минуты. Для деактивации устройства необходимо ввести пятизначный пароль состоящий только из цифр. Так же нам известно, что программист оставил уязвимость CVE-697 в коде, что позволит отложить время срабатывания на один час.

Задание: узнать пароль для обезвреживания.

Задание есть, давайте запустим программу.

Запускаем программу

Пробный запуск программы.
Пробный запуск программы.

После запуска программы мы видим Time1, Time2 и предложение ввести пароль. Обратите внимание, что Time1 совпадает с системным временем.

Когда системное время покажет 49 минут, что совпадает с Time2, программа выдает сообщение BOOM!!!

Сообщение в случае истечения одной минуты.
Сообщение в случае истечения одной минуты.

Если мы попытаемся ввести пароль, программа вернет нам грустный смайлик в знак того, что пароль мы ввели неверный.

Сообщение о не правильном пароле.
Сообщение о не правильном пароле.

В задании сказано, что программа имеет CVE-697, которая позволит нам отложить время срабатывания на один час. Данная уязвимость означает, что в программе не корректно сравниваются объекты, что может привести к нарушению безопасности продукта.

Поскольку для отсчета одной минуты программа опирается на системное время, давайте попробуем перепрыгнуть Time2 путем изменения системного времени на компьютере.

  • Запускаем программу;

  • Меняем системное время на 2 минуты вперед;

  • Ждем реакции;

  • Видим, что через минуту сообщение BOOM!!! не появилось.

Такими не хитрыми действиями мы воспользовались уязвимостью не корректного сравнения, что дает нам один час пока минуты в системном времени снова не будут равняться Time2.

Переходим к следующей части задания. Для того, что бы узнать пароль мы воспользуемся фреймворком radare2 для реверса статического кода.

Начинаем реверс

Запускаем radare2 и передаем в качестве первого параметра наш HelloWorld.exe.

radare2 ./HelloWorld.exe

Что бы радар проанализировал наш бинарник вводим команду aaaa.

Дальше начинается поиск места, где программа сравнивает пароль. Поиск по строкам показал, адрес, где программа показывает сообщение You win!!. Сравнение введенного пароля происходит со строкой 10141042524399622065.

Скриншет из radare2
Скриншет из radare2

Из readme файла мы знаем, что пароль имеет длину 5 цифр, так же выше мы видим строку call method str::hash..., что намекает нам на использование хеширования. Значит пароль лежит в хешированном виде и нам придется заняться перебором.

На этом моменте мы можем начать гуглить, что бы выяснить какой алгоритм хеширования используется для перебора в hashcat или пойти моим путем.

Брутфорсим пароль при помощи Frida

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

Внутренности str::hash..
Внутренности str::hash..

Тут мы видим, что перед ret вызывается функция std::_Hash_impl::hash. Данная функция принимает 3 параметра.

Перехватываем функцию

Теперь мы знаем адрес функции, которая предположительно возвращает результат хеширования. Давайте узнаем, какие параметры она принимает на вход.

Для этого я буду использовать фриду, а именно Interceptor.replace.

Подключаемся к нашей программе.

var moduleData = Process.getModuleByName("HelloWorld.exe");

Говорим по какому адресу хотим перехватить функцию.

var Ihash2 = moduleData.base.add("0x7ea0")

Указываем типы данных, которые будем передавать в функцию и их количество. В нашем случае будем работать с указателями.

const Fhash2 = new NativeFunction(Ihash2, 'pointer', ['pointer','pointer', 'pointer']);

Дальше перехватываем функцию и передаваемые в нее параметры.

Interceptor.replace(Ihash2, new NativeCallback((po1, po2, po3) => {
	const fd = Fhash2(po1, po2, po3); 
  console.log(po1,po2,po3)
	return fd;
}, 'pointer', ['pointer','pointer', 'pointer']));

Здесь переменные po1, po2, po3 - те самые три параметра, которые мы передаем в функцию. Подключившись фридой к нашему HelloWotld.exe при помощи команды frida -f HelloWorls.exe -l exp.js --no-pause, пытаемся ввести пароль и видим в консоли три указателя, которые нам удалось перехватить. Один из них - наш пароль, который мы вводим.

Пробуем прочитать значения в указателях при помощи readAnsiString() .

console.log(po1.readAnsiString(), po2.readAnsiString(), po3.readAnsiString())

Таким образом мы узнаем, что po1 - интересующий нас параметр, который содержит введенный пароль. Переменная fd содержит результат хеширования в хексах.

Теперь составим массив из всех возможных комбинации паролей, пройдемся по нему циклом, внутри которого будем вызывать функциюFhash2 меняя параметр po1 на значения из массива.

Готовый скрипт

var moduleData = Process.getModuleByName("HelloWorld.exe");
//массив всех комбинаций
arr = ["11111", ... "00000"];
//адресс функции хеширования
var Ihash2 =  moduleData.base.add("0x7ea0")

const Fhash2 = new NativeFunction(Ihash2, 'pointer', ['pointer','pointer', 'pointer']);
Interceptor.replace(Ihash2, new NativeCallback((po1, po2, po3) => {
	
	var truepass = "";
	//проходимся по всему циклу
	arr.forEach(function(item, i, arr) {
		// алоцируем пароль получаем адресс
		var pp = Memory.allocUtf8String(item);
		//передаем адресс в качестве пароля
		const fd = Fhash2(pp, po2, po3); 
		//сравниваем получившиеся хеши с найденным  
    //8CBC387246F857B1 - 10141042524399622065 (найденный хеш в хексах)
		if (fd.toString() == "0x8cbc387246f857b1"){
			console.log('\n  правильный пароль: ' + fd , item );
			truepass = item;
		}
	});
	//подсовываем правильный пароль
	var pp = Memory.allocUtf8String(truepass);
	const fd = Fhash2(pp, po2, po3); 
	return fd;
}, 'pointer', ['pointer','pointer', 'pointer']));

Вот такой скрипт для фриды у нас получился, давайте запустим и проверим, что пароль переберется успешно.

Результат перебора пароля
Результат перебора пароля

На скриншете видно, что нам удалось найти правильный пароль, так же видим сообщение You win!

Материалы из статьи
  • https://cwe.mitre.org/data/definitions/697.html

  • https://frida.re/docs/javascript-api/

  • https://github.com/notrobot1/hackme/tree/main/fBJ_nXQLGp0

Источник: https://habr.com/ru/post/674630/


Интересные статьи

Интересные статьи

Создание ботов - довольно заезжанная тема, но все уроки, статьи и различного рода документация дают информацию только о том, как построить одноуровневого бота без возможности создания древа из различн...
Продолжаю публикацию решений отправленных на дорешивание машин с площадки HackTheBox. Надеюсь, что это поможет хоть кому-то развиваться в области ИБ. Подключение к л...
Если вы хотя бы отдалённо интересуетесь играми и не прожили последнюю пару лет в тайге, то, вероятно, слышали что-нибудь о Cyberpunk 2077. После долгого ожидания она наконец вышла! И в ...
Много всякого сыпется в мой ящик, в том числе и от Битрикса (справедливости ради стоит отметить, что я когда-то регистрировался на их сайте). Но вот мне надоели эти письма и я решил отписатьс...
Периодически мне в разных вариантах задают вопрос, который «в среднем» звучит так: «что лучше: заказать интернет-магазин на бесплатной CMS или купить готовое решение на 1С-Битрикс и сделать магазин на...