第一个缓冲区溢出的全过程实践
首发于:http://www.giantbranch.cn/?p=449
前言
这是8月处写的,缓冲区溢出大家估计听了不少了,但是实践过就更好了
为什么会出现缓存区溢出呢?(这里主要针对栈)
简单来说,首先局部变量,返回地址都是储存在栈上的,当我们的输入很长的一串字符,而且程序不检查长度就直接copy到局部变量上,那么局部变量就可以覆盖返回地址,控制漏洞函数的返回地址,从而控制程序的执行(具体实践实例)。
实例实践与分析
首先编译下面的代码,编译用debug版吧
#include <stdio.h>
#include <windows.h>
int overflow_here(char *key){
char buffer[66];
strcpy(buffer, key);
return 0;
}
int main(){
char key[666];
FILE *fp;
LoadLibrary("user32.dll");
if (!(fp = fopen("key.txt", "rw+"))){
exit(0);
}
fscanf(fp, "%s", key);
overflow_here(key);
printf("come on, overflow me!");
return 0;
}
可以看到漏洞函数overflow_here,直接将我们输入的key copy到buffer那,又没有对长度进行检查
解析一下代码
1.LoadLibrary("user32.dll"); 这动态链接库是为我们等一下运行弹框提供支持
2.还有为什么要从文件读取呢,因为我们覆盖返回地址的话,基本都要输入一些不可见字符,在文件中可以用十六进制编辑器区输入
当然还可以用python,perl脚本给程序传递不可见字符
如:
python -c 'print "\x99\x34\x56\x78"' | ./test
当然还可以从网络接收不可见字符
我们开始实验吧
创建一个key.txt,放在exe的同一个目录,我们先在文件中写66个A吧,
断在strcpy
我们看到buffer在ebp-0x44的地方,即ebp-68,
我们有两种基本的方法看看要多少个才覆盖,方法一就是根据局部变量的地址算出来,方法二就是看od的栈视图
先看看方法1:
那么栈的结构如下
那么我们搞68+4 = 72 个A就覆盖到返回值前面,返回地址覆盖成jmp esp的地址,后面就是我们的shellcode
方法二:利用od就更加直观啦
接下来寻找jmp esp的地址
若将jmp esp的地址放到返回地址,那么漏洞函数返回的时候,就返回执行jmp esp,而此时esp指向返回地址的下一个,或者下面几个,看它是retn 4还是retn 8, retn C咯,反正在返回地址后填充多几个nop就肯定行,之后的地址就布置shellcode
插件找jmp esp
我这里利用之前学习写的immunity Debugger的python插件来找jmp esp吧http://blog.csdn.net/u012763794/article/details/52174275#t39
用第一个吧
0x77562fbd
手动找jmp esp
或者手动找一波,去dll那里找
制作我们的弹框shellcode
在代码中写个MessageBox函数
用vc++6.0的调试功能,当然vs2005-2016也是可以的,查看到本机的MessageBox的地址
那就可以在od编写我们的shellcode啦,右边已写注释
选中后二进制复制
一粘贴就是下面的效果
33 DB 53 68 6E 63 68 21 68 74 62 72 61 68 67 69 61 6E 8B C4 53 50 50 53 B8 D6 FC C0 76 FF D0
最后用16进制工具编辑成这样(注意我们输入的地址要小端模式哦,即返回地址是字节逆序),那个messageBox代码(即shellcode)就不用逆序了,如果在你电脑上就要看看messageBox的地址是不是我这个了,不是就要改了[我的环境是win 7 64位]
用od调试看看,可以看到返回地址被我们覆盖了
F9直接让od运行吧,成功弹窗实验成功
参考
《0day安全》