Простое переполнение буфера для перенаправления выполнения программы

Прежде всего, вам нужно знать, какова цель реестра EIP. EIP расшифровывается как Extended Instruction Pointer, и его цель — указать адрес, по которому должна быть выполнена следующая инструкция.

Давайте напишем программу на C с двумя функциями, main и win.

Обратите внимание, что мы используем gets() для получения пользовательского ввода. Поиск в руководстве по gets(), ввод команды man gets в терминале показывает нам, что у него нет защиты от переполнения буфера.

Мы должны отключить ASLR:

sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'

Теперь давайте скомпилируем нашу программу на C с помощью следующей команды:

gcc -fno-stack-protector programname.c -o outputfilename

Опция «-fno-stack-protector» отключает защиту gcc от разрушения стека.

Мы можем использовать gdb для просмотра дизассемблированного кода нашей программы с помощью следующей команды:

gdb programname

Стандартный синтаксис Gdb — AT&T, мы можем изменить его на синтаксис Intel с помощью:

set disassembly-flavor intel

Разберем основную функцию и поставим точку останова.

Выполните его с помощью «r», введите «AAAAAAAAAAAA» в качестве ввода, и он достигнет точки останова. Теперь мы можем видеть стек с «x/32wx $rsp».

Символ «A» в шестнадцатеричном формате — это 0x41, в этом примере наш буфер начинается с 0x7ffffffdd20. Нам нужно знать, где находится EIP, введите «информационный кадр» или «if» в gdb.

В моем примере RIP расположен по адресу 0x7ffffffdd68. Цель состоит в том, чтобы перезаписать RIP адресом win(). Как я говорил ранее, наш буфер начинается с 0x7ffffffdd20, а наш RIP — с 0x7ffffffffdd68, поэтому, если мы вычтем адрес буфера из RIP, мы получим количество байтов, необходимых для получения RIP и его перезаписи. Мы можем сделать это с помощью gdb:

Как мы видим, нам нужно 72 байта заполнения. Теперь нам нужен адрес функции win, чтобы поместить ее в RIP. Введите «disas win».

Функция Win начинается с адреса 0x00005555555546ca. Теперь мы готовы написать наш эксплойт с помощью Python.

Вот код:

padding = "A"*72
eip = "\xca\x46\x55\x55\x55\x55\x00\x00"
print padding+eip

Первая строка заполняет 72 байта между буфером и RIP буквами A. EIP — это адрес функции win в обратном порядке из-за архитектуры с прямым порядком байтов.

Сохраните его и перенесите строку, сгенерированную этим скриптом, в другой файл с помощью:

python exploit.py > exp

Давайте проверим это в gdb.

Это сработало!

Изображение выше показывает нам, что RIP был перезаписан адресом функции win.

Это был мой первый пост, я старался сделать объяснения максимально понятными, так как я только начинаю заниматься реверс-инжинирингом и эксплуатацией. Я буду писать больше сообщений в соответствии с тем, что я узнаю по пути.