Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify return address on stack

I looked at the basics of buffer overflow vulnerabilities and tried to understand how the stack is working. For that I wanted to write a simple program which changes the address of the return address to some value. Can anybody help me with figuring out the size of the base pointer to get the offset from the first argument?

void foo(void)
{
    char ret;
    char *ptr;

    ptr = &ret; //add some offset value here 
    *ptr = 0x00;
}

int main(int argc, char **argv)
{
    foo();

    return 1;
}

The generated assembler code looks as follows:

    .file   "test.c"
    .text
    .globl  foo 
    .type   foo, @function
foo:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16 
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    leaq    -9(%rbp), %rax
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    movb    $0, (%rax)
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret 
    .cfi_endproc
.LFE0:
    .size   foo, .-foo
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16 
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    call    foo 
    movl    $1, %eax
    leave
    .cfi_def_cfa 7, 8
    ret 
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (GNU) 4.7.1 20120721 (prerelease)"
    .section    .note.GNU-stack,"",@progbits

The relevant part of the foo frame segment should look like this:

[char ret] [base pointer] [return address]

I have the position of the first one which is only 1 byte in size. Is it only 1 byte further to the base pointer or the size of a word as mentioned in http://insecure.org/stf/smashstack.html? And how do I get to know the size of the base pointer?

like image 462
fliX Avatar asked Sep 27 '12 21:09

fliX


People also ask

How is return address stored in stack?

Every time a CALL instruction is executed, its return address is pushed onto the stack. Every time a RETURN instruction enters the pipeline, the next address is popped off the stack and the processor continues fetching from the associated address seamlessly.

Is return address part of stack frame?

Return address contains the address of the instruction to return to. It's not otherwise stored anywhere else. Frame pointer is generally the previous stack pointers. The return address is the previous instruction pointer.

What is the need for storing the return address in the function call stack?

Functions of the call stack. As noted above, the primary purpose of a call stack is to store the return addresses. When a subroutine is called, the location (address) of the instruction at which the calling routine can later resume needs to be saved somewhere.

What is return address in MIPS?

In machine code, the return address, $ra for MIPS, is effectively a parameter to the subroutine — it tells the subroutine where to resume execution in the caller, where to return to. There are several ways to set the $ra register with a meaningful return address, though of course jal is by far the most common way.


2 Answers

You're not going to be able to do this in vanilla C, you don't have control of how the compiler lays out the stack frame.

In x86-64, the return address should be at %rbp + 8. You could use some inline assembly to get that (gcc syntax):

uint64_t returnaddr;
asm("mov 8(%%rbp),%0" : "=r"(returnaddr) : : );

Similarly for setting it.

Even that is a bit sketchy, as you don't know whether the compiler is going to set up %rbp or not. YMMV.

like image 155
Keith Randall Avatar answered Oct 08 '22 00:10

Keith Randall


Your basepointer is most likely just a pointer, so it has the size sizeof(int*). But there is also another value in between your variable ret and the base pointer. I would assume its value of a register (eax?). This would lead to something like the following, if you want an endless loop:

void foo(void)
{
    char ret;
    char *ptr;

    ptr = (char*)(&ret) + (sizeof(ret)  + 2*sizeof(int*)) ;
    *(int*)ptr -= 0x0c;
}

The return target which is modified assuming it has the size of a pointer (could differ for other instruction sets). By decrementing it, the return target is set to a point before the calling point of foo.

like image 27
Uli Klank Avatar answered Oct 08 '22 00:10

Uli Klank