SharkTeam独家分析 | 可升级合约漏洞—Web3音乐平台Audius被黑事件分析
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等建立长期合作关系。
Bitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
Bitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
Justin Sun suspected to have purchased $160m in Ethereum
Justin Sun suspected to have purchased $160m in Ethereum