缓冲区溢出漏洞实验
缓冲区溢出漏洞实验
我盯着屏幕上那行十六进制地址,缓冲手指悬在键盘上。区溢旁边同学已经敲完回车,出漏终端里弹出一个root shell。洞实他的缓冲实验成功了。我还在犹豫——那行地址偏移量算错了一位。区溢
缓冲区溢出,出漏说穿了就是洞实程序往一个固定大小的内存区域里塞了太多数据,多出来的缓冲部分溢出去,覆盖了相邻内存。区溢这听起来像水管爆裂,出漏水漫到不该去的洞实地方。但计算机里,缓冲漫出去的区溢水可以变成代码,变成指令,出漏变成攻击者想要的任何东西。
实验环境是Ubuntu 16.04,关闭了ASLR(地址空间布局随机化),用gcc编译时加上-fno-stack-protector。这些设置把现代系统的防御机制全部卸掉,让漏洞裸奔。我们用的靶机程序是个简单的strcpy调用,从argv[1]拷贝字符串到局部缓冲区,缓冲区只有64字节。
我重新算了偏移量。用gdb调试器查看栈布局,找到返回地址在栈上的确切位置。这一步最烦人——不同编译选项、不同系统版本,偏移量都会变。我花了二十分钟才确认,返回地址距离缓冲区起始位置是76字节,不是网上教程写的72。
构造payload的过程像拼积木。前76字节填NOP sled(一堆空操作指令),接着填入shellcode(一段能启动/bin/sh的机器码),最后覆盖返回地址,指向NOP sled中间某个位置。当函数返回时,CPU跳到我指定的地址,顺着NOP滑梯一路滑进shellcode,弹出root shell。
第一次真正执行时,程序直接segmentation fault。我检查payload,发现shellcode里有个字节被strcpy截断了——因为shellcode包含0x00,而strcpy遇到空字符就停止拷贝。这个坑很经典,解决办法是把shellcode编码,或者放到环境变量里绕过strcpy的限制。
改用了环境变量法。把shellcode放进环境变量,然后在栈上找到环境变量的地址,用这个地址覆盖返回地址。这次成功了。root shell弹出来的瞬间,实验室里好几台机器都发出类似的声音——那种混合着兴奋和不安的轻呼。
缓冲区溢出的本质是信任。程序员信任用户输入不会超过缓冲区大小,信任strcpy会自己判断长度,信任系统默认设置能挡住一切。这些信任在真实世界里被攻破过无数次。1988年的Morris蠕虫用的就是fingerd的缓冲区溢出,2003年的Slammer蠕虫只用了376字节就感染了全球75%的脆弱SQL服务器。
实验结束后,我关掉root shell,把系统恢复原样。但那个漏洞还留在程序里,像一道没锁的门。修复它只需要一行代码——用strncpy替代strcpy,或者检查输入长度。但真实世界的代码库里,这样的门成千上万扇,有些已经存在了几十年。
技术本身没有善恶,但掌握技术的人必须明白自己在做什么。我在实验报告里写了这么一句:缓冲区溢出不是bug,是程序员和机器之间一次关于信任的谈判破裂。
本文地址:http://www.79wt.cn/news/354a0399642.html
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。