从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

Squid 经过了暴跌与暴涨,但本质上仍没有完成去中心化,合约依然存在诸多安全风险。

原标题 | 知道创宇区块链安全实验室 | 从EIP-1967谈“鱿鱼游戏SQUID”安全风险

前言

随着电视剧的爆火,鱿鱼游戏的热度也逐渐攀升,而 SQUID 在 10 月 21 日上线后,价格幅度变化巨大,但是现在的它真的安全吗?

Squid 从代码上来看其依赖于以太坊提案 EIP-1967,知道创宇区块链安全实验室 将从 EIP-1967 提案再谈 Squid 的安全风险。

SQUID 价格从 0.08 刀一路扶摇直上九万里,飙升到 3000 美元。然而令人唏嘘的是,价格随即闪崩,5 分钟从 3000 跌至 0.0007,究其原因,合约开发者在短短的几分钟内利用 7000w 枚 Squid 砸盘 ,导致流动性池被抽干,直至归零。在经历了底部 0.0007 后,该游戏代币最近短短几天重新涨到了 0.4,涨幅达到了 50 倍以上,可谓势头不小。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

EIP-1967

This EIP standardises the storage slot for the logic contract address, instead of a public method on the proxy contract as DelegateProxy (EIP897) does. The rationale for this is that proxies should never expose functions to end users that could potentially clash with those of the logic contract.

首先,EIP-1967 的目的是规定一个通用的存储插槽,用于在代理合约中的特定位置存放逻辑合约的地址。

在该提案中,对逻辑合约地址的存储槽进行了标准化,而不是像 DelegateProxy (EIP897) 一样在代理合约上使用公共方法。

通过跟进该提案,在提案中定义了如下的标准化存储槽。

bytes32(uint256(keccak256(“eip1967.proxy.implementation”)) – 1)

bytes32(uint256(keccak256(“eip1967.proxy.beacon”)) – 1)

bytes32(uint256(keccak256(“eip1967.proxy.admin”)) – 1)

最后通过计算,列出来了三个 byte32位 的 Hash 值作为推荐的存储槽。

bytes32(uint256(keccak256(“eip1967.proxy.implementation”)) – 1)

//逻辑合约地址 存储槽 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc

bytes32(uint256(keccak256(“eip1967.proxy.beacon”)) – 1)

//信标合约地址 存储槽 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50

bytes32(uint256(keccak256(“eip1967.proxy.admin”)) – 1)

//admin 地址 存储槽 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

EIP-1967 中有提到,对于一个代理来说,代理永远不应该向最终用户公开可能与逻辑合约功能冲突的方法。此处计算将 keccak256 结果进行减一再转化为 bytes32 来隐藏前像,以防止基于函数签名攻击。

针对该攻击,具体哈希后的前 4 个 bytes 函数签名的攻击思路如下:

  • 由于 solidity 中识别一个函数,靠的是函数签名,而函数签名是函数哈希后的前 4 个 bytes,是非常容易碰撞出来的。而函数签名相关知识点可以参考实验室之前的文章

  • 在一个独立的 solidity 文件中,编译器自己会去检查所有的 external 和 public 函数是否存在函数签名碰撞,但对于代理模式的合约文件,可能存在 proxy 合约中的函数签名与 impl 合约中的函数签名碰撞。而一旦发生这种碰撞,proxy 合约中的函数就会被直接调用,而不是 impl 合约对应的函数。

除了以上用途,使用 EIP-1967 还有如下的好处

合约代理模式规范性:

由于代理合约中缺少用于获取代理的逻辑地址的通用接口,因此无法构建对这些信息进行操作的通用工具。比如在区块链浏览器中,最终用户想要与底层逻辑合约而不是代理本身进行交互。

如果拥有从代理检索逻辑合约地址的通用方法将可以允许区块浏览器去显示逻辑合约的 ABI 而不是代理的 ABI。浏览器可以还检查合约在不同槽位的存储,来确定它是否确实是一个代理。

Squid安全性

通过跟进 Squid 合约,虽然我们看到合约部署者0x87230146e138d3f296a9a77e497a2a83012e9bc5 通过 renounceOwnership 方法将 _owner 设置为了 0 地址:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

但是这样就可以高枕无忧了吗?在Squid的初始化中,部署者通过为ApprovedEngine传入逻辑函数地址并设置为接口实现。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

但与此同时,初始化传入了参数_sir,该参数从代码中可以发现,其被存储在了存储槽(storage[‘0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103’])中。该地址后续可成功通过ifSir修饰器的检查并随时调用approveTo函数来部署新的逻辑合约实现。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

_sir可通过升级对应的逻辑合约,进而改变了_implementation返回的对于EIP-1967中提到的槽中bytes32(uint256(keccak256(“eip1967.proxy.implementation”) – 1))的值通过改变Engine收到调用的时候合约执行逻辑,进而修改逻辑合约的代码:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

针对该修改逻辑合约进行攻击已屡见不鲜,在几天前 bzx 就曾因”开发方被钓鱼导致私钥被盗”,进而代理合约被修改并影响到了流动性提供者,攻击者不仅转走了原本合约内的资金,还尝试转移对合约进行了approve的账户的资产。

事件参考(https://bzx.network/blog/prelminary-post-mortem

最后,通过追溯该Squid的部署合约,我们可以发现该合约的具体部署Transaction:

https://bscscan.com/tx/0xcaa4186f7e4dacd856835cb92a8518c88b098a33348a42168f99a0c57b7291c7

而在此 Transaction 中,传入合约的参数最后一个参数则为 _sir 地址:

0x6bdb3b0fd9f39427a07b8ab33bac32db67eb4e38

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

当然,还存在多种方法拿到该地址如:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

并且该sir后门地址至今仍非常活跃:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险后记

Squid 经过了暴跌与暴涨,但本质上仍没有完成去中心化,合约依然存在诸多安全风险。在频繁和大幅度的涨跌中,常有参与者忘记了本心,最后导致亏空的结局。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

转载声明:本文 由CoinON抓取收录,观点仅代表作者本人,不代表CoinON资讯立场,CoinON不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。若以此作为投资依据,请自行承担全部责任。

声明:图文来源于网络,如有侵权请联系删除

风险提示:投资有风险,入市需谨慎。本资讯不作为投资理财建议。

(0)
上一篇 2021年11月11日 下午9:14
下一篇 2021年11月11日 下午9:18

相关推荐

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

星期四 2021-11-11 21:17:11

原标题 | 知道创宇区块链安全实验室 | 从EIP-1967谈“鱿鱼游戏SQUID”安全风险

前言

随着电视剧的爆火,鱿鱼游戏的热度也逐渐攀升,而 SQUID 在 10 月 21 日上线后,价格幅度变化巨大,但是现在的它真的安全吗?

Squid 从代码上来看其依赖于以太坊提案 EIP-1967,知道创宇区块链安全实验室 将从 EIP-1967 提案再谈 Squid 的安全风险。

SQUID 价格从 0.08 刀一路扶摇直上九万里,飙升到 3000 美元。然而令人唏嘘的是,价格随即闪崩,5 分钟从 3000 跌至 0.0007,究其原因,合约开发者在短短的几分钟内利用 7000w 枚 Squid 砸盘 ,导致流动性池被抽干,直至归零。在经历了底部 0.0007 后,该游戏代币最近短短几天重新涨到了 0.4,涨幅达到了 50 倍以上,可谓势头不小。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

EIP-1967

This EIP standardises the storage slot for the logic contract address, instead of a public method on the proxy contract as DelegateProxy (EIP897) does. The rationale for this is that proxies should never expose functions to end users that could potentially clash with those of the logic contract.

首先,EIP-1967 的目的是规定一个通用的存储插槽,用于在代理合约中的特定位置存放逻辑合约的地址。

在该提案中,对逻辑合约地址的存储槽进行了标准化,而不是像 DelegateProxy (EIP897) 一样在代理合约上使用公共方法。

通过跟进该提案,在提案中定义了如下的标准化存储槽。

bytes32(uint256(keccak256(“eip1967.proxy.implementation”)) – 1)

bytes32(uint256(keccak256(“eip1967.proxy.beacon”)) – 1)

bytes32(uint256(keccak256(“eip1967.proxy.admin”)) – 1)

最后通过计算,列出来了三个 byte32位 的 Hash 值作为推荐的存储槽。

bytes32(uint256(keccak256(“eip1967.proxy.implementation”)) – 1)

//逻辑合约地址 存储槽 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc

bytes32(uint256(keccak256(“eip1967.proxy.beacon”)) – 1)

//信标合约地址 存储槽 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50

bytes32(uint256(keccak256(“eip1967.proxy.admin”)) – 1)

//admin 地址 存储槽 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

EIP-1967 中有提到,对于一个代理来说,代理永远不应该向最终用户公开可能与逻辑合约功能冲突的方法。此处计算将 keccak256 结果进行减一再转化为 bytes32 来隐藏前像,以防止基于函数签名攻击。

针对该攻击,具体哈希后的前 4 个 bytes 函数签名的攻击思路如下:

  • 由于 solidity 中识别一个函数,靠的是函数签名,而函数签名是函数哈希后的前 4 个 bytes,是非常容易碰撞出来的。而函数签名相关知识点可以参考实验室之前的文章

  • 在一个独立的 solidity 文件中,编译器自己会去检查所有的 external 和 public 函数是否存在函数签名碰撞,但对于代理模式的合约文件,可能存在 proxy 合约中的函数签名与 impl 合约中的函数签名碰撞。而一旦发生这种碰撞,proxy 合约中的函数就会被直接调用,而不是 impl 合约对应的函数。

除了以上用途,使用 EIP-1967 还有如下的好处

合约代理模式规范性:

由于代理合约中缺少用于获取代理的逻辑地址的通用接口,因此无法构建对这些信息进行操作的通用工具。比如在区块链浏览器中,最终用户想要与底层逻辑合约而不是代理本身进行交互。

如果拥有从代理检索逻辑合约地址的通用方法将可以允许区块浏览器去显示逻辑合约的 ABI 而不是代理的 ABI。浏览器可以还检查合约在不同槽位的存储,来确定它是否确实是一个代理。

Squid安全性

通过跟进 Squid 合约,虽然我们看到合约部署者0x87230146e138d3f296a9a77e497a2a83012e9bc5 通过 renounceOwnership 方法将 _owner 设置为了 0 地址:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

但是这样就可以高枕无忧了吗?在Squid的初始化中,部署者通过为ApprovedEngine传入逻辑函数地址并设置为接口实现。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

但与此同时,初始化传入了参数_sir,该参数从代码中可以发现,其被存储在了存储槽(storage[‘0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103’])中。该地址后续可成功通过ifSir修饰器的检查并随时调用approveTo函数来部署新的逻辑合约实现。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

_sir可通过升级对应的逻辑合约,进而改变了_implementation返回的对于EIP-1967中提到的槽中bytes32(uint256(keccak256(“eip1967.proxy.implementation”) – 1))的值通过改变Engine收到调用的时候合约执行逻辑,进而修改逻辑合约的代码:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

针对该修改逻辑合约进行攻击已屡见不鲜,在几天前 bzx 就曾因”开发方被钓鱼导致私钥被盗”,进而代理合约被修改并影响到了流动性提供者,攻击者不仅转走了原本合约内的资金,还尝试转移对合约进行了approve的账户的资产。

事件参考(https://bzx.network/blog/prelminary-post-mortem

最后,通过追溯该Squid的部署合约,我们可以发现该合约的具体部署Transaction:

https://bscscan.com/tx/0xcaa4186f7e4dacd856835cb92a8518c88b098a33348a42168f99a0c57b7291c7

而在此 Transaction 中,传入合约的参数最后一个参数则为 _sir 地址:

0x6bdb3b0fd9f39427a07b8ab33bac32db67eb4e38

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

当然,还存在多种方法拿到该地址如:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险

并且该sir后门地址至今仍非常活跃:

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险后记

Squid 经过了暴跌与暴涨,但本质上仍没有完成去中心化,合约依然存在诸多安全风险。在频繁和大幅度的涨跌中,常有参与者忘记了本心,最后导致亏空的结局。

从EIP-1967谈大火的“鱿鱼游戏SQUID”安全风险