Пример программы на ассемблере для переполнения буфера стека - PullRequest
0 голосов
/ 25 мая 2018

Я пытаюсь написать пример программы, чтобы понять переполнение буфера стека, и у меня есть следующая программа.

overflow.s:

    .section .data
    .section .text
    .globl _start
    _start:
          call sum
          movl %eax, %ebx
          movl $15, %ebx
          movl $1, %eax
          int $0x80

         .type sum, @function
    sum:
         pushl %ebp        # save the current base pointer
         movl %esp, %ebp   # store current stack pointer to %ebp
         subl $4, %esp     # inc the stack pointer by 4 bytes for local variable 
         movl $5, -8(%ebp) # store value 5 from 8 bytes of %ebp 4 bytes beyond stack pointer
         addl $5, -8(%ebp) # add 5 to the value store beyond of stack pointer 
         movl -8(%ebp), %eax # store the value in %eax
         movl %ebp, %esp
         popl %ebp
         ret

собрать и связать программу:

   as -gstabs+ overflow.s -o oveflow.o
   ld overflow.o -o overflow
   ./overflow
   echo $?
   15 <============= the result

Я ожидал, что получу какой-нибудь мусор или segfault.но, похоже, работает как ожидалось.Таким образом, в функции sum, когда я увеличиваю указатель стека на 4 байта и когда я сохраняю значение 5 8 байтов из базового указателя, я ожидал, что это симуляция переполнения.Является ли приведенная выше программа неправильной, чтобы использовать пример переполнения буфера стека.

1 Ответ

0 голосов
/ 25 мая 2018

Память ниже %esp может быть засорена асинхронно (обработчиком сигнала 1 ), но поведение вашей программы не зависит от значений, которые вы читаете / записываете с addl $5, -8(%ebp)или movl -8(%ebp), %eax, в этом 4-байтовом слоте стека прямо под ESP.

В Linux не является ошибкой касаться памяти ниже ESP, вплоть до предела максимального размера стека (ulimit -s, по умолчанию 8192 КБ).Если память еще не отображена, отображение стека автоматически расширяется, чтобы отобразить все страницы между ними и отображаемой в данный момент страницей стека с наименьшим адресом.(Или для стека потоков он уже будет полностью выделен, а не увеличен на лету. Но начальный стек процессов является специальным.)


Если вы запустили push вцикл (без pop или чего-либо еще, чтобы уравновесить его), стек будет расти до тех пор, пока ESP не уменьшится, чтобы указать на не отображенную страницу за пределами того места, где ядро ​​будет наращивать стек для вас.Тогда следующий push (или call или любой другой) будет segfault, и мы назовем это переполнением стека.


переполнение буфера будет, если вы это сделаетеsub $12, %esp чтобы зарезервировать место для int arr[3], но затем написал int arr[5]: это перезапишет ваш обратный адрес, так что возможный ret будет прыгать туда, куда злоумышленник хотел, чтобы вы прыгнули.

 # arg in EAX: how many array elements to store into arr[3]
 vulnerable_function:
    sub  $12, %esp
    mov  %esp, %ecx
.Lloop:
    mov  %eax, (%ecx)
    add  $4, %ecx
    dec  %eax
    jnz

    add  $12, %esp
    ret

Сноска 1 : вы не установили никаких обработчиков сигналов, поэтому (в Linux) ничто не может использовать стековую память асинхронно, и у вас есть неограниченная ниже ESP.

Но это особый случай, когда вы пишете законченную программу и не используете никаких библиотек, обычно вам просто нужно встроить небольшие функции, если дополнительные инструкции по резервированию и освобождению стекового пространства имеют нетривиальную стоимость.

...