what's happened when process is attacked by "stack buffer overflow"?

Viewed 34

I'm a student learning computer security. Recently, I learned stack buffer overflow on c.
I understood its concepts and run sample codes written by c.

void main(){
    char buf[] = "\xeb\x0b\x31\xc0\xb0\x0b\x31\xd2\x31\xc9\x5b\xcd\x80\xe8\xf0\xff\xff\xff/bin/sh\x0";
    int* p;
    p = (int*)&p + 2;
    *p = (int)buf;
    return;
}

Runtime Environment

  • Architecture: i686
  • OS: ubuntu 16.04 32bit
  • Compiler: gcc
  • Turn off ASLR(sysctl -w kernel.randomize_va_space=0)
  • Options: gcc -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector

But I confuse what stack is saved and which memories are overlapped.
Above binary code, "\xeb\x0b\x31\xc0\xb0\x0b\x31\xd2\x31\xc9\x5b\xcd\x80\xe8\xf0\xff\xff\xff/bin/sh\x0", the same assembly code is

.global main

main:
    jmp strings

start:
    xor %eax, %eax
    movb $0xb, %al

    xor %edx, %edx
    xor %ecx, %ecx
    
    popl %ebx
    int $0x80

strings:
    call start
    .string "/bin/sh"

means execve("/bin/sh", NULL, NULL);.
When buffer overflow occurs, the binaries are overlapped return addresses of main on stack. But, I'm understood to be that the stack stores data s.t local variables, previous frame pointers, and return address.
I think the above binaries are not data, actually instructions. If so, why is this valid? The stack stores instructions and executes one-by-one by popping them? Or I misunderstand something?
And if the stack stores instructions, how do previous stack frame pointers(fp) and return addresses(ra) work?
I learned that previous function's stack frame address is stored in fp and next instruction's address on code area is stored in ra. So, when called function is terminated, sp is popped and then ra does to restore previous function state and run next instruction. Is it correct? Or I misunderstand something?
I want to know really this..
Thank you for your help.

1 Answers

Data are instructions are instructions are instructions. The stack is memory is memory is memory.

That's just that. Since the stack is ordinary memory, just like what you get with malloc, only growing downward and used implicitly by some instructions, you can put any data on the stack.
Since instructions are data, it follows that you can put instructions on the stack.

This particular exploitation works by overwriting the return address with a specific value and everything above it with a sequence of instructions.
That's why you need to tell GCC to make the stack executable (the code is on the stack) and not to generate a canary (both of these protections will suffice to prevent the attack) and also you need to tell Linux not to randomize the process address space layout (or the specific, fixed, value used to overwrite the return address won't work).

The fp and ra thing is most likely for a RISC architecture, x86 doesn't have such registers.

The execution flow is redirected when main returns (with ret), that's what ret does.
Look in Intel's manuals how the call/ret pair works and then see it in practice by just stepping into a call with a debugger.
Make sure you understand the calling convention and keep an eye on the stack every time you step.

Related