tags: exploitation - x86 - linux
Return to libc или Эксплуатация, используя библиотечные вызовы libc
Return to libc или Эксплуатация, используя библиотечные вызовы libc
Intro
Мы будем использовать переполнение буфера, для спавна шелла в 32 битной системе, с выключенным ASLR и неисполняемым стеком. Чтобы полностью всё осознать, вы должны иметь иметь базовое знание языка Си и языка ассемблера.
ret2libc
Мы будем эксплуатировать программу из предыдущей части, выглядела она вот так
void win()
{
printf("WINNER\n");
return;
}
void func1()
{
char buffer[64];
gets(buffer);
printf("Your input = %s\n", buffer);
return;
}
int main(int argc, char **argv)
{
func1();
printf("end of main()\n");
return 0;
}
Будем все также переполнять буфер в функции func1()
.
Способ эксплуатации ret2libc используется, если существует запрет на исполнение в стеке. Вместо того, что вызывать код на стеке, мы будем спавнить шелл, используя функции библиотеки libc, в частности вызов system("/bin/sh")
. В прошлой части мы перезаписывали адрес возврата адресом функции win()
. Здесь, тоже самое, только мы должны перезаписать адресом функции system()
для того, чтобы открыть шелл.
Откуда нам взять это адрес? Дело в том, что во время работы любой программы на Си в GNU/линуксе, в адресное пространство этой программы, маппится стандартная библиотека libc. Эта библиотека содержит код функции system()
. Именно из libc мы и будем брать этот адрес. Мы можем запустить нашу программу в gdb и командой p system
получить адрес функции в libc.
Мы в начале нашли путь к конкретной библиотеки, используемой нашей программой, с помощью ldd
. Потом внутри нее нашли смещение system()
простым грепом (адрес 0003cd10). Так как у нас отключен ASLR, мы можем сложить базовый адрес и смещение, и получить абсолютный адрес функции system()
(в моем случае - 0xf7e1cd10
).
Адрес для переполнения у нас есть. Но чтобы открыть шелл, нам необходимо передать строку "/bin/sh"
в system()
. Как вы знаете, аргументы функций в 32 битной системе, передаются через стек. А значит нам надо поместить на стек адрес строки "/bin/sh"
. Откуда ее взять? Брать мы ее будем из все той же libc, простым strings
Это смещение до строки “/bin/sh” в libc. Теперь нам необходимо найти базовый адрес, по которой библиотека загружена. Для этого открываем нашу программу в gdb и командой находим этот адрес
Складываем их, и так как у нас отключен ASLR, мы получаем абсолютный адрес нашего аргумента (0xf7de0000 + 17b8cf = F7F5 B8CF).
Теперь внимательно посмотрим на следующую картинку
1- Это изначальное состояние нашего стека. На вершине лежит адрес возврата ret, который мы перезаписываем, далее ebp (на него в этих частях забиваем) и сам буфер.
2 - Здесь мы произвели переполнение. Перезаписали адрес возврата на вызов функции system, что и было нашей изначальной целью
3 - Мы также не должны забывать, что перед вызовом любой функции, мы должны положить на стек входные аргументы args и адрес возврата.
4 - В итоге наш стек должен выглядеть так. Адресом возврата для system() мы выбрали функцию exit() (ее адрес мы находим также, как и system()), чтобы мы могли корректно выйти из шелла. А в качестве аргумента наша строка /bin/sh.
Все просто! В итоге получаем такой пейлоад (помните, что все адреса в payload мы вставляем наоборот, так как little endian) . И этот пейлоад открывает нам шелл!
Вверх