揭秘四年陈年老漏洞
发现异常
午餐后,我收到以太坊安全群聊的推送通知,显示一个go-ethereum(geth)节点在处理区块11805072时出现错误。这引起了我的注意,因为:
- geth软件通常极其稳定,用户很少遇到错误
- 此错误发生在最新版geth上,意味着已包含所有最新安全补丁
错误信息显示区块头声称交易总共使用了12458355 gas,但节点执行时仅使用了11152534 gas。
深入调查
通过检查问题交易,发现这是一个简单的ERC20转账。进一步分析发现,Anatol的节点上某个合约的存储槽0在主网有地址,但在他的节点上为空,表明存在存储损坏。Anatol透露他曾从备份恢复geth数据库,可能在此过程中丢失了部分数据。
转向漏洞挖掘
解决节点问题后,我将注意力转向损坏的合约。我认出这是EToken2平台发行的代币合约,决定重新审计这个四年前审查过的平台。
攻击面分析
作为ERC20合约,最高影响的漏洞包括:
- 获取免费代币(盗取或自行铸造)
- 任何形式的破坏(燃烧他人代币或阻止转账)
合约架构分析
代币合约将ERC20功能委托给实现合约,但每个用户的实现可能不同。代币包含可随时由所有者升级的默认实现,用户可以选择退出升级并固定其实现版本。
关键发现
在EToken2平台合约中,我发现了两个关键问题:
-
事件伪造漏洞
_proxyTransferEvent函数通过proxies[_symbol]间接触发Transfer事件- 如果能在转账过程中改变代理地址,就能伪造任意转账事件
-
权限转移漏洞
grantAccess函数允许将持有者ID权限转移给其他地址- 但实现存在缺陷:转移后原地址仍保持权限
- 攻击者可以后门任何新平台用户,控制其所有EToken2代币
利用链构建
通过结合cosigner功能和重入攻击,攻击者可以:
- 监控内存池中新用户注册交易
- 抢跑交易,将权限授予攻击者控制的地址
- 获得对受害者账户的完全控制权
修复方案
由于EToken2被设计为不可升级,强制所有代币迁移数据不现实。与项目方合作,我们通过三个合约修补漏洞:
- 修改
emitRecovery处理程序,要求地址明确选择接受权限授予 - 修改ERC20相关事件处理程序,要求代理合约符合预期
- 升级EventsHistory合约,永久禁用新发射器注册
在发现漏洞仅4天后,修复方案于4月6日部署,这个传奇被永久铭刻在区块链上。