缓冲区溢出还是问题吗?C++/CLI安全编码
,编译器会为main()及checkpassword()函数生成Microsoft媒介语言(MSIL或称为通用媒介语言CIL),CIL字节码会被打包进一个可执行文件,在调用即时编译器(JIT)将其翻译为本地程序集指令后,接着把控制权交给main()。
程序运行时,提示用户输入用户名:
接着程序要求用户输入密码,其被读入到声明在11行上的10个字符数组这个变量中,在插1中,如果在密码从标准输入读取之前,查看堆栈上的数组地址起始处的数据(本例中为0x002DF3D4),将会看到分配给密码的存储空间(以黑体字标出)及堆栈上的返回地址(以红色字标出)。返回地址在此为小尾字节序(Little Endian)。 代码段1:堆栈上数组地址起始处的数据
倘若输入了更多的字符,以致密码字符数组存储空间无法容纳,一个攻击者就可以溢出此缓冲区,并以shellcode(可为任意的代码)地址覆盖掉返回地址。出于演示的目的,在此假定shellcode已被注入,且定位于0x00408130,为执行此代码,攻击者只需把下列字符串作为密码输入:
这个输入的字符串被复制到密码字符数组,溢出了此缓冲区并覆盖相应的内存包括返回地址。字符串中的三个字符0|@覆盖了返回地址的前三个字节,而返回地址的最后一个字节被一个由gets()函数产生的null结尾字符所覆盖。注意,如果这个null不在最后一个字节上,那么不可能复制整个字符串,因为gets()函数会把这个null字符解释为字符串的结尾。那为什么要以上这三个字符呢?因为,这些字符的十六进制形式提供了内存中表示地址所需的值,"0"的ASCII十六进制码为0x30,"|"为0x81,而"@"为0x40。如果把这三个字符以顺序{ ''0'', ''|'', ''@'' }连接起来,就可将shellcode(0x00408130)地址的小尾字节序表示形式写入到内存中。最后一个null字节 由字符串的null字符提供。(见代码段2。) 代码段2:
当checkpassword()函数返回时,控制权就传到shellcode而不是main()函数中的原始返回地址上。 为了简化这个攻击过程,在此,关闭了缓冲区安全检查选项/GS。如果这个选项没有关闭,编译器将会在声明在堆栈上的任何数组(缓冲区)之后插入一个"密探"--实际上为一个Cookie,见图1。
图1:基于"密探"的缓冲区溢出保护 如果要使用那些不受控制的字符串复制操作,如gets()或strcpy(),来覆盖掉由"密探"保护的返回地址(EIP)、基指针(EBP)、或堆栈上的其他值,一个攻击者将首先要覆盖掉这个"密探"。如果"密探"被修改了,当函数返回时,将会产生一个错误,导致攻击失败--除非是为了进行"拒绝服务攻击"。通过暴力枚举猜测这个值,或其他方法,还是有可能挫败这个"密探"的,但是,进行一次成功攻击的难度增加了。 打开/GS选项不会让程序对缓冲区溢出漏洞彻底免疫,堆栈中的缓冲区溢出仍会使程序崩溃,攻击者利用基于堆栈的溢出来执行任意代码 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |