游客发表

整数溢出漏洞

发帖时间:2026-10-17 04:38:33

2016年,整数黑客从以太坊DAO合约里转走了超过6000万美元的溢出以太币。不是漏洞靠高超的密码学破解,不是整数靠内鬼,只是溢出利用了智能合约里一个整数溢出漏洞——把余额减成天文数字,然后提现。漏洞那次事件直接导致以太坊硬分叉,整数社区撕裂。溢出一个小小的漏洞整数,把整个区块链生态搅得天翻地覆。整数

整数溢出这事儿,溢出说穿了特别简单。漏洞计算机里的整数整数有固定位数,就像一个小杯子。溢出你往杯子里倒水,漏洞倒满了还继续倒,水就溢出来了。32位无符号整数最大能表示4294967295,你给它加1,它不变成4294967296,而是直接归零。64位同理,只是杯子更大。这种"翻转"在物理世界里不存在,但在数字世界里每天都在发生。

我见过最离谱的一个案例,是某电商平台的优惠券系统。开发人员把用户领券数量定义成无符号8位整数,最大值255。测试时一切正常,因为没人会领255张券。但黑客注册了255个小号,每个号领一张,然后同时操作,把领券接口的计数器从255翻到0。系统以为他没领过,又发一轮。反复循环,最后囤了上千张券,全部换成实物商品。平台发现时,已经亏了六位数。

你可能会问,为什么不直接用大整数类型?这不就解决了吗?问题在于性能。底层C语言里,64位整数的运算速度比128位快得多,内存占用也少一半。在高并发的支付系统、游戏引擎、嵌入式设备里,每一纳秒都金贵。很多老代码跑了几十年,没人敢动底层数据结构——一改,所有依赖溢出特性的逻辑全崩。

更隐蔽的是,有些溢出不是直接算出来的,而是"隐式转换"导致的。比如一个函数接收int类型参数,内部把它转成unsigned int。你传个-1进去,转换后变成4294967295。如果这个值被用来计算数组索引或者内存偏移量,后果不堪设想。这就是传说中的"整数符号混淆",比纯粹的溢出更难发现,因为静态分析工具往往抓不到。

我自己的习惯是,凡是涉及金额、数量、长度、索引的运算,一律用64位有符号整数,并且每次加减后都做边界检查。听起来很笨,但能省掉90%的麻烦。有人觉得这样太啰嗦,但真等到线上出事故,你连啰嗦的机会都没有。

还有一类溢出特别坑人——时间戳。32位Unix时间戳在2038年会溢出,这已经是个老梗了。但很多系统还在用32位保存时间。我去年审计一个物联网设备固件,发现它的固件更新模块用32位时间戳判断证书有效期。证书是2038年后的,系统一算,时间戳变成负数,直接判定证书过期,拒绝更新。设备从此变砖。你说这算不算一种"未来攻击"?

写代码的人总爱说"这不可能发生",但现实里黑客最爱钻这种空子。整数溢出不挑语言,C、C++、Java、Python、JavaScript,只要底层有定长整数,都有这个风险。唯一的区别是,有的语言默认抛异常,有的语言默默翻转。Python的int是无限精度的,但numpy数组里的整数还是定长的——别以为换个语言就高枕无忧了。

最后说个题外话。我见过某团队为了防止溢出,写了一个自定义的SafeMath库,每次运算都要调用。代码丑得没法看,但人家上线三年零事故。另一个团队追求代码优雅,用原生运算,半年被薅了两次羊毛。安全性从来不是技术问题,是态度问题。

    热门排行

    友情链接