风险提示:请理性看待区块链,树立正确的货币观念和投资理念,不要盲目跟风投资,本站内容不构成投资建议,请谨慎对待。 免责声明:本站所发布文章仅代表个人观点,与CoinVoice官方立场无关

全面揭露 bZx 闪电贷事件

加密谷Live
2020年02月19日

全面揭露 bZx 闪电贷事件

作者 | PeckShield

本文我们将介绍关于 bZx 攻击者的交易行为,该攻击者的交易行为最近占据了推文与媒体的头条。人们对该攻击者的性质存在很多误解。我们强调这不是针对 Oracle 的攻击。相反,这是一个聪明的套利行为。该攻击者利用了 bZx 智能合约执行中的一个漏洞,允许本应锁定的 bZx 资金流向 Uniswap,并进一步将流出资金吸收到一个 Compound 头寸中。我将通过深入的利润分析来揭露该攻击者的行为。
全面揭露 bZx 闪电贷事件bZx Hack I
全面揭露 bZx 闪电贷事件Bzx 事件的五个套利步骤

套利的五个步骤

罪魁祸首:0xb5c8bd9430b6cc87a0e2fe110ece6bf527fa4f170a4bc8cd032f768fc5219838 发生在 2020 年 2 月 15 日以太坊区块高度 9484688 期间。如上图所示,该攻击可以分成 5 个不同的步骤:Flashloan Borrow, Hoard, Margin Pump, Dump, Flashloan Repay。接下来,本文将逐一拆分每个步骤。 第一步: Flashloan Borrow。该步利用闪电贷的特性从 dYdX 中借出 10,000 个 ETH。这一部分不做细讲。
全面揭露 bZx 闪电贷事件
这步骤完成后,我们注意到攻击者具有以下细分资产。但是还没有产生收益。
全面揭露 bZx 闪电贷事件
第二步: Hoard。攻击者将 5, 500 个 ETH 存入 Compound 作为抵押品,并借出 112 个 WBTC。该步是正常 Compound 操作,而这些 WBTC 为第 4 步做准备。
全面揭露 bZx 闪电贷事件
完成此步骤后,我们看到攻击者控制的资产发生了以下变化。但很显然,还没有任何收益。
全面揭露 bZx 闪电贷事件
第三步: Margin Pump。该攻击者利用 bZx 的保证金交易功能做空 ETH,这有利于 WBTC (如 sETHWBTCx5)。该攻击者还存入 1,300 个 ETH,发起 bZx 保证金交易。保证金交易利用 KyberSwap 将借入的 5637.623762 个 ETH 换成 51.345576 个 WBTC。值得注意的是,做空 ETH 是借入的 5 倍。该互换实际上将 1 个 WBTC 的转化率提高到 109.8 个 WETH,大约是正常转化率的三倍。 具体来说,为了完成这一交易,bZx 将订单转发给 KyberSwap, KyberSwap 随后会查询其外汇储备并找到最佳汇率。这一步骤实质上使 Uniswap 中的 WBTC 价格上涨了三倍。
全面揭露 bZx 闪电贷事件
需要注意的是,内置的完整性检查应该阻止该步骤的行为,因为这个检查会验证头寸在交换之后不会变成默认值。然而,当攻击发生时,这个检查并没有生效,稍后我们将在之智能合约 bug 部分检查详细信息。 在这一步之后,我们注意到攻击者控制的资产发生了以下变化。然而,这一步之后仍然没有产生收益。
全面揭露 bZx 闪电贷事件
第四步: Dump。随着 Uniswap 中 WBTC 的价格飙升,攻击者以 Uniswap 中的价格将借来的 112 WBTC 抛售。
全面揭露 bZx 闪电贷事件
该步骤将获得 6871.4127388702245 个 ETH 的回报,总的转化率为 1WBTC=61.4WETH。
全面揭露 bZx 闪电贷事件
第五步: Flashloan Repay。利用 112 个 WBTC 转换的 6871.4127388702245 个 ETH,攻击者将归还 10,000 个 ETH 的 dYdX 闪电贷。 在此步骤后,我们重新计算资产明细。结果表明,攻击者获得了 71 个 ETH 的套利,再加上两个头寸,一个是 Compound (+5,500WETH/-112WBTC),另一个是 bZx (-4,337WETH/+51WBTC)。当 bZx 头寸处于默认状态时,Compound 头寸是非常有利可图的。显然,在攻击之后,攻击者马上开始安排支付 Compound 债务,归还 112WBTC 换回 5,500weth 抵押品。对于 bZx 头寸,因为它已经处于默认状态,所以攻击者没有表现出进一步的兴趣。
全面揭露 bZx 闪电贷事件
考虑到 1WBTC=38.5WETH (或 1WETH=0.025BTC) 的平均市场价格,攻击者可以用 4,300 个 ETH 兑换 112 个 WBTC。其结果是,加上之前的 71.4 个 ETH,攻击者大约获利 1,271 个 ETH,大约获利 355,880 美元(当时 ETH 价格约为 280 美金)。

bZx 智能合约中的 bug

最神奇的是 Uniswap 中的 WBTC/ETH 价格是如何被操纵至高达 61.4 的利润。如步骤 3 所述,WBTC/ETH 的价格甚至在正常市场价格仅为 38 左右时,就被推高到了 109.8。然而,如此巨大的价格下滑应该会导致 bZx 头寸未完全抵押。但为什么会允许抵押品不足,这自然会导致在 bZx 智能合约执行中发现隐藏的错误。 特别是,margin pump 从 marginTradeFromDeposit() 这项功能开始。
全面揭露 bZx 闪电贷事件
如上如所示,marginTradeFromDeposit() 利用 840 行设置为 true 的第四个参数调用_borrowTokenAndUse()。
全面揭露 bZx 闪电贷事件
在_borrowTokenAndUse() 中,当 amountIsADeposit 为 true 时,在第 1,348 行调用_getBorrowAmountAndRate()。返回的 borrowAmount 将会存入 sentAmounts[1]。
全面揭露 bZx 闪电贷事件
同样地,在_borrowTokenAndUse() 中,在 amountIsADeposit 为 true 时,第 1,355 行中的 sentAmounts[1] 的值会填充 sentAmounts[6](稍后我们将看到这一点)。随后,在第 1,370 行中调用_borrowTokenAndUseFinal()。
全面揭露 bZx 闪电贷事件
在第 1414 行,_borrowTokenAndUseFinal() 通过 IBZx 接口调用 takeOrderFromiToken(),以便交易流进入 bZxContract。
全面揭露 bZx 闪电贷事件
有趣的部分来了。在第 145 至 153 行,由一个 require() 来检查头寸是否健康。不幸的是,在 loadDataBytes.length == 0 && sentAmounts[6] == sentAmounts[1] 例子中,完整性检查 bZxOracle::shoudLiquidate() 将被跳过。这正是漏洞触发避免完整性检查的条件。
全面揭露 bZx 闪电贷事件
如果我们研究一下 bZxOracle::shouldLiquidate(,第 514 行 getCurrentMarginAmount() <= loanOrder.maintenanceMarginAmount 可以通过捕捉 margin pump 步骤来完成检查,从而防止这种攻击。
全面揭露 bZx 闪电贷事件bZx Hack II
2 月 18 日,就在官方公布黑客报告的几小时后,bZx 团队再次暂停了该协议。
全面揭露 bZx 闪电贷事件利用 Oracle 操作的五个步骤 PeckShield 的研究人员使用内部实时异常检测引擎检测到异常的交易模式,并立即对其进行研究。第二次攻击与第一次攻击不同,它实际上是 Oracle 攻击。在 Oracle 的操作中,它实际上采取了一种相反的方式,允许假定锁定的 bZx 资金直接流向攻击者控制的帐户,而不需要进一步将资金归还到 Compound 头寸中。具体来说,Oracle 操纵实质上提高了受影响数字货币(如 sUSD)的价格,并使其在 bZx 贷款系统中极具价值。然后,攻击者可以简单地将之前购买或储存的 sUSD 作为抵押品存入,而借入 WETH 以获取利润 (而不是出售)。在上图中,我们详细展示了这一行为背后的五个步骤 :Flashloan Borrow、Hoard、Pump、Collateralized Borrow、Flashloan payments。注意第四步是抵押借款,而不是抛售。接下来,我们将检查每个特定的步骤。

获利的五个步骤

该漏洞发生于 2020 年 2 月 18 日 18:13:58 时,以太坊区块高度为 9,504,627。罪魁祸首可以在 etherscan 上找到。如上述所言,这个攻击过程可以分为以下 5 个步骤: 第一步: Flashloan Borrow。这一步主要利用了 bZx 闪电贷的特点借入 7,500 个 ETH。值得注意的是,这个步骤与第一次攻击中的第一步相同。不同之处在于第二次攻击使用 bZx 而不是 dYdX 来进行闪电贷。因此,我们不在此处过多讨论该细节。
全面揭露 bZx 闪电贷事件
该步之后,我们注意到攻击者具有以下资产细分。但是还没有产生收益。
全面揭露 bZx 闪电贷事件
第二步: Pump。攻击者通过 Kyber 分两批将 900 个 ETH 交换为 sUSD。第一批在 KyberSwap 中卖出 540 个 ETH,在对储备金进行内部咨询之后,将掉期订单传递至 KyberUniswap 储备(0x31e085afd48a1d6e51cc193153d625e8f0514c7f)中,并得到 92,419 个 sUSD 回报。第二批价格是 ETH 的 18 倍,同样在 Kyber 中,在对储备金进行内部咨询之后,将掉期订单转至 Kyber-sUSD 储备(0x4cb01bd05e4652cbb9f312ae604f4549d2bf2c99),并得到 63,584 个 sUSD。这两批抛售有效地推动了 sUSD 的价格上涨到 0.00899ETH (或 1ETH=111sUSD)。与 ETH/sUSD 的平均市场价格相比,被操纵的价格大约高出平均市场价格的 2.5 倍。 通过以上操作后,攻击者获得 92,419+63,584=156,003 个 sUSD。
全面揭露 bZx 闪电贷事件
此步骤后,我们注意到攻击者控制的资产发生以下改变。但是仍没有产生收益。
全面揭露 bZx 闪电贷事件
第三步: Pump。接下来,攻击者转向 Synthetic Depot 合同以市场价格获得更多的 sUSD。值得注意的是 Synthetic Depot 合同允许以公平价格的 sUSD 存入 ETH。我们的分析显示,攻击者发送了 6,000 个 ETH 并回购了 943,837 个 sUSD(由于没有足够的 sUSD,有 2,482 个 ETH 被退回)。请注意,此步骤通常在 Pump 步骤之前启动。无论出于何种原因,在这次的黑客攻击中,情况并非如此 (订购不会影响最终结果,因为 Synthetic Depot 价格不受 KyberSwap 的影响)。
全面揭露 bZx 闪电贷事件
完成此步骤后,攻击者将拥有 100 万个 sUSD,约占 sUSD 总供应量的 20%!我们还注意到攻击者的资产发生了以下变化,但仍未产生任何收益。
全面揭露 bZx 闪电贷事件
第四步: Collateralized Borrow。正如之前所讨论的那样,到目前为止,攻击者已经显著地推高了 sUSD/ETH 价格,并拥有超过 100 万个 sUSD 可供使用。请注意,在第一次攻击中,攻击者采取的方法是在一个有利可图的 Compound 头寸中利用上涨的价格。考虑到 sUSD 的流动性可能较低,攻击者这次采取的方法是先将收集到的 100 万个 sUSD 抵押回 bZx,然后向 bZx 借款 6796 个 ETH。由于 bZx 依靠 Kyber 作为价格来源,在 sUSD/ETH 价格飙升的情况下,拥有的 1 百万个 sUSD 可以借入 6,796 个 ETH。按照正常的 1ETH=111 sUSD 的兑换率,同样数量的 sUSD 代币只能购买 4,000 个 ETH,这说明这笔贷款已经资不抵债,担保不足。
全面揭露 bZx 闪电贷事件全面揭露 bZx 闪电贷事件
第五步: Flashloan Repay。借入的 6,796 个 ETH(加上剩余的 7,500—900—6,000—2,482=3,082 ETH),攻击者可以将 7,500 个 ETH 归还给 bZx,获利 2,378 个 ETH 的利润。
全面揭露 bZx 闪电贷事件
简单回顾一下,在这次交易中,攻击者获得 2378 个 ETH 的利润,并留下 bZx 头寸 (+1,099,841 sUSD/-6,796 ETH)。显然,攻击者没有进一步的兴趣,并带走了 2,378 个 ETH,约合 665,840 美元(假设 ETH 的价格为 280 美元)。

全面揭露 bZx 闪电贷事件

PeckShield 作者 *Zoe Zhou *翻译

Roy Wang 编辑

内容仅供参考 不作为投资建议 风险自担

版权所有 未经允许 严禁转载

全面揭露 bZx 闪电贷事件

全面揭露 bZx 闪电贷事件

全面揭露 bZx 闪电贷事件

全面揭露 bZx 闪电贷事件

全面揭露 bZx 闪电贷事件

全面揭露 bZx 闪电贷事件

☟☟☟


声明:本内容为作者独立观点,不代表 CoinVoice 立场,且不构成投资建议,请谨慎对待,如需报道或加入交流群,请联系微信:VOICE-V。

评论0条

加密谷Live

简介:分享区块链领域专业、前沿、有趣的内容

专栏

更多>>