7

狸猫换太子:Vee Finance 安全事件再分析

 2 years ago
source link: https://www.tuoluocaijing.cn/technology/detail-10070064.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

狸猫换太子:Vee Finance 安全事件再分析

BlockSec_Team 原创 2021-09-23 07:45 热度 305555
分享

微信扫一扫:分享



微信里点“发现”,扫一下 二维码便可将本文分享至朋友圈

在昨天(2021年9月22日)Vee Finance项目发生攻击事件之后,我们第一时间对该事件开展分析并发布了初步的分析报告(似曾相识燕归来:Vee Finance 安全事件分析)。但在分析过程中,依然存在一些悬而未决的疑点:

在攻击交易中createOrderERC20ToERC20函数调用,有一个cToken行为比较奇怪,和这个地址相关的交易只有几十条;后续查明这个cToken是由攻击者控制的账户创建的。

在重新Review Vee项目的代码中,我们发现前一篇文章中发现整个发起杠杆交易的borrowAndCall调用并没有对第一笔交换的价值进行判断这个分析是不确切的。下文会阐述,在整个调用过程中存在对交换前后的价值进行判断的代码逻辑。

在分析攻击交易的Trace中,我们发现了一个奇怪的BTC代币地址,该地址和前一篇文章所述的攻击过程并无关联。

在我们的分析报告发布之后,项目方也公布了自己的官方分析报告(The Main Cause of Vee Finance Attack: https://veefi.medium.com/the-main-cause-of-vee-finance-attack-7a8475085ec5),然而该报告依然无法解释上述疑问。鉴于此,我们对Vee项目和此次攻击事件进行了更为细致的分析和复盘。分析结果表明,导致此次攻击的根本原因是校验机制的缺陷,而非如官方分析报告宣称的,诸如单一价格预言机等因素带来的影响。

0x1. 深入分析Vee项目代码

在后续对Vee项目方的代码进行深入分析的过程中,我们发现上述的检验过程其实是存在的,只是在攻击者巧妙利用下检查被绕过。下面我们来分析如何检查和攻击者如何绕过的过程:

75%7Cimageslim

首先在createOrderERC20ToERC20函数中,红色箭头标注的getAmountOutMin调用会对交换前后的价值进行检查。当然,我们首先注意到在整个函数调用中,并没有对cToken的真实性做检查。也就是说,攻击者可以自己创建一个cToken并调用createOrderERC20ToERC20函数创建一个订单。这为攻击者的攻击埋下了伏笔。

75%7Cimageslim

在getAmountOutMin函数中,对第一次交换前后的价值是这样做判断的:

首先获得传入和传出的cToken(ctokenA和ctokenB),从PriceOracle中调用getUnderlyingPrice获得其Underlying代币的价格。

计算调用calcSwapAmount,扣除交易费用,计算真正的swapAmountA = amountA * leverage * (1 - serviceFee)。

计算由Oracle返回的应该转出的tokenA的估计量,即amountFromOracle = (priceA * swapAmountA) / priceB。

调用getAmountOut,返回从Pangolin交易所真正返回的转出tokenA的数量amountOut。

对比Oracle返回的tokenA转出估计量amountFromOracle和具体数量amountOut。如果amountFromOracle * 0.95 > amountOut,代表真正交易获得的tokenB过少,则需要拒绝这笔交易。

第二次Review整个逻辑实现,我们注意到这里有几次调用cToken的underlying()函数的过程:

第一次在createOrderERC20ToERC20函数中,获得了tokenA、tokenB,后续函数中几乎所有需要用到Underlying的地方传入的都是这两个Token。

第二次在createOrderERC20ToERC20的getAmountOutMin调用中。如上文所述,这个调用的主要目的是检验此次Swap前后的价值是否一致,项目方本身是否受损。

那么在getAmountOutMin中是怎么检验的呢?我们重述一下这个过程:

重新调用underlying()函数获得tokenA和tokenB。

从PriceOracle获得ctokenA和ctokenB对应的Underlying价格。在这个过程中会再次调用underlying()获得cToken对应的Underlying。

用第一步获得的tokenA和tokenB,去Pangolin查询能换得的tokenB数量,并与PriceOracle的数量进行比较。

一般来说这个过程是没有问题的,这是由于正常的cToken合约,其Underlying是固定的。但是在整个过程中没有对cToken是否真实进行验证,这导致攻击者可以传入自己设置的cToken合约。

而攻击者又是如何巧妙运用这个不一致性的呢?

在createOrderERC20ToERC20调用开头,让underlying()函数返回LINK代币。因此后续真正执行的交易是WETH兑换LINK。

在getAmountOutMin函数中,让underlying()函数返回BTC代币,使这一步兑换价值校验能够通过。

更为巧妙的是,由于swapERC20ToERC20的第四个参数(如下图所示)依赖getAmountOutMin函数返回的结果,因此攻击者选取了BTC这个价值较高的代币,使得合约对交换获得的代币数量的下限要求很低。

校验完成后,真正执行的交易是在攻击者创建的不平衡交易对中,将WETH兑换为LINK的交易,成功用少量的LINK套出了Vee合约的WETH。

75%7Cimageslim

通过巧妙地设计了underlying()函数,攻击者成功地“狸猫换太子”,将(Vee合约认为的)BTC替换成了LINK。再根据之前所述的过程将Vee合约中锁仓的流动性套出,完成了此次攻击。

当然,项目方还是做了许多检查。在createOrderERC20ToERC20中,合约调用了一个检查函数进行检查,其中对转出Token做了检查:

75%7Cimageslim

也就是说,每个杠杆交易的第一步交易,转入的Token(也就是代理合约使用杠杆借入的资金换得的Token)必须是在项目方自己控制的白名单内的。

总结来说,项目方的两个疏忽导致了此次攻击:

没有对用户创建订单时传入的cToken进行验证。任何人都可以创建一个cToken,然后创建这个cToken对应的订单。

没有在Pangolin创建项目支持Token的交易对,或者说没有维持交易对的流动性。只有维持了交易对的流动性,杠杆交易的第一次交换才能换到等值的代币。

0x2. 关于官方分析报告

在攻击发生不久后,Vee项目官方发布了分析攻击原因的报告(https://veefi.medium.com/the-main-cause-of-vee-finance-attack-7a8475085ec5)。其中项目方认为导致攻击的原因有以下几个:

价格预言机只有一个价格来源,因此这个价格受到了市场波动的影响。

价格处理时没有考虑不同Token的decimals可能不同。

交易对在交易时没有设立白名单机制。

首先,Vee项目的价格预言机并没有开源。但由于Vee是一个借鉴Compound的项目,而Compound的预言机是开源的,从源码中可以看出:

75%7Cimageslim

Compound的预言机在计算Underlying价格时是考虑了不同Token的decimals可能不同这种情况的。除非Vee项目对Compound预言机进行了大幅修改,否则预言机不太可能是导致此次攻击的罪魁祸首。事实上,攻击交易中预言机返回的报价如下图所示:

75%7Cimageslim

注意这里的16进制值0x15e1549d1216fe9fc032e7c00000对应的十进制值为443783124870000000000000000000000,正好是当时BTC的价格,可以作为预言机清白的旁证。

同样在之前的分析中可以看出,Vee是对杠杆交易能够换到什么代币做了严格的白名单检查的。因此白名单检查也不能为此次攻击背锅。

综上所述,真正导致攻击的问题在于校验机制的缺陷:创建订单的cTokenB(杠杆交易第一笔交易要兑换获得的Token),其地址是用户(通过order参数)可以完全控制的;而直到订单执行的整个过程中,该地址都是被直接使用的,并未经过任何校验。

0x3. 结语

本次攻击手法隐蔽而巧妙,整个分析过程也是百转千折。当然,在这一过程中我们也有很多收获。安全之路上,“博学之,审问之,慎思之,明辨之,笃行之”,诚哉斯言!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK