背景 2020 年 8 月 5 日,Opyn 合约遭遇黑客攻击。慢雾安全团队在收到情报后对本次攻击事件进行了全面的分析,下面为大家就这次攻击事件展开具体的技术分析。 攻击细节 逻辑分析 看其中一笔攻击交易: https://etherscan.io/tx/0xa858463f30a08c6f3410ed456e59277fbe62ff14225754d2bb0b4f6a75fdc8ad 通过查看内联交易可以看到攻击者仅使用 272ETH 最终得到 467ETH 使用 OKO 合约浏览器对具体的攻击细节进行分析 https://oko.palkeo.com/0xa858463f30a08c6f3410ed456e59277fbe62ff14225754d2bb0b4f6a75fdc8ad/ 关键点在于 oToken 合约的exercise函数,从上图中可以看出在exercise函数中通过调用两次 transfer 将 USDC 发送给攻击者合约,接下来我们切入exercise函数进行具体的分析 function exercise( uint256 oTokensToExercise, address payable[] memory vaultsToExerciseFrom) public payable { for (uint256 i = 0; i < vaultsToExerciseFrom.length; i++) { address payable vaultOwner = vaultsToExerciseFrom[i]; require( hasVault(vaultOwner), "Cannot exercise from a vault that doesn't exist" ); Vault storage vault = vaults[vaultOwner]; if (oTokensToExercise == 0) { return; } else if (vault.oTokensIssued >= oTokensToExercise) { _exercise(oTokensToExercise, vaultOwner); return; } else { oTokensToExercise = oTokensToExercise.sub(vault.oTokensIssued); _exercise(vault.oTokensIssued, vaultOwner); } } require( oTokensToExercise == 0, "Specified vaults have insufficient collateral" ); } 可以看到exercise函数允许传入多个 vaultsToExerciseFrom,然后通过 for 循环调用_exercise函数对各个 vaultsToExerciseFrom 进行处理,现在我们切入_exercise函数进行具体的分析 function _exercise( uint256 oTokensToExercise, address payable vaultToExerciseFrom) internal { // 1. before exercise window: revert require( isExerciseWindow(), "Can't exercise outside of the exercise window" ); 1、在代码第 6 行首先检查了现在是否在保险期限内,这自然是肯定的 2、在代码第 11 行则对 vaultToExerciseFrom 是否创建了 vault 进行检查,注意这里只是检查了是否有创建 vault 3、在代码第 14、16、21 行对传入的 oTokensToExercise 值进行了检查,在上图 OKO 浏览器中我们可以看到攻击者传入了 0x1443fd000,这显然是可以通过检查的 4、接下来在代码第 28 行计算需要消耗的 ETH 数量 5、在代码第 35、41 行计算需要支付的数量与手续费 6、接下来在代码第 59 行对 underlying 是否是 ETH 地址进行判断,而 underlying 在上面代码第 31 行进行了赋值,由于 isETH 为 true, 因此将会进入 if 逻辑而不会走 else 逻辑,在 if 逻辑中 amtUnderlyingToPay 与 msg.value 都是用户可控的 7、随后对 oTokensToExercise 进行了燃烧,并调用 transferCollateral 函数将 USDC 转给exercise函数的调用者 以上关键的地方在于步骤 2 与步骤 6,因此我们只需要确保传入的 vaultToExerciseFrom 都创建了 vault,且使 amtUnderlyingToPay 与 msg.value 相等即可,而这些相关参数都是我们可以控制的,所以攻击思路就显而易见了。 思路验证 让我们通过攻击者的操作来验证此过程是否如我们所想: 1、首先在保险期限内是肯定的 2、攻击者传入的 vaultToExerciseFrom 分别为: 0xe7870231992ab4b1a01814fa0a599115fe94203f0x076c95c6cd2eb823acc6347fdf5b3dd9b83511e4 经验证,这两个地址都创建了 vault 3、攻击者调用exercise传入 oTokensToExercise 为 0x1443fd000 (5440000000),msg.value 为 272ETH,vaultsToExerciseFrom 分别为以上两个地址 4、此时由于此前攻击者创建的 oToken 为 0xa21fe800 (2720000000),及 vault.oTokensIssued 为 2720000000 小于 5440000000,所以将走exercise函数中的 else 逻辑,此时 oTokensToExercise 为 0xa21fe800 (2720000000),则以上代码第 60 行 msg.value == amtUnderlyingToPay 是肯定成立的 5、由于 vaultsToExerciseFrom 传入两个地址,所以 for 循环将执行两次_exercise函数,因此将 transfer 两次把 USDC 转给攻击者合约 完整的攻击流程如下 1、攻击者使用合约先调用 Opyn 合约的 createERC20CollateralOption 函数创建 oToken 2、攻击合约调用exercise函数,传入已创建 vault 的地址 3、通过exercise函数中 for 循环逻辑执行调用两次_exercise函数 4、exercise函数调用 transferCollateral 函数将 USDC 转给函数调用者(由于 for 循环调用两次_exercise函数,transferCollateral 函数也将执行两次) 5、攻击合约调用 removeUnderlying 函数将此前传入的 ETH 转出 6、最终攻击者拿回了此前投入的 ETH 以及额外的 USDC 攻击合约地址 0xe7870231992Ab4b1A01814FA0A599115FE94203f Opyn 合约地址 0x951D51bAeFb72319d9FBE941E1615938d89ABfe2 攻击交易(其一) 0xa858463f30a08c6f3410ed456e59277fbe62ff14225754d2bb0b4f6a75fdc8ad 修复建议 此次攻击主要是利用了_exercise函数中对 vaultToExerciseFrom 是否创建 vault 的检查缺陷。此检查未校验 vaultToExerciseFrom 是否是调用者自己,而只是简单的检查是否创建了 vault,导致攻击者可以任意传入已创建 vault 的地址来通过检查。 建议如下: 1、在处理用户可控的参数时应做好权限判断,限制 vaultToExerciseFrom 需为调用者本人。 2、项目方可以在项目初期或未完成多次严谨安全审计之前添加合约暂停功能与可升级模型,避免在发生黑天鹅事件时无法有效的保证剩余资金安全。 —- 编译者/作者:慢雾区 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
慢雾:Opyn 合约被黑分析
2020-08-05 慢雾区 来源:区块链网络
- 上一篇:8.5晚间行情:震荡盘局中的操作策略
- 下一篇:连胜解盘:EOS上行无力还是多头洗盘
LOADING...
相关阅读:
- 期货会刺激比特币价格(BTC)吗?2020-08-05
- 静如初子/动如脱兔——ALOKEX交易所赢在起步跑线2020-08-05
- eth2.0 未整理乱码笔记2020-08-05
- 墨菲言币:8月5日BTC大跌过后的震荡需要多久?2020-08-05
- 金融微期货数字货币永续合约平台招代理只做国外用户2020-08-05