#9:MEV 机器人 0xd61492:从捕食者到猎物的绝妙漏洞利用

2023年8月3日,Arbitrum 上的一款 MEV 机器人遭到攻击,损失达80万美元。此次攻击的根本原因是**用户输入验证不足**。

#9:MEV 机器人 0xd61492:从捕食者到猎物的绝妙漏洞利用

2023年8月3日,Arbitrum上的一个MEV Bot遭到攻击,导致80万美元的损失。此次攻击的根本原因是用户输入验证不足

考虑到MEV Bot与其合约之间复杂的交互未经验证,这表明非开源并不保证安全,尤其对于DeFi协议而言。

背景

MEV Bot

MEV Bot(最大可提取价值机器人)旨在识别并执行区块链上的盈利机会。 它通过分析待处理的交易(即内存池中的交易)或链上状态来产生套利利润。

与典型的抢先交易和三明治攻击MEV Bot不同,此次攻击的目标MEV Bot专注于执行套利和债务清算等策略。这些Bot本身有助于稳定AMM的价格,并协助借贷协议进行清算以确保顺畅运行,构成了DeFi生态系统健康运行的重要组成部分。

Flashloan

Flashloan代表了DeFi生态系统中的一项独特创新——一种无抵押借贷形式。通过Flashloan,您可以借入高达十亿美元的资金,而无需任何抵押品,前提是贷款必须在同一笔交易中偿还。如果在同一笔交易中未偿还贷款,则该交易将被撤销,就好像交易从未发生过一样。

这种机制通常用于套利或利用其他DeFi策略来剥削临时的市场低效率。

漏洞

简述

对用户输入参数验证不足,使得攻击者能够引入一个FakeFlashloanProvider。Vault合约利用这个Provider发起了一笔闪电贷。随后,可能是为了结算闪电贷,Vault合约向FakeFlashloanProvider批准了代币,导致资产未经授权地从Vault中转出。

详细版本

被利用的合约是:

  • Vault: 受害者合约 0xd614927acfb9744441180c2525faf4cedb70207f 作为“Vault”,提供储备金并促进AAVE和Balancer等其他协议的闪电贷。
  • Arbitrage Bot: 易受攻击的合约 0x8db0efee6a7622cd9f46a2cf1aedc8505341a1a7,在“Vault”合约中充当“套利机器人”的角色,持有借款人身份。

套利机器人”中的函数 0x0582f20f() 是启动套利的主要入口点。 它首先调用“Vault”中的 borrow() 来获取原始本金,然后通过 delegatecall 调用calldata中指定的外部合约来执行套利逻辑,并且没有进行任何验证。

function 0x0582f20f(...) {
  ...
  v67, /* uint256 */ v68 = address(0xd614927acfb9744441180c2525faf4cedb70207f).borrow(address(v39), address(v9[0]), v29).gas(msg.gas);
  ...
  // 0x4da91757 = swap(address,address,address,uint256,uint256,uint256,address)
  MEM[MEM[64] + 32] = uint224(address(MEM[0 + v4[v69]])) | 0x4da9175700000000000000000000000000000000000000000000000000000000;
  v82 = address(v76 >> 96).delegatecall(MEM[(MEM[64]) len 228], MEM[(MEM[64]) len 0]).gas(msg.gas);
  ...
  v189 = v170.refund(0x410085df, address(v9[0]), address(v39), v68, address(v9[0]), v29, v186, 4 + MEM[64] + (varg2.length << 5) - (4 + MEM[64]) + 192).gas(msg.gas);
  ...
}

随后,它调用“Vault”中的 0x512b7351(),向攻击者的 FakeFlashloanProvider 合约发起闪电贷。

函数 0x512b7351() 要求 msg.sender 在允许列表中,但它被先前的 delegatecall 成功绕过,从而规避了检查。 这是一个非常关键的步骤

function 0x512b7351(...) public nonPayable {
    ...
    if (_borrow[msg.sender] >= 1) {
        v0 = !_refund;
    }
    require(v0, Error('BBVault: FORBIDDEN'));
    ...
    v38 = v23.length;
    v39 = v23.data;
    _refund = keccak256(v23);
    ...
    <FakeFalshloanProvider>.flashloan(...);
    ...
}

在闪电贷回调期间,“Vault”中的 executeOperation() 首先将借入的资产转移给“套利机器人”MEVBot 0x8db0ef,然后调用其 0x7fe3ba8b()

function executeOperation(...) {
  ...
  require(_refund == keccak256(v3.data), Error('BBVault: STATUS'));

  Token.transfer(ArbitrageBot, amountBorrowed);
  <ArbitrageBot>.call(0x7fe3ba8b...);

}

“套利机器人”信任此外部调用,将收到的资产转回 FakeFlashloanProvider。 然而,“Vault”未能识别这一点,仍在 executeOperation() 结束时授予 FakeFlashloanProvider 批准以偿还闪电贷。

攻击过程

攻击交易:0x864c8cfb8c54d3439613e6bd0d81a5ea2c5d0ad25c9af11afd190e5ea4dcfc1f

攻击者调用“套利机器人”的 0x0582f20f(),该函数继而对攻击者的合约执行 delegatecall

然后 hack_contract_2 调用 victim 的函数 0x512b7351()0x512b7351() 要求 msg.sender 在允许列表中,但它被先前的 delegatecall 成功绕过,从而规避了检查。

然后 victim 调用攻击者的 FakeFlashloanProvider 合约,将所有闪电贷资产转入 victim 并调用 victim 的 executeOperation()

“套利机器人”的 0x7fe3ba8b() 再次对 攻击者合约 执行 delegatecall,这次将所有资产转回给攻击者。 此时,攻击者闪电贷提供商提供的资产已被偿还。

受害者(“Vault”)批准代币给 FakeFlashloanProvider,可能是为了偿还闪电贷。

攻击者利用此批准,通过 transferFrom 从受害者处提取资金,从而获利。

安全建议

非开源代码不保证安全

认为非开源和混淆的代码能保证安全是一种误解。此次MEV Bot事件表明,保密并不能防范攻击,反而可能给开发者带来虚假的安全感。

严格的输入验证

在处理闪电贷和交换回调等标准接口时,必须仔细验证所有合约交互和calldata。在合约设计和实现中,确保数据的完整性和安全性应是优先考虑的事项。

阅读本系列其他文章:

Sign up for the latest updates