DeFi平台Opyn智能合约漏洞解析 攻击者空手套白狼

PeckShield view 11816 2020-8-6 14:23
share to
Scan QR code with WeChat

2020年8月5日,DeFi 期权平台 Opyn 的看跌期权(Opyn ETH Put)智能合约遭受到了黑客攻击,损失了大概37万美元。

Opyn 是一个通用期权协议,于今年2月份转型为保险平台,通过 oTokens 为 DeFi 平台提供可交易的 ETH 看跌期权,以此锚定 ETH 市场价格,为高波动性的 DeFi 市场提供相对的稳定性。

PeckShield 安全团队获悉 Opyn 平台遭受攻击后,迅速定位到问题关键点在于:

攻击者发现 Opyn 智能合约行权(exercise)接口对接收到的 ETH 存在某些处理缺陷,其合约并没有对交易者的实时交易额进行检验,使得攻击者可以在一笔对自己发起真实的交易之后,再插入一笔伪装交易骗得卖方所抵押的数字资产,进而实现空手套白狼。

简单来说,由于 Opyn ETH Put 智能合约中的行权函数 exercise() 没有对交易者的ETH 进行实时校验。根据 Opyn 平台的业务逻辑,看跌期权的买方给卖方转移相应价值的 ETH,即可获得卖方抵押的数字资产。狡猾的攻击者,先向自己发起伪装的交易,利用这笔 ETH 可以重复使用的特性,再次向卖方用户发起转账,进而骗取卖方已经抵押的数字资产。

下面为您详细分析漏洞原因及攻击过程。

漏洞详细过程分析

先来说说,Opyn 平台的业务逻辑:当用户使用 Opyn 合约行权即买卖期货(exercise)时,需要买方向卖方转入相应数量的 ETH 或者 ERC20 Token,然后合约将销毁买方对应的 oToken,而后买方将获得卖方已经抵押的资产。

例如:小王认为行情进入了下跌趋势,看到 Opyn 上挂着一个小李对 ETH 330美元的看跌期权,于是进入交易系统,向小李转账一个 ETH,获得小李抵押的等额数字资产。若此刻行情已经跌至了300美元,小王便可获得其中的差价。

DeFi平台Opyn智能合约漏洞解析 攻击者空手套白狼

图1. exercise() 函数中循环执行传入的 vaults 地址列表

如上面的合约代码片段所示,行权函数 exercise() 的内部是一个循环,依据参数中传递的 vaultsToExerciseFrom 中的地址数量依次调用真正的行权逻辑 _exercise() 函数。

DeFi平台Opyn智能合约漏洞解析 攻击者空手套白狼

图2. 重用传入合约的 ETH 来获得抵押资产

函数处理 ERC20 Token 时,和大部分的 DeFi 项目做法一样,使用 transferFrom(),如代码 1882 行所示,从 msg.sender 转账到 address(this)。

但是当函数处理的资产为 ETH 时,处理的方式就完全不一样了。因为在 Solidity 中,msg.value 的意思是合约调用者在调用具有 payable 接口时所转给该合约的 ETH 数量,仅是一个量值,所以在合约代码的 1879 行中,检查 msg.value == amtUnderlyingToPay 仅能确保合约确实收到了 amtUnderlyingToPay 数量的 ETH,并不会对 msg.value 的值造成任何影响。

但是正如上面讲到的在 exercise() 中会循环调用 _exercise() 函数,这导致尽管合约实际只收到一次ETH,然而在循环过程中却可以重复使用。

攻击点就在这里,由于合约少了一步对 ETH 实时数量的检验,使得攻击者可以先伪造一笔指向自己的交易,然后再把已经花掉的本金再次利用,和平台其他用户完成一笔正常交易。

DeFi平台Opyn智能合约漏洞解析 攻击者空手套白狼

图3. 攻击交易分析

在图3中,我们通过 Bloxy 浏览器显示的调用过程来展示攻击的过程。由于攻击者吃掉了很多笔订单,我们以其中一笔交易为例,向大家展示其攻击逻辑:

1、攻击者先从 Uniswap 购入了 75 oETH 为进一步调用函数行权做好筹备;2、攻击者创建了一个 Vault 地址,作为看空期权卖方,并且抵押24,750 USDC 铸造出75 oETH,但并未卖出这些期权,等于自己同时买入了以 330 的价格卖出75 ETH 的权利;3、攻击者在 Opyn 合约中调用了 exercise(),在持有 150 oETH 看空期权的情况下,先向自己的 Vault 地址转入了75个 ETH,获得自己事先抵押的 24,750 个 USDC,再重利用了这75个 ETH,成功吃掉了另一个用户的 24,750 个 USDC,进而实现非法获利。

修复建议

PeckShield 安全团队建议,在 Solidity 中,合约可使用一个局部变量 msgValue 来保存所收到 ETH(即 msg.value 的值)。这样,在后续的步骤中通过操作 msgValue ,就能准确的标记有多少 ETH 已经被花费,进而避免资产被重复利用。此外,我们还可以使用 address(this).balance 来检查合约余额来规避 msg.value 被重复使用的风险。

PeckShield 作为业内领先的区块链安全公司,安全业务已覆盖全球范围,主要客户包括有:公链提供商 (EOS、Nervos、Harmony、AVA、HBTC、NEO 、IOST、Bytom、TRON、OKChain),头部钱包和矿池 (imToken、SparkPool、比特派、Cobo 金库,VoiceWallet),以及头部交易所(Huobi、KuCoin、Bithumb、Upbit、OKex)、DeFi 应用及智能合约(MakerDAO、StarkWare、bZx、Aave、Tokenlon、InstaDApp、Set Protocol、Zerion、Ren Project、Hydro Protocol、dForce、Newdex、HoneyLemon)等。

近一年内,PeckShield 已经接连审计了数十个 DeFi 项目,帮助 DeFi 协议做代码安全审计、业务逻辑风控、威胁情报风险预警等等,已经成为服务 DeFi 领域的头部安全公司。

btcfans公众号

Scan QR code with WeChat

Disclaimer:

Previous: 一文解读热门项目Filecoin的经济模型与矿工经济行为 Next: DeFi领域近期三大事:Balancer、Bancor V2和YFI克隆体

Related