pwn入门二:缓冲溢出
环境:cenos6.5 64位,安装了 gcc的32位编译库,cenos运行于文本模式,搭建方法见博文《pwn入门之一:搭建64位centos6.5虚拟机 》。
一、建立 test1.c,内容如下:
#include <stdio.h>
main()
{
char a='a';
char b[10];
gets(b);
if (a=='a')
printf("Try again.\n");
else
printf("You've pwned it.\n");
}
可以不必去理解这段代码的含义,只要无误的输入就可以了,理解了代码反而不利于理解PWN技术。
二、编译生成可执行文件test1
用以下命令
gcc -m32 -o test1 test1.c
可生成test1文件。
三、运行test1
用./test1命令运行之,程序要求键盘输入,输入一些字符后回车,可发现当输的内容的长度大于10,且第11个字符 不为‘a’时,提示成功信息,否则提示失败信息。
四、用gdb分析test1
运行gdb test1命令,出现(gdb)提示符,输入disas main命令,显示main函数的汇编代码,如下图所示:
代码中有两处出现[email protected],这是输出的语句,我们两来看看这两个语句前放入栈顶的是什么,
输入 x /s 0x80484f4 命令,显示“Try again.”如下图:
可知,如攻击不成功时会执行第11条语句 即
movl $804841f4,(%esp)
输入 x /s 0x80484ff 命令,显示“You've pwned it.”如下图:
可知,如果攻击成功,一定会执行第14条语句即
movl $804841ff,(%esp)
再看第10条语句,当0x1f(%esp)不等于0x61时就会执行第14条语句。
但在第5条语句,已将0x61赋值给了0x1f(%esp)了。
再看第6、7,8条语句,将这个地址放入栈顶,然后再调用[email protected],这说明此时的输入的内容将被放入0x15(%esp)及以后的内存单元中,但0x15(%esp)刚好在0x1f(%esp)前面10个单元的位置上,所以当输入的字符数为10个时,0x1f(%esp)将为置为‘0x00’,0x1f(%esp)r的值就不等于0x61了,这时攻击就成功了,另外,当输入的字符数大于10个时,第11个字符就会覆盖0x1f(%esp),当这个字符不是‘a’时,0x1f(%esp)r的值也就不等于0x61了,这时攻击就成功了。
来验证一下。
我们在第7个语句后设置一个断点,然后运行程序,到达断点后逐条运行,观察用键盘输入一些字符后0x15(%esp)到0x1f(esp)的内存单元的值的变化。如下图:
如其中的标示,在输入10个a字符之前,$esp+0x15至$esp+0x1e的值分别为0x83,0x04,0x08,0x4b,0x84,0x04,0x08,0xf4,0x0f,0x7a,而$esp+0x1f的值为0x61.
输入10个a字符之后,$esp+0x15至$esp+0x1e的值均为0x61,而$esp+0x1f的值变为了0x00,
依上法,我们重新做一次实验,这次我们输入10个a和1个b,情况如下:
这次我们发现$esp+0x1f的值变为了0x62,再而$esp+0x20的值则变成为0x00.
这就验证了我们的想法,由此设计攻击的方法,如下:
但当输入的第10个字为a时,失败,如下图:
以上就是一种缓冲溢出攻击的过程,攻击的原理读者可自行揣摩,涉及的命令的用法和意见请读者百度,此处不再详述。