Я присоединяюсь к этому процессу.
Проиграв некоторое время ролик, отладчик остановится на BP.
Я трассирую с помощью клавиши F7 и вижу, что в регистре EDX находится адрес БУФЕРА.
Я щелкаю на маленькую стрелку рядом с регистром EDX, которая переносит фокус в листинг.
Сейчас я делаю правый щелчок в стеке на этих данных и создаю массив из 32 байтов в десятичной системе.
У меня получается вот так.
Мы устанавливаем BP на запись в первом DWORD буфера, чтобы увидеть когда программа остановится заполнив буфер внутри функции STREAM_READ.
После нажатия на RUN, отладчик останавливается в библиотеке MSVCRT на инструкции REP MOVSD, копируя данные в буфер.
Через меню DEBUGGER → DEBUGGER WINDOWS → MODULE LIST появляется список модулей и там я ищу библиотеку MSVCRT.DLL.
Я делаю правый щелчок и выбираю пункт ANALIZE MODULE, и когда анализ закончится, я выбираю пункт LOAD DEBUG SYMBOLS, и теперь функция выглядит лучше. Мы можем увидеть её в стеке вызовов где мы находимся сейчас.
Теперь делаем так: DEBUGGER → DEBUGGER WINDOWS → STACK TRACE.
Теперь мы внутри функции MEMCPY и видим откуда она вызывается.
На самом деле, инструкция REPS MOVS копирует данные из источника, на который указывает регистр ESI в регистр EDI, который является назначением. А в регистре ECX хранится количество копируемых двойных-слов. Давайте посмотрим куда указывает ESI. Для этого делаем щелчок на стрелке, которая находится рядом с ESI, но теперь нужно сфокусироваться на режиме HEX DUMP, чтобы увидеть эти данные там.
Это то, что функция копирует в БУФЕР. Давайте откроем файл .TY в HEX редакторе и сделаем следующее.
Давайте выделим эти 32 байта и сделаем EDIT → EXPORT DATA, чтобы скопировать байты, которые отмечены, в желаемый формат.
Я думаю, что так они будут выглядеть лучше.
Итак, мы уже нашли байты, которые программа читает из файла. Мы знаем, что 14-15-16 и 17 байты - это те байты, из которых будет создаваться нужное значение. Программа добавляет к значению 8 и делает деление, а потом приходит к нужному значению. Давайте посмотрим что у нас есть в этом файле.
Нужные нам байты - 00 00 00 02. Давайте установим BP так, чтобы отладчик остановился, когда происходит возврат из функции STREAM_READ снова в библиотеку LIBTY_PLUGIN.
Я запускаю отладчик снова, потому что IP был отключен.
Сейчас буфер будет здесь.
Я могу скопировать его в HEX DUMP и добавить значение 0x14 в адрес буфера и я увижу, что это значение 00 00 00 02, которое мы и видели в файле.
Давайте будем трассировать, чтобы увидеть, что программа делает с этими данными.
Мы видим, что все эти вычисления нужны, чтобы создать переменную типа DWORD и переместить её в регистр EDI. Затем к этому регистру прибавляется значение 8.
Позже программа будет исполнять инструкцию IDIV. Давайте пойдем по этому адресу.
Здесь, это байт 0x0A, который получился из байта 0x02. Он был прочитан из файла и программа прибавила к нему значение 8. Поэтому результат равен 0xA.
IDIV - это знаковое деление. Инструкция разделит регистр EDX:EAX на размер, чтобы скопировать, который не будет изменен. Проблема заключается в том, что если я увеличу размер, чтобы скопировать больше, деление будет давать мне результат - нуль и это значение, пойдёт в функцию MALLOC после умножения на 16. Поэтому мы должны хорошо постараться с этим делением, чтобы результат не был равен 0.
Регистр EDX:EAX сейчас равен 00000000:00000148 и это значение делится на 0x0A. Если мы увидим в файле значение 0x148, то оно близко к значению 00000002.
Если я увеличу это значение до 0x02, мне также придется увеличить значение 0x148, чтобы деление не было равно нулю. Сделаем это.
Таким образом, мы увидим, достигает ли программа функции STREAM_READ с размером больше чем 8, чтобы переполнить буфер. Мы снова спровоцируем переполнение с этим измененным файлом.
Здесь программа создаёт число 0x4647 в регистре EDI. Затем прибавляет к нему 8.
Затем программа исполнит инструкцию IDIV 0000000:AA48, которая поделит это значение на число 0x464F.
Результат деления будет в регистре EAX и он равен 2.
Это максимальное значение, которое будет умножено на 16 и будет передано функции MALLOC. Поскольку мы не эксплуатируем переполнение кучи, во время выделения всё будет хорошо.
Так что программа вызывает функцию MALLOC с аргументом 0x20. Этот размер будет выделяться без проблем.
Указатель попадёт в блок, где есть уязвимость, со значением переменной SIZE_A_COPIAR равной 0x464F, которая очевидно больше чем 8. В пропатченной версии, программа будет игнорировать такое значение и переполнения не случится.
Я установил BPs на буфер. Регистр ECX указывает на него. Я иду туда и устанавливаю аппаратную BP на чтение и запись для того, чтобы программа остановилась, когда начнёт заполняться буфер.
Я нажимаю F9 для того, чтобы отладчик остановился, когда программа копирует данные в буфер.
Регистр ECX копирует 1192 DWORDS, так как REP MOVSD это REPEAT MOV DWORDS. Поэтому общая сумма, которая будет записана в 32-х байтовый буфер равна 0x1192 x 4 т.е. 0x4648. Это сумма исходит из округления числа 0x4647. Я поместил это значение в файл.
Я смогу перейти к инструкции RET, потому что программа может перезаписать буфер из-за размера, который она должна скопировать в буфер.
Я командую RUN TILL RETURN или CTRL + F7 и возвращаюсь в главную функцию, где расположен буфер, когда программа доходит до RET. Программа должна вызвать крах.
Я устанавливаю в функции BP на инструкцию RET и выключаю все другие BPs.
Я вижу, что стек разрушен, потому что я перезаписываю там все данные. Я иду в HEX VIEW и нажимаю маленькую стрелку рядом с регистром ESP.
И ищу эти байты в файле.
Это адреса, в которые программа будет передавать выполнение, так как мы перезаписываем ими адрес возврата. Я изменяю эти байты на такие:
Сейчас я запускаю VLC c этим измененным файлом.
Готово. Если сейчас я запущу программу, я возьму под контроль EIP, который является целью нашего POC. Некоторые POC не делают этого. Они просто разрушают программу.
Если всё хорошо, этот POC можно эксплуатировать. Позже мы увидим, как продолжить с эксплуатацией этого примера. В следующих частях, мы будем продолжать работать с теорией, которую я опустил и некоторыми простыми примерами, запрограммированными мной для практики. Я уже так много работаю )).
Нужно заметить, что расширение файла должно быть TY. Если мы его изменим, программа не попадет в уязвимую часть.
До встрече в 32 части.
=====================================================
Автор текста: Рикардо Нарваха - Ricardo Narvaja (@ricnar456)
Перевод на английский: IvinsonCLS (@IvinsonCLS)
Перевод на русский с испанского+английского: Яша_Добрый_Хакер(Ростовский фанат Нарвахи).
Перевод специально для форума системного и низкоуровневого программирования — WASM.IN
25.02.2018
Версия 1.0
Введение в реверсинг с нуля, используя IDA PRO. Часть 31. Часть 2.
Дата публикации 25 фев 2018
| Редактировалось 26 фев 2018