Search code examples
cubuntubuffer-overflow

Buffer overflow vulnerability lab


I am working my way through a lab to demonstrate a buffer over flow exploit. I have it working but there's one area that I'm not quite understanding that I'm hoping someone can explain for me.

This is the code with the exploit:

/* Vunlerable program: stack.c */
/* You can get this program from the lab’s website */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(char *str)
{
  char buffer[24];
  /* The following statement has a buffer overflow problem */
  strcpy(buffer, str); ➀
  return 1;
}
int main(int argc, char **argv)
{
  char str[517];
  FILE *badfile;
  badfile = fopen("badfile", "r");
  fread(str, sizeof(char), 517, badfile);
  bof(str);
  printf("Returned Properly\n");
  return 1;
}

One step of the lab is to determine the size of the memory allocated to the buffer[24]. To do this what I have done is run gdb on the bof function and I can see that the memory allocated on my system is 0x20 which is 32 bits.

If I change size of buffer I can run gdb and find the memory slot allocated. But should I be able to tell how much memory would be allocated to buffer[24] without gdb? If I change to buffer[8] should I know at a glance what the memory block on a 32 bit system is, or does it vary on the system? And if I should know can someone explain how.


Solution

  • This depends on the target platform, compiler and compile flags.

    For example, GCC 7.2 x86 in debug mode (-O0) aligns stack frames on a 16-byte boundary and allocates a frame pointer (ebp).

    Example: (godbolt link)

    bof(char*):
            push    ebp                   ; -4
            mov     ebp, esp           
            sub     esp, 40               ; -40
            sub     esp, 8                ; -8
            push    DWORD PTR [ebp+8]     ; -4
            lea     eax, [ebp-32]         ; 32 bytes to top of stack frame
            push    eax                   ; -4
            call    strcpy                ; stack is aligned to 16 bytes (-64)
            add     esp, 16
            mov     eax, 1
            leave
            ret
    

    With optimization on (-O2) the frame pointer is omitted but the stack is still aligned on 16 bytes (godbolt link):

    bof(char*):
            sub     esp, 52               ; -52
            push    DWORD PTR [esp+56]    ; -4
            lea     eax, [esp+20]         ; 36 bytes to top of stack frame
            push    eax                   ; -4
            call    strcpy                ; stack is aligned to 16 bytes (-64)
            mov     eax, 1
            add     esp, 60
            ret
    

    With a forced 4-byte stack alignment (-O2 -mpreferred-stack-boundary=2) (godbolt link):

    bof(char*):
            sub     esp, 24               ; -24
            push    DWORD PTR [esp+28]    ; -4
            lea     eax, [esp+4]          ; 24 bytes to top of stack frame
            push    eax                   ; -4
            call    strcpy
            mov     eax, 1
            add     esp, 32
            ret
    

    With stack protector on (-O2 -fstack-protector-all) (godbolt link):

    bof(char*):
            sub     esp, 52                      ; -52
            mov     eax, DWORD PTR gs:20
            mov     DWORD PTR [esp+36], eax      ; stack check value at -16 (-52+36)
            xor     eax, eax
            push    DWORD PTR [esp+56]           ; -4
            lea     eax, [esp+16]                ; 40 bytes to top of stack frame, leaving exactly 24 bytes to check value
            push    eax
            call    strcpy
            add     esp, 16
            mov     edx, DWORD PTR [esp+28]
            xor     edx, DWORD PTR gs:20
            jne     .L5
            mov     eax, 1
            add     esp, 44
            ret
    .L5:
            call    __stack_chk_fail
    

    Other compilers might have entirely different results.

    In real life, a buffer overflow is exploited in assembly mode by analyzing instructions and counting the bytes to the function's return address, so it doesn't matter what the source code was or how it was compiled (this info is often unavailable anyway).