6

I've read that stack usually starts in same address so the attacker may guess the starting point of the buffer to overflow. This is necessary to know this address to make the malicious code run. I made a program with a few lines of code to get the stack pointer address each time it starts and print it on the screen:

int * get_stack_pointer(){
    __asm__("mov %esp,%eax");
}
void main(){
  printf("Address: %p\n",get_stack_pointer());
}

And this is disassembly of the program:

<get_stack_pointer>:
push   %rbp
mov    %rsp,%rbp
mov    %esp,%eax
pop    %rbp
retq   

<main>:
push   %rbp
mov    %rsp,%rbp
mov    $0x0,%eax
callq  40050c <get_stack_pointer>
mov    %rax,%rsi
mov    $0x4005ec,%edi
mov    $0x0,%eax
callq  4003e0 <printf@plt>
pop    %rbp
retq 

But each time I start the program I get different addresses. Some of these are as following:

Address: 0xc31b2c80
Address: 0x2e041e0
Address: 0x7b003190
Address: 0xb3fd1350

So in this case how is it possible for the attacker to run his code on the vulnerable program? (my OS is Linux 64bit)

EDIT: I made another program in assembly which includes a few simple lines. I just check the value of RSP every time it starts with debugger and I see always RSP has the same value but not the program written in c.

user2808671
  • 127
  • 1
  • 9
  • 1
    On a 64-bit system you're looking for RSP not ESP. You also need to make sure that ASLR is disabled, otherwise programs are not necessarily loaded in the same place each time. Might also want to try this method instead: http://stackoverflow.com/a/20059713/3714897 – RoraΖ Mar 17 '15 at 17:47

1 Answers1

6

Your problem is ASLR randomly choosing where your program is loaded. You can turn off ASLR in Linux using sudo sysctl -w kernel.randomiz_va_space=0.

Here's my program. I'm using RAX instead of EAX, and an unsigned long * rather than an int *.

#include <stdio.h>
#include <stdlib.h>

unsigned long *get_stack_ptr(void) {
  __asm__(
    "mov %rsp, %rax"
  );
}

int main(int argc, char **argv) {
  unsigned long *stack_ptr = get_stack_ptr();

  printf("Size Of Ptr: %d bytes\n", sizeof(unsigned long *));
  printf("Stack Pointer: %llX\n", stack_ptr);

  return 0;
}

Here's my program on ASLR:

@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFD328233D0
@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFC2B5F07E0
@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFFE3A2FF10
@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFE5F0795F0

Now I perform: sudo sysctl -w kernel.randomize_va_space=0

Here's my program without ASLR:

@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFFFFFFDF70
@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFFFFFFDF70
@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFFFFFFDF70
@narrator:$ ./stackptr 
Size Of Ptr: 8 bytes
Stack Pointer: 7FFFFFFFDF70
RoraΖ
  • 12,317
  • 4
  • 51
  • 83
  • I think only eax is returned as the functions's "Return Value" which is 4 byte. in this case we cant get the full 8 byte address. can you please correct me about this if I'm wrong? Because I think all 8 bytes are needed to have the correct address (as rsp and rip are 64 bits) – user2808671 Mar 17 '15 at 18:59
  • I've updated my code and results. Also notice that I'm using RAX not EAX – RoraΖ Mar 17 '15 at 19:40
  • You've written: printf("Stack Pointer: %016X\n"); which you probably mean: printf("Stack Pointer: %016x\n",stack_ptr); And again the output of program is wrong. I checked value of RSP by gdb which is '0x7fffffffe380' and this code gives me :'00000000ffffe3b0' Because only for bytes (EAX) is is accepted as the return address not the whole RAX – user2808671 Mar 17 '15 at 20:00
  • as I see in debugger the return value (RAX) is correctly copied to the stack but printf only prints for bytes of it and consider the rest all zero! – user2808671 Mar 17 '15 at 20:08
  • That's because you're using an `int *` which is a signed 32-bit value. Thanks for pointing out my epic mistake though. I'll have to fix it tomorrow. – RoraΖ Mar 17 '15 at 20:17
  • I am talking about output of your code and I don't see any `int *` in your code. I think this is the problem of printf() function itself – user2808671 Mar 17 '15 at 20:21
  • Using my code or yours? – RoraΖ Mar 17 '15 at 20:23
  • Dude I run 'your' code and get wrong output (only 32 bit). You have used `usigned long *`. I changed it to non-poiter long `unsigned long` and again wrong output (32 bits only) – user2808671 Mar 17 '15 at 20:27
  • 1
    OH! *lightbulb* Sorry for not understanding last night. Gotta use `%llX` for long integers. Updated my code to print the correct variable, and the correct type. – RoraΖ Mar 18 '15 at 11:20