北京时间2021年8月27日20点50分左右(区块高度13107518),以太坊突然出现分叉。我们通过分析Geth的代码版本修改和这笔造成分叉的交易(0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4)厘清了以太坊分叉的根本原因:Geth旧版本在处理预编译合约调用时,并未考虑特殊情况(corner case)下参数值的处理,从而引发重叠拷贝(overlapping copy),导致返回值异常。该漏洞(CVE-2021-39137)已提交Geth官方,目前尚未披露细节,但攻击者已经利用漏洞实施了攻击。我们认为及时的分析和披露是必要的,也希望我们的分析能够为社区提供必要的理解和帮助。 攻击分析 运用我们的在线分析工具,可以看出: 图一这笔交易执行了一个精心构造的 STATICCALL, 攻击者将 addr 设为0x04(是预编译合约dataCopy), inOffset 为 0, inSize 为 32, retOffset 为 7, retSize 为 32。 由于STATICCALL的目标地址是预编译合约,所以会执行图二中的RunPrecompiledContract。 图三 图四根据图三和图四的代码,可以看到预编译合约0x04真正执行的逻辑只是简单地把 in (指针)返回。 图五 图六 图五是STATICCALL的执行过程,753 行是执行预编译合约的入口,751 行的 args 指向 EVM 的 Memory 中 inOffset ~ inOffset + inSize 这篇区域的指针,也就是说args 指向 Mem[0:32]; 根据图六以及前文对预编译合约0x04(dataCopy)的分析,我们可以知道 753 行的返回值 ret 是与 args 完全相同的指针,也指向 Mem[0:32]; 在 1.10.7 版本的 Geth 中(有Bug): 762 行将 ret 指向的值赋给 EVM 的 Memory 中 retOffset ~ retOffset + retOffset 这篇区域, 也就是将 Mem[0:32] 的值赋给 Mem[7:7+32]; 而由于 ret 是一个指向Mem[0:32]的指针,这次 Memory.Set 修改了 Mem[7:32] 的值,也就修改了 ret 所指的值。 所以在第 771 行返回的 ret 已经不是预编译合约执行结束时的 ret 了。 在 1.10.8 版本的 Geth 中(无Bug): 增加了 766 行: ret = common.CopyBytes(ret), 将 Mem[0:32] 中的值做了一次深拷贝赋给ret,那么在 767 行执行的 Memory.Set 只会修改 Memory 而不会修改 ret, 在 771 行返回的 ret 就是正确的 ret。 总结 通过对整个攻击流程的梳理和Geth源代码的分析,我们认为根本原因在于Geth旧版本在处理预编译合约的调用时并未考虑异常值的处理,导致攻击者利用该漏洞实施了重叠拷贝,影响了返回值,最终导致分叉的出现。由于Geth是BSC、HECO、Polygon等公链的基础,因此该漏洞影响范围甚广。目前各公链也先后推出了升级和补丁,我们也呼吁各相关节点尽早升级打上补丁,以确保基础设施的安全。 —- 编译者/作者:BlockSec 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
以太坊突遭分叉的罪魁祸首:CVE-2021-39137漏洞成因及攻击分析
2021-08-28 BlockSec 来源:区块链网络
LOADING...
相关阅读:
- BIB社交应用通证已通过HECO生态链正式上线2021-08-28
- 边玩边赚的区块链游戏普通人如何开始玩?2021-08-28
- SEC 与区块链分析公司达成协议以监控 DeFi 交易2021-08-28
- 以太坊、波卡、莱特币价格分析:8 月 28 日2021-08-28
- 火丶羽白:月线即将收官大饼何去何从?2021-08-28