专栏名称: 加密谷Live
加密谷(Crypto Valley Live)是亚洲领先的金融科技媒体、服务和社群平台,提供区块链领域全案服务
目录
51好读  ›  专栏  ›  加密谷Live

全面揭露 bZx 闪电贷事件

加密谷Live  · 公众号  ·  · 2020-02-19 18:30

正文


作者 |  PeckShield


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

bZx Hack I

Bzx事件的五个套利步骤

套利的五个步骤


罪魁祸首:
0xb5c8bd9430b6cc87a0e2fe110ece6bf527fa4f170a4bc8cd032f768fc5219838发生在2020年2月15日以太坊区块高度9484688期间。 如上图所示,该攻击可以分成5个不同的步骤: Flashloan Borrow, Hoard, Margin Pump, Dump, Flashloan Repay。 接下来,本文将逐一拆分每个步骤。
第一步: Flashloan Borrow。 该步利用闪电贷的特性从dYdX中借出10,000 个ETH。 这一部分不做细讲。

这步骤完成后,我们注意到攻击者具有以下细分资产。 但是还没有产生收益。

第二步: Hoard。 攻击者将5, 500个ETH存入Compound作为抵押品,并借出112个WBTC。 该步是正常Compound操作,而这些WBTC为第4步做准备。

完成此步骤后,我们看到攻击者控制的资产发生了以下变化。 但很显然,还没有任何收益。


第三步: 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价格上涨了三倍。

需要注意的是,内置的完整性检查应该阻止该步骤的行为,因为这个检查会验证头寸在交换之后不会变成默认值。 然而,当攻击发生时,这个检查并没有生效,稍后我们将在之智能合约 bug部分检查详细信息。
在这一步之后,我们注意到攻击者控制的资产发生了以下变化。 然而,这一步之后仍然没有产生收益。

第四步: Dump。 随着Uniswap中WBTC的价格飙升,攻击者以Uniswap中的价格将借来的112 WBTC抛售。

该步骤将获得6871.4127388702245个ETH的回报,总的转化率为1WBTC=61.4WETH。

第五步: 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头寸,因为它已经处于默认状态,所以攻击者没有表现出进一步的兴趣。

考虑到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()这项功能开始。

如上如所示,marginTradeFromDeposit()利用840行设置为true的第四个参数调用_borrowTokenAndUse()。

在_borrowTokenAndUse()中,当amountIsADeposit为true时,在第1,348行调用_getBorrowAmountAndRate()。 返回的borrowAmount将会存入sentAmounts[1]。

同样地,在_borrowTokenAndUse()中,在amountIsADeposit为true时,第1,355行中的sentAmounts[1]的值会填充sentAmounts[6](稍后我们将看到这一点)。 随后,在第1,370行中调用_borrowTokenAndUseFinal()。

在第1414行,_borrowTokenAndUseFinal()通过IBZx接口调用takeOrderFromiToken(),以便交易流进入bZxContract。

有趣的部分来了。 在第145至153行,由一个require()来检查头寸是否健康。 不幸的是,在loadDataBytes.length == 0 && sentAmounts[6] == sentAmounts[1]例子中,完整性检查bZxOracle::shoudLiquidate()将被跳过。 这正是漏洞触发避免完整性检查的条件。

如果我们研究一下bZxOracle::shouldLiquidate(,第514行getCurrentMarginAmount() <= loanOrder.maintenanceMarginAmount可以通过捕捉margin pump步骤来完成检查,从而防止这种攻击。
bZx Hack II

2月18日,就在官方公布黑客报告的几小时后,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来进行闪电贷。 因此,我们不在此处过多讨论该细节。

该步之后,我们注意到攻击者具有以下资产细分。 但是还没有产生收益。

第二步: 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。

此步骤后,我们注意到攻击者控制的资产发生以下改变。 但是仍没有产生收益。

第三步: Pump。 接下来,攻击者转向Synthetic Depot合同以市场价格获得更多的sUSD。 值得注意的是Synthetic Depot合同允许以公平价格的sUSD存入ETH。 我们的分析显示,攻击者发送了6,000个ETH并回购了943,837个sUSD(由于没有足够的sUSD,有2,482个ETH被退回)。 请注意,此步骤通常在Pump步骤之前启动。 无论出于何种原因,在这次的黑客攻击中,情况并非如此(订购不会影响最终结果,因为Synthetic Depot价格不受KyberSwap的影响)。

完成此步骤后,攻击者将拥有100万个sUSD,约占sUSD总供应量的20%! 我们还注意到攻击者的资产发生了以下变化,但仍未产生任何收益。






请到「今天看啥」查看全文