版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/swjtu100/article/details/49976089
0x00 strcpy()函数
void main()
{
char s[]="123456789";
char d[]="abc";
strcpy(d,s); printf("d=%s,\ns=%s",d,s);
getchar();
}
- Visual C++6.0中运行结果:
- 拷贝前后栈中变量分布:
—————->>> - 解释:strcpy(d,s)将s中的所有字符拷贝到s中,直遇到结束符’\0’,而不检查d是否越界。
0x01 修改邻接变量
- 不进行编译优化前提下,局部变量在栈中是相邻存放的,若局部变量中有数组等缓冲区,并且程序存在数组越界的缺陷,则越界的数组元素有可能破坏栈中相邻变量、EBP值、返回地址等
#include <stdio.h>
#include<string.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[8];// add local buff
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
while(1)
{
printf("please input password: ");
scanf("%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
break;
}
}
}
- 运行结果:
- 错误密码通过验证原理
函数栈中参数的分布:
拷贝前后栈中变量分布:
—————>>>
输入8个’q’,第9个为字符串截断符0x00,溢出至authenticated的低字节,恰好将0x00000001覆盖成0x00000000,成功通过验证。 - 说明:
a) 只有输入的8个字符大于”1234567”是才能通过验证。由于authenticated的值是strcmp()的返回值,输入字符串大于”1234567”是,返回1,内存中为0x00000001,可以用字符串截断符NULL覆盖authenticated的低字节通过验证。当输入字符串小于”1234567”时,函数返回-1,内存中为0xffffffff,覆盖后为0xffffff00,仍不能通过验证。
b) Visual C++ 6.0 Debug版本编译能实现该实验,VS2010的GS(缓冲区安全检查)会使该实验失败。
0x02 修改函数返回地址
- 通过缓冲区溢出改写函数栈帧最下方的EBP值和函数返回地址等栈帧状态值。
#include<stdio.h>
#include<string.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[8];// add local buff
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024] = "AAAAAAAAAAAAAAAA\x0A\x11\x40\x00";
while(1)
{
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
break;
}
}
}
- 通过验证原理:
程序中password[1024] = “AAAAAAAAAAAAAAAA\x0A\x11\x40\x00”,其中”\x0A\x11\x40\x00”将覆盖函数返回地址的值,且0x0040110A为密码验证成功处理分支的指令地址(该地址通过动态调试得到)。故程序能在verify_password()调用后直接跳转至通过验证分支,成功绕过密码验证。
拷贝前后栈中变量分布:
————- ->>>
由于EBP被覆盖为无效值,是程序退出时堆栈无法平衡,导致程序崩溃。 - 说明:
a) Visual C++ 6.0 Debug版本编译能实现该实验,VS2010的GS(缓冲区安全检查)会使该实验失败。
b) 可以password[1024]中写入自己的代码,用该代码的虚拟地址覆盖返回地址实现代码植入。
——《0day安全》学习笔记