首页 > 区块链 > 区块链资讯PeckShield:技术拆解 DeFi 协议 Akropolis 被盗 200 万美元攻击过程
  • 评论(0)

分享到

微博

微信

QQ

PeckShield:技术拆解 DeFi 协议 Akropolis 被盗 200 万美元攻击过程

区块链资讯 2020-11-13 16:41:00
黑客利用 Akropolis 合约漏洞连续实施了 17 次重入攻击,导致其 yCurve 和 sUSD 资金池损失了 203 万枚 DAI。原文标题:《DeFi 协议 Akropolis 漏洞详解:黑客复现「经典重入攻击」掳走 203 万 DAI》 撰文:PeckShield昨天晚间 19 时 50 分,DeFi 协议 Akropolis 遭到了黑客攻击。区块链安全公司 PeckShield (派盾)安全人员迅速定位到问题在于,Akropolis 项目的 SavingsModule 合约在处理用户存储资产时存在某种缺陷,黑客利用此缺陷连续实施了 17 次重入攻击,导致其 YCurve 和 sUSD 资金池损失了 203 万枚 DAI。PeckShield:技术拆解 DeFi 协议 Akropolis 被盗 200 万美元攻击过程

技术概要

本次攻击的原因如下:
  • 合约没有对用户存储的 Token 进行白名单校验
  • 关键的 deposit 函数没有对重入攻击的保护
  • 简单而言:黑客利用 Akropolis 项目存在的存储资产校验缺陷,向合约发起连续多次的重入攻击,致使 Akropolis 合约在没有新资产注入的情况下,凭空增发了大量的 pooltokens,进而再利用这些 pooltokens 从 YCurve 和 sUSD 池子中提取 DAI,最终导致项目合约损失了 203 万枚 DAI。

    攻击过程详解

    攻击流程复现:我们通过分析黑客实施攻击的交易哈希 (0xe1f375a47172b5612d96496a4599247049f07c9a7d518929fbe296b0c281e04d) 发现,攻击来自于一个恶意的 ERC20 合约地址 (0xe2307837524Db8961C4541f943598654240bd62f)这个恶意合约实现了一个钩子函数,使得函数在 transferFrom() (function signature: 0x23b872dd) 被调用的时候会被执行。攻击者先是调用 SavingsModule.sol 中的 deposit() 函数,并将自己编写的位于 0xe230 开头的恶意合约作为要存储的代币地址传入。当其恶意代币的 transferFrom() 函数被调用时,其钩子函数会再次调用 deposit() 函数并存入真实的 DAI 资产。由于 pooltokens 增发的量通过代币 deposit 前后余额的差值得出。所以第二次 deposit 的真实的 DAI 资产会被计算两次用于铸造 pooltokens。第一次是在恶意合约 0xe230 存储的时候,第二次是在 DAI 存储的时候。也就是说,如果第二次存储的时候存入了 25K DAI, 那么由于重入攻击,总的铸造的 pooltokens 将会是双倍,也就是 50K DAI 。PeckShield:技术拆解 DeFi 协议 Akropolis 被盗 200 万美元攻击过程以此类推,黑客总共发起 17 次重入攻击并获得了总共 2,030,841.0177 个 DAI 资产。值得注意的是,在攻击的最开始,攻击者还使用了 dYdX 的 闪贷功能。

    核心漏洞详解

    接下来,我们分析下存在漏洞的代币存储逻辑。Akropolis 的用户可以将代币存储入 Delphi Savings Pools,而资金池会铸造相应的 pooltokens 给用户。核心逻辑在 SavingsModule::deposit()(1,944 行)。PeckShield:技术拆解 DeFi 协议 Akropolis 被盗 200 万美元攻击过程第一步:攻击者调用 deposit() 函数并提供 _tokens 参数。这个函数在进一步调用 depositToProtocol(_protocol,_tokens,_dnAmounts) 前后会计算代币的余额,并通过代币余额的变化来决定将要铸造的 poolTokens 数目 (第 1,970 行)。而 depositToProtocol() 函数会调用目标代币的 safeTransferFrom() 函数来进行代币的转账 (第 2,004 行)。然而 deposit() 函数没有对重入攻击进行检测,也没有检查存入的代币是否为恶意代币;第二步:在恶意代币的 transferFrom() 函数被调用的时候,触发钩子函数,从而再次调用 deposit() 函数;第三步:因为第二次调用 deposit() 函数的时候攻击者存入了真正的 DAI 代币使得池子的代币余额发生变化,所以攻击者可以获得资金池铸造的 poolTokens;第四步:当第二次 deposit() 函数调用结束的时候,代码执行流程将返回第一次存储代币调用 depositToProtocol() 函数的上下文。这个时候,代币余额变化将被再次计算。此时代币余额的变化和第二次调用 deposit() 函数代币余额变化一样。因此攻击者可以再次获得相应数目的 poolTokens。

    被盗资产情况

    这次攻击的被盗资产目前被存储在钱包 0x9f26 中。PeckShield 旗下数字资产追踪平台 CoinHolmes 正在对该地址做全方位监控,并对其资金流向做进一步的锁定分析和追踪,以便协助项目方挽回被盗资产。来源链接:mp.weixin.qq.com
    文章来源于网络,不代表天眼观察www.wdtygc.com网站立场,如发现有害或侵权内容,请与我们联系。