Order Of Six Angles

Main Logo

A security researcher's blog about reverse-engineering, malware and malware analysis

Home | RU | Translations | Tools | Art | About

4 December 2019

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) . И этот пейлоад открывает нам шелл!

Вверх