可升级合约漏洞—Web3音乐平台Audius被黑事件分析
作者: 日期:2022年07月26日 阅:2,601

2022年7月24日消息,黑客从音乐流媒体协议Audius转移了1800万个AUDIO代币,损失约600万美元。

SharkTeam第一时间对此事件进行了技术分析,并总结了安全防范手段,希望后续项目可以引以为戒,共筑区块链行业的安全防线。

一、事件分析

攻击者发起攻击交易如下:

攻击者发起了两次攻击,其中第一次攻击失败,第二次攻击成功。

攻击者地址:0xa0c7bd318d69424603cbf91e9969870f21b8ab4c

第一次攻击如下:

攻击合约:0xa62c3ced6906b188a4d4a3c981b79f2aabf2107f

攻击交易:0x3bbb15f9852c389e8d77399fe88b49b042d0f22aad4a33c979fbabc60a34b24f

交易中提交了84号提案

在提案并没有投票,所以也没有被执行,但该交易通过调用Governance合约的初始化函数并对提案82和83进行评估,修改了其状态:

接下来,我们以第二次攻击发起的交易来说明整个攻击的过程。

攻击合约地址:0xbdbb5945f252bc3466a319cdcc3ee8056bf2e569,简记为0xbdbb

攻击者在创建了攻击合约后,通过攻击合约发起了攻击,包含4笔交易:

交易1 txHash: 0xfefd829e246002a8fd061eede7501bccb6e244a9aacea0ebceaecef5d877a984

该交易包含了7个 步骤,如下:

1. 通过Audius的代理合约对Governance合约进行初始化

初始化函数如下:

该初始化函数对投票系统进行初始化,变量说明以及参数设置如下:

(1)registryAddress:注册代理合约地址,设置为攻击合约地址;

(2)votingPeriod:治理提案开放投票的区块周期,设置为3,即3个区块内可以投票,第4个及其之后的区块不可以再进行投票;

(3)exectionDelay:投票期结束后必须通过的区块数才能评估/执行提案,设置为1,即投票期结束后再经过1个区块才能执行,或者说结束投票后需等待1个区块才可以评估/执行提案;

(4)votingQuorumPercent:投票认为提案有效所需的总股份的最低百分比,设置为1;

(5)maxInProgressProposals:一次性可能处于InProgress状态的最大提案数量,设置为4;

(6)guardianAddress:具有特殊治理权限的账户地址,设置为攻击合约。

之所以如此设置参数,是为了让提案可以不需要复杂的多方投票就可以进行执行。

2. 评估/执行84号提案,即第一次攻击提交的提案,评估为QuorumNotMet

原因是没有投票。

3. 查询Governance代理合约的AUDIO代币余额

4. 提交85号提案,与84号提案相同。该提案的功能就是将Governance代理合约中的AUDIO转移到攻击合约,数量不能超过Governance代理合约的AUDIO余额。

5. 通过代理合约对Staking合约进行初始化

将治理代币地址以及代理合约地址都设置为攻击合约。

6. 通过代理合约对DelegateManagerV2合约进行初始化

将治理代币地址以及代理治理地址都设置为攻击合约。

7. 通过代理合约将DelegateManagerV2合约中的服务提供者工厂合约为攻击合约

8. 通过代理合约将质押的代理权授权给攻击合约,授权的代币数量为1e31

通过以上步骤,攻击者篡改并获取了治理系统的最高权限。

然后攻击者在提交了提案85之后的3个区块内进行了投票,即第2笔交易:

交易2 txHash: 0x3c09c6306b67737227edc24c663462d870e7c2bf39e9ab66877a980c900dd5d5

投票完成后,攻击者在3个区块的投票期以及1个区块的等待期之后对提案85进行了评估/执行,即第3笔交易:

交易3 txHash: 0x4227bca8ed4b8915c7eec0e14ad3748a88c4371d4176e716e8007249b9980dc9

执行提案85,将18,56万枚AUDIO转移到攻击合约。

攻击合约收到1800万枚AUDIO后,将其兑换为704 枚ETH,即第4笔交易:

交易4 txHash: 0x82fc23992c7433fffad0e28a1b8d11211dc4377de83e88088d79f24f4a3f28b3

最后,攻击者将兑换的ETH存入到了Tornash平台:

从以上攻击过程中,我们发现攻击者之所以能够攻击成功,根本原因在于通过代理合约多次调用初始化函数,而初始化函数本应该只能调用一次的。以Governance合约中的初始化函数为例,其代码如下:

这里使用了Openzeppelin里面的初始化器initializer,代码如下:

明显,initializer没有起到任何作用,原因在于代理调用。这里实现合约中定义的两个bool类型的状态变量initialized和intializing分别占用了存储插槽slot0中的前16个字节。第1个8字节为initialized,第2个8字节为initializing。由于代理合约本身定义了一个地址类型的状态变量proxyAdmin,其值为0x80ab62886eacfebca74511823d4699eb88fd097e,同样占用了存储插槽slot0,第1个8字节为0,第2个8字节为0x80ab6288,第3个8字节为0x6eacfebca7451182,第4个8字节为0x3d4699eb88fd097e.

于是,实现合约中的initialized和intializing与代理合约中的proxyAdmin同时占用了存储插槽slot0,从而引起了存储冲突。

插槽0中的数据分布如下:

初始化函数执行到initializer时,从存储插槽slot0的第1个8字节读取initialized,其值为0,即false;从存储插槽slot0的第2个8字节读取initializing,其值为0x80ab6288 > 0,即true。

因此,初始化器initializer完全没有任何作用。

二、安全建议

引发本次攻击事件的根本原因是可升级合约的实现过程中,代理合约与实现合约的存储出现冲突,导致初始化器initializer完全失去了作用。针对该漏洞,我们建议在使用可升级合约时首先要熟悉代理模式,对合约数据和逻辑做好规划,避免出现数据冲突、丢失等问题。另外,选择多个智能合约审计团队进行多轮审计,也是提高合约安全性的重要保障。

关于我们

SharkTeam的愿景是全面保护Web3世界的安全。团队成员分布在北京、南京、苏州、硅谷,由来自世界各地的经验丰富的安全专业人士和高级研究人员组成,精通区块链和智能合约的底层理论,提供包括智能合约审计、链上分析、应急响应等服务。已与区块链生态系统各个领域的关键参与者,如Huobi Global、OKC、polygon、Polkadot、imToken、ChainIDE等建立长期合作关系。

Web:https://www.sharkteam.org

Telegram:https://t.me/sharkteamorg

Twitter:https://twitter.com/sharkteamorg

Reddit:https://www.reddit.com/r/sharkteamorg

更多区块链安全咨询与分析,点击下方链接查看

D查查|链上风险核查 https://m.chainaegis.com

关键词:

申明:本文系厂商投稿收录,所涉观点不代表安全牛立场!


相关文章