这篇文章最初发布在以太坊博客.
摘要:在某些情况下,变量可能覆盖存储中的其他变量。
受影响的 Solidity 编译器版本:0.1.6 到 0.4.3(包括 0.4.4 预发布版本)
详细描述
小于 256 位的存储变量如果可以容纳,则会打包到同一个 256 位槽中。如果将大于类型允许的值分配给第一个变量,则该值将覆盖第二个变量。
这意味着如果攻击者可以导致第一个变量的值溢出,则可以修改第二个变量。使用算术运算或通过直接从调用数据传递值(调用数据中的值对齐到 32 字节,并且填充既不验证也不强制)来创建第一个变量的溢出是可能的。
仅对状态变量使用下面列出的类型的合约不受影响。数组、映射和结构体(基于以下类型)也不受影响
- 有符号整数,包括小于 256 位的大小
- bytesNN 类型,包括小于 256 位的大小
- 256 位的无符号整数(uint)
小于 256 位的类型在彼此之间从未相邻的合约(注意,基础合约的状态变量会被“拉入”)不受影响。
以太坊多重签名钱包合约不受影响。请注意,地址占用 160 位,因此仅使用地址和 256 位类型的合约是安全的。此外,在实践中,地址和布尔值几乎从未通过算术运算进行操作,因此仅使用地址、布尔值和 256 位类型的合约也应该是安全的。
以下合约可能会受到影响:包含两个或多个连续状态变量的合约,其中它们的总大小小于 256 位,并且第一个状态变量不是有符号整数,也不是 bytesNN 类型。
小于 256 位的类型包括:bool、枚举、uint8、...、uint248、int8、...、int248、address、任何合约类型
建议的操作
- 使用至少 Solidity 版本 0.4.4(不是预发布或夜间版本)重新编译尚未部署的合约。
- 停用、提取资金或升级已部署的合约。
此漏洞由 @catageek 发现:https://github.com/ethereum/solidity/issues/1306