Переполнение буфера: выполнить загруженный в память массив символов

Я изучаю этический взлом, и мне дали это в качестве упражнения. Я застрял на нем уже два дня.

Мы пишем программу, которая преднамеренно уязвима к «переполнению буфера».

#include <stdio.h>

void badf(int n, char c, char* buffer)
{

    char mycode[] = {
0xeb, 0x0f, 0xb8, 0x0b,
0x00, 0x00, 0x00, 0x8b,
0x1c, 0x24, 0x8d, 0x0c,
0x24, 0x31, 0xd2, 0xcd,
0x80, 0xe8, 0xec, 0xff, 
0xff, 0xff, 0x2f, 0x62,
0x69, 0x6e, 0x2f, 0x6c, 
0x73, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00
}; // 37 bytes

    int i;
    // Copy mycode array into buffer array
    for (i=0; i<n; i++)
    {
    buffer[i]=mycode[i];
    }

    // Overwrite Base Pointer
        buffer[37] = 0x00;
    buffer[38] = 0x00;
    buffer[39] = 0x00;
    buffer[40] = 0x00;
    // Overwrite Instruction Pointer
    buffer[41] = 0x90;
    buffer[42] = 0x83;
    buffer[43] = 0x04;
    buffer[44] = 0x08;
}

void f(int n, char c)
{
    char buffer[37];    

    badf(n,c,buffer);
}

void test()
{
    printf("test\n");
}

int main()
{
    f(37,0x00);
    return 0;
}

Массив mycode содержит "вредоносный" машинный код (на самом деле он просто вызывает execv с /bin/ls). badf — «уязвимая» функция. На данный момент вы можете видеть, что я перезаписываю базовый указатель на 0x00s и указатель инструкций на 0x08048390, который является адресом функции test(). Это работает, «тест» печатается на терминале.

Теперь мое следующее упражнение состоит в том, чтобы «использовать ddd, чтобы найти адрес вашего массива кода и изменить C, чтобы записать этот адрес поверх указателя инструкции, как вы делали на предыдущем шаге».

Чего я не понимаю, так это того, как я могу использовать ddd, чтобы найти адрес моего массива кода. Я легко нахожу адрес, по которому массив перемещается в БП:

   0x08048260 <badf+12>:        movb   $0xeb,-0x29(%ebp)
   0x08048264 <badf+16>:        movb   $0xf,-0x28(%ebp)
   0x08048268 <badf+20>:        movb   $0xb8,-0x27(%ebp)
.....

Или куда он копируется в буферный массив:

   0x080482f4 <badf+160>:       movl   $0x0,-0x4(%ebp)
   0x080482fb <badf+167>:       jmp    0x8048316 <badf+194>
   0x080482fd <badf+169>:       mov    -0x4(%ebp),%edx
   0x08048300 <badf+172>:       mov    0x10(%ebp),%eax
.....

Но, конечно, это не то, что мы ищем.

Как найти адрес указателя инструкций для выполнения загруженного машинного кода, записав его в массив буферов таким образом?

edit: ddd — это отладчик, который мы используем, также обратите внимание, что мы работаем с 32-битной версией Linux. Код компилируется с флагом -fno-stack-operator, отключающим автоматические проверки компилятором на переполнение буфера.


person Juicy    schedule 18.11.2013    source источник
comment
разбить на badf+12 и сбросить адрес ebp-0x29   -  person Michael M.    schedule 18.11.2013
comment
Но это адрес базового указателя нет? Я пробовал, но моя программа дает сбой, я не знаю, неправильный ли мой машинный код.   -  person Juicy    schedule 18.11.2013
comment
Я не думаю, что получаю правильный адрес, я вычислил bfff f427, посмотрев, где в стеке появляется 0xeb. Я думаю, что это должно быть неправильно. Есть ли в DDD команда или что-то еще для сброса адреса ebp-0x29?   -  person Juicy    schedule 18.11.2013


Ответы (2)


Поскольку вы копируете myCode в буфер, вы можете просто использовать сам buffer:

Предполагая машину с прямым порядком байтов:

// Overwrite Instruction Pointer
buffer[41] = (char)(((uintptr_t)buffer) >> 0);
buffer[42] = (char)(((uintptr_t)buffer) >> 8);
buffer[43] = (char)(((uintptr_t)buffer) >> 16);
buffer[44] = (char)(((uintptr_t)buffer) >> 24);
person Medinoc    schedule 18.11.2013
comment
Я пробовал именно это, но я получаю ошибку сегментации. Нужно ли учитывать прямой порядок байтов для вредоносного кода? - person Juicy; 18.11.2013

Я не знаю, как это сделать с помощью ddd, но вы можете изменить badf для печати адреса mycode с помощью оператора печати, подобного этому:

printf("mycode address: %p", (void *) mycode);

Посмотрите, что это напечатает, и просто напишите это в указатель инструкции

person Filipe Gonçalves    schedule 18.11.2013
comment
Спасибо за ваше предложение, однако я попробовал, и адрес mycode продолжает меняться при каждом выполнении. - person Juicy; 18.11.2013
comment
Тогда попробуйте метод medinoc в ответе ниже - person Filipe Gonçalves; 18.11.2013
comment
Я бы хотел, но мне действительно нужно знать, как найти этот адрес, а не просто использовать адрес буфера. Это нормально, что адрес кода начинается с 0xbf, потому что он находится в стеке? Большинство других адресов указателей команд, которые мы использовали в упражнении, начинались с 0x08, но можно ли ожидать 0xbf в этом случае? - person Juicy; 18.11.2013