当前位置:首页 > 探索

缓冲区溢出是什么意思

2003年夏天,缓冲美国三个州的区溢电力监控系统同时宕机,后来查出原因不是意思病毒,也不是缓冲硬件故障,而是区溢一段只有几十个字节的恶意数据挤爆了控制程序的内存空间。这就是意思缓冲区溢出——一个听起来像水管爆裂的词,实际是缓冲计算机内存里最经典的“越界”事故。

要理解它,区溢得先知道程序怎么用内存。意思你可以把内存想象成一排带编号的缓冲储物柜,每个柜子只能放固定大小的区溢东西。程序运行时,意思会给变量分配几个柜子,缓冲比如一个能装8个字符的区溢数组,就占8个柜子。意思正常情况下,你往里放8个字符,相安无事。但如果你硬塞进去20个字符,多出来的12个就会挤到隔壁柜子里——隔壁可能存着函数返回地址、其他变量的值,甚至控制程序跳转的指令。

这不是比喻。2001年Code Red蠕虫横扫全球,靠的就是微软IIS服务器里一个缓冲区溢出漏洞。攻击者发送超长URL,溢出后覆盖了返回地址,让服务器去执行攻击者指定的代码。结果几十万台机器被感染,白宫官网都被迫换IP。一个“塞多了”的动作,能瘫痪整个网络。

为什么程序员会犯这种错?C语言是罪魁祸首之一。它为了效率,不检查数组边界。你声明char buf[10],然后strcpy(buf, user_input),如果user_input长度超过10,strcpy照抄不误,多出来的字节直接踩到栈上其他数据。栈是内存里一块特殊区域,函数调用时用来保存返回地址和局部变量。一旦返回地址被覆盖,函数执行完就不会回到原来的调用点,而是跳到攻击者写好的地址去。

我见过一个真实案例。某工控设备用C写了个解析串口数据的函数,接收缓冲区只有64字节。操作员误发了一条200字节的调试命令,设备立刻重启。后来发现,溢出的136字节里,有4字节恰好覆盖了看门狗定时器的重载值,导致喂狗失败。你看,不需要黑客,一个手滑就能触发。

防御手段这些年进步不少。现代编译器默认开启栈保护(Stack Canary),在返回地址前插一个随机值,溢出时先破坏这个值,程序检测到就主动崩溃,而不是执行恶意代码。操作系统也加了ASLR,让栈和堆的地址随机化,攻击者很难猜中该跳到哪里。还有DEP,把数据段标记为不可执行,就算你写入了shellcode,CPU也不认。

但缓冲区溢出没消失。嵌入式设备、老旧的C项目、甚至某些Java本地接口(JNI)调用,依然在犯同样的错误。去年有个智能门锁的固件漏洞,就是WiFi配网时SSID字段没做长度检查,溢出后可以远程开锁。厂商的补丁只是把strcpy换成strncpy,一行代码的事,但漏洞已经存在了三年。

写代码的人得记住:内存不是无限宽的马路,每个变量都有自己的车道。你多占一厘米,就可能把别人的车挤下悬崖。而攻击者最喜欢这种“挤”出来的机会。

分享到: