Есть ли переполнение буфера helloworld для c ++? - PullRequest
2 голосов
/ 28 марта 2010

Я пробовал код, предоставленный этим вопросом , но он не работает.

Как создать переполнение, чтобы обернуть мою голову?

Обновление:

    .file   "hw.cpp"
    .section .rdata,"dr"
LC0:
    .ascii "Oh shit really bad~!\15\12\0"
    .text
    .align 2
.globl __Z3badv
    .def    __Z3badv;   .scl    2;  .type   32; .endef
__Z3badv:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    $LC0, (%esp)
    call    _printf
    leave
    ret
    .section .rdata,"dr"
LC1:
    .ascii "WOW\0"
    .text
    .align 2
.globl __Z3foov
    .def    __Z3foov;   .scl    2;  .type   32; .endef
__Z3foov:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    LC1, %eax
    movl    %eax, -4(%ebp)
    movl    $__Z3badv, 4(%ebp)
    leave
    ret
    .def    ___main;    .scl    2;  .type   32; .endef
    .align 2
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    call    __alloca
    call    ___main
    call    __Z3foov
    movl    $0, %eax
    leave
    ret
    .def    _printf;    .scl    2;  .type   32; .endef

Ответы [ 7 ]

3 голосов
/ 28 марта 2010

Это поможет скомпилировать пример из другого вопроса в сборку, чтобы вы могли понять, как устроен стек для вашего компилятора и процессора. +8 в примере может быть неправильным числом для вашей среды. Вам нужно определить, где адрес возврата хранится в стеке относительно массива, хранящегося в стеке.

Кстати, пример работал для меня. Я скомпилировал на Win XP с Cygwin, gcc версии 4.3.4. Когда я говорю, что это «работает», я имею в виду, что он запускал код в функции bad(), хотя эта функция никогда не вызывалась кодом.

$ gcc -Wall -Wextra buffer-overflow.c && ./a.exe
Oh shit really bad~!
Segmentation fault (core dumped)

Код действительно не является примером переполнения буфера, это пример того, что может случиться с плохим при использовании переполнения буфера.

Я не очень хорошо разбираюсь в сборке x86, но вот моя интерпретация того, как работает этот эксплойт.

$ gcc -S buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp           ;2
        movl    %esp, %ebp     ;3
        subl    $16, %esp      ;4
        movl    LC1, %eax      ;5
        movl    %eax, -4(%ebp) ;6
        leal    -4(%ebp), %eax ;7
        leal    8(%eax), %edx  ;8
        movl    $_bad, %eax    ;9
        movl    %eax, (%edx)   ;10
        leave
        ret

_main:
    ...
        call    _foo            ;1
    ...

Когда main вызывает foo (1), инструкция call помещает в стек адрес внутри main, чтобы вернуться к нему после завершения вызова foo. Загрузка в стек включает в себя уменьшение ESP и сохранение там значения.

Однажды в foo старое базовое значение указателя также помещается в стек (2). Это будет восстановлено, когда foo вернется. Указатель стека сохраняется в качестве базового указателя для этого кадра стека (3). Указатель стека уменьшается на 16 (4), что создает пространство в этом кадре стека для локальных переменных.

Адрес литерала "WOW \ 0" копируется в локальную переменную overme в стеке (5,6) - мне это кажется странным, если бы не копирование 4 символов в пространство, выделенное на стек? В любом случае, место, куда копируется WOW (или указатель на него), находится на 4 байта ниже текущего базового указателя. Таким образом, стек содержит это значение, затем старый базовый указатель, а затем адрес возврата.

Адрес overme помещается в EAX (7), а целочисленный указатель создается на 8 байт за этим адресом (8). Адрес функции bad помещается в EAX (9), а затем этот адрес сохраняется в памяти, на которую указывает целочисленный указатель (10).

Стек выглядит так:

     // 4 bytes on each row
ESP: (unused)
   : (unused)
   : (unused)
   : &"WOW\0"
   : old EBP from main
   : return PC, overwritten with &bad

Когда вы компилируете с оптимизацией, все интересные вещи оптимизируются как «бесполезный код» (который он есть).

$ gcc -S -O2 buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
3 голосов
/ 28 марта 2010

Вы можете использовать пример C, который вы разместили. В C это работает так же, как и в C ++.

Самый маленький читаемый ответ, который я могу придумать:

int main() {
    return ""[1]; // Undefined behaviour (reading past '\0' in string)
}
2 голосов
/ 28 марта 2010

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

#include <stdio.h>
#include <string.h>

int main() {
   char a[4] = {0};
   char b[32] = {0};

   printf("before: b == \"%s\"\n", b);

   strcpy(a, "Putting too many characters in array a");

   printf("after:  b == \"%s\"\n", b);
}

Возможный вывод:

before: b == ""
after:  b == " characters in array a"

Фактическое поведение программы: undefined , поэтому переполнение буфера также может привести к разным выводам, сбоям или отсутствию наблюдаемого эффекта.

2 голосов
/ 28 марта 2010

Как то так?

int main()
{
    char arr[1];
    arr[1000000] = 'a';
}
0 голосов
/ 10 марта 2011

Термин переполнение буфера точно означает доступ за концом буфера (небрежно нужно включить идею переполнение буфера тоже). Но есть целый класс «проблем безопасности памяти», связанных с переполнением буфера, указателями, массивами, выделением и освобождением, которые могут вызывать сбои и / или использовать возможности в коде. Смотрите C пример другой проблемы безопасности памяти (и наш способ ее обнаружения).

0 голосов
/ 28 марта 2010

В дополнение к отличной статье , на которую указывает Эрик , вы можете также ознакомиться со следующими материалами для чтения:

В следующей статье больше внимания уделяется переполнению кучи:

Это было скопировано из моего ответа здесь .

0 голосов
/ 28 марта 2010
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

void process_msg(const char *pSrc)
{
    char cBuff[5];
    strcpy(cBuff, pSrc);
}

void main()
{
    char szInput[] = "hello world!";
    process_msg(szInput);
}

Запуск этой программы в Visual Studio 2008 в режиме отладки выдает следующее сообщение:

Run-Time Check Failure #2 - Stack around the variable 'cBuff' was corrupted.

В этом примере массив стека 'cBuff' размещается в стеке и имеет размер 5 байт. Копирование данных указанного указателя (pSrc) в этот символ arrat (cBuff) перезаписывает данные фрейма стека, что приведет к возможному использованию.

Этот метод используется хакерами - они посылают специально созданный массив символов, который перезапишет указатель на адрес возврата в стеке и изменит его на желаемое место в памяти.

Так, например, они могут указать этот «обратный» адрес любому системному / программному коду, который откроет порт или установить соединение, и затем они получат ваш ПК с привилегиями приложения (много раз это означает root /administrator).

Подробнее на http://en.wikipedia.org/wiki/Buffer_overflow.

...