如何登陆一个无法登陆的系统?
首先我们来看一个非常简易的登录系统
#include<bits/stdc++.h>
using namespace std;
int main()
{
char *buf=(char *)malloc(3);
char *password=(char *)malloc(6);
strcpy(password,"123456");
memset(buf,0,3);
scanf("%s",buf);
if(strcmp(password,"666666")==0){
puts("login success");
}
return 0;
}
里面最核心的逻辑是通过strcmp函数进行了密码校验,只有密码为666666的时候才能登陆成功。 貌似这是一个永远无法登录的系统?但是事实上并非如此,在不安全的环境下,我们可以通过很简单的技术手段实现登录,这种技术手段通常被称作缓冲区溢出。
如何实现登录?
直接切入主题,通过实验可以发现,只需要输入38个6,就可以成功登录系统。
关于C++的缓冲区溢出
我们这里不探讨内存对齐等C++知识,只针对缓冲区溢出有关的内存模型部分进行调试和讲解。
在这里,调试工具我采用了Codeblocks16+GDB的配置。调试环境基于Windows10系统。
在实现覆盖之前,我们需要简单计算一下,0x2c83540-0x2c83520=32,因此字符从0x2c83520开始,到0x2c8353F结束,一共需要32个字符。而0x2c83540到0x2c83545还需要6个字符才能完全覆盖123456这六个字符,因此我们需要尝试输入38个字符。 经过了上述分析以后,我们输入38个字符'6',发现成功完成了校验,实现了登录。结果在文章开头已经展示,这里不再进行重复展示。
总结
缓冲区溢出利用了系统内存模型的漏洞,通过输入过量的字符实现对后续变量的覆盖,从而达到了破坏程序正常运行的目的。如果想要防止缓冲区溢出漏洞,最佳的方案是使用更安全的输入输出函数.(例如VC++实现了scanf_s函数来避免缓冲区攻击)