Search code examples
cexploit

Smashing the Stack - Trouble finding return address


I've been reading "Smashing the Stack for Fun and Profit" and seem to be encountering a problem similar to what others have run into the past; however I cannot figure out why my code is still not working.

What I'm trying to do:

Consider the code below:

void function1(int a, int b, int c){
    char buffer1[8];
    // char buffer2[10];
    int *ret;

    ret = (int *) buffer1 + 24;
    (*ret) += 7; 
}

void main() {
    int x;

    x = 0;
    function1(1,2,3);
    x = 1;
    printf("%d\n", x);
}

The goal of the example is to overwrite the return address of *function1 * and skip the line x = 1 in main. So, the program should output 0 instead of 1. However, my output is still 1. So I'm not sure where I'm going wrong.

Using gdb to calculate the return address and the offsets

From an objdump of the assembly:

00000000000006db <main>:
 6db:   55                      push   %rbp
 6dc:   48 89 e5                mov    %rsp,%rbp
 6df:   48 83 ec 10             sub    $0x10,%rsp
 6e3:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
 6ea:   ba 03 00 00 00          mov    $0x3,%edx
 6ef:   be 02 00 00 00          mov    $0x2,%esi
 6f4:   bf 01 00 00 00          mov    $0x1,%edi
 6f9:   e8 b2 ff ff ff          callq  6b0 <function1>
 6fe:   c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%rbp)
 705:   8b 45 fc                mov    -0x4(%rbp),%eax
 708:   89 c6                   mov    %eax,%esi
 70a:   48 8d 3d 93 00 00 00    lea    0x93(%rip),%rdi        # 7a4 <_IO_stdin_used+0x4>
 711:   b8 00 00 00 00          mov    $0x0,%eax
 716:   e8 45 fe ff ff          callq  560 <printf@plt>
 71b:   90                      nop
 71c:   c9                      leaveq 
 71d:   c3                      retq   
 71e:   66 90                   xchg   %ax,%ax

Since I'm trying to skip x = 1;, 0x705 - 0x6fe = 0x7, which I'm confident is correct. For determining the offset between buffer1 and the return address on the call stack, I inspect gdb:

Breakpoint 1, function1 (a=1, b=2, c=3) at example3.c:12
12      ret = (int *) buffer1 + 24;
(gdb) p $rbp
$1 = (void *) 0x7fffffffea80
(gdb) p &buffer1
$2 = (char (*)[8]) 0x7fffffffea70

The distance between buffer1 and the return address should then be: 0x7fffffffea80 - 0x7fffffffea70 + 8 = 24

I've also verified that the word size is 8 (using arch I know it's x86_64).

My guess is the return address offset might be different due to something like a stack canary, but how would I find the actual return address then?

EDIT:

The disassembly for function1:

00000000000006b0 <function1>:
 6b0:   55                      push   %rbp
 6b1:   48 89 e5                mov    %rsp,%rbp
 6b4:   89 7d ec                mov    %edi,-0x14(%rbp)
 6b7:   89 75 e8                mov    %esi,-0x18(%rbp)
 6ba:   89 55 e4                mov    %edx,-0x1c(%rbp)
 6bd:   48 8d 45 f0             lea    -0x10(%rbp),%rax
 6c1:   48 83 c0 44             add    $0x44,%rax
 6c5:   48 89 45 f8             mov    %rax,-0x8(%rbp)
 6c9:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 6cd:   8b 00                   mov    (%rax),%eax
 6cf:   8d 50 07                lea    0x7(%rax),%edx
 6d2:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 6d6:   89 10                   mov    %edx,(%rax)
 6d8:   90                      nop
 6d9:   5d                      pop    %rbp
 6da:   c3                      retq   

Solution

  • Not sure if this is your main problem, but I'm looking at

       ret = (int *) buffer1 + 24;
    

    Cast has higher precedence than binary +, so this is ((int *)buffer1) + 24. The effect is that ret is set to an address which is 96 bytes higher than that of buffer1, since sizeof(int) == 4.

    You probably meant to write

       ret = (int *)(buffer1 + 24);
    

    Also, the return address is 64 bits, and int is 32 bits. So you probably wanted to declare ret as unsigned long * instead of int *, and change the cast accordingly, so that your *ret += 7 is a 64-bit add. It's unlikely to actually make a difference because of alignments, but still it will look more correct.