@rg070836rg
2016-11-01T15:15:51.000000Z
字数 964
阅读 1790
网络安全
函数的局部变量在栈中,一个挨着一个排列,如果有缓冲区,那么可能 就存在数组越界的可能,比如破坏相邻的变量值,或者破坏EBP,返回地址等。
#include "stdafx.h"
#include <iostream>
using namespace std;
#define PASSWORD "12345"
int verify(char * psw)
{
int auth;
char buffer[8];
auth = strcmp(PASSWORD, psw);
strcpy(buffer, psw);//缓冲区溢出点
return auth;
}
int main(int argc, _TCHAR* argv[])
{
int flag = 0;
char psw[1024];
while (1)
{
cout << "输入密码" << endl;
cin >> psw;
flag = verify(psw);
if (flag)
{
cout << "密码错误" << endl;
}
else
{
cout << "验证成功" << endl;
}
}
return 0;
}
我们来观察auth的地址以及buffer的地址
&auth:0x0019FAC8
&buffer:0x0019FAC0
很容易发现auth刚好在buffer的下方,这样我们可以利用这个缓冲区,来替换auth的内容。
我们试着输入abcdefghijk:
在执行过strcpy之后,我们观察内存:
很容易发现,0x0019FAC8 中间的值被修改了。
那我们只要构造,让溢出的时候,让其为0即可
测试结果:
这是函数栈帧的起始点与结束部分
我们通过寄存器可以看到 EBP的地址:
EBP = 0019FACC
EBP上下文:
我们发现EBP在auth下方记下来一行就是我们函数的返回地址
这边记录的是我们的返回地址,对应着main函数(调用者)的EIP寄存器值。
main函数(调用者)
那么我们只需要修改EBP下方的内容,就可以重新定位返回点,来执行其他的代码,所以我们只需要找到一个有效的指令地址,就可以跳转到任意地方去执行代码。
从反汇编中,我们找到 验证成功的地址,我们只需要,将这个地址给构造进输入,那么就可以跳过验证,直接进入main中的else分支。
这边由于某些地址对应的ASSIC字符,比较难输入(需要从文本读入比较方便),所以不去实验了。