#9:MEVボット 0xd61492:捕食者から獲物へ、巧妙なエクスプロイト

2023年8月3日、Arbitrum上のMEVボットが攻撃され、80万ドルの損失が発生しました。この攻撃の根本原因は**ユーザー入力検証の不備**でした。

#9:MEVボット 0xd61492:捕食者から獲物へ、巧妙なエクスプロイト

2023年8月3日、Arbitrum上のMEVボットが攻撃を受け、80万ドルの損失が発生しました。この攻撃の根本原因は「ユーザー入力検証の不備」でした。

MEVボットとそのコントラクト間の複雑な相互作用を検証せずに考えると、オープンソースでないことがセキュリティを保証しない、特にDeFiプロトコルにおいては、ということが明らかになります。

背景

MEVボット

MEVボット(Maximum Extractable Value Bot)は、ブロックチェーン上で収益性の高い機会を特定し、実行するために設計されています。 これは、保留中のトランザクション(つまり、メモリプールにあるもの)やオンチェーンの状態を分析して、裁定取引を通じて利益を生み出すことによって機能します。

この攻撃で標的とされたMEVボットは、通常のフロントランニングやサンドイッチ攻撃のMEVボットとは異なり、三角裁定取引や負債清算などの戦略の実行に焦点を当てていました。これらのボット自体は、AMMの価格を安定させ、貸付プロトコルが円滑に運用されるように清算を支援し、DeFiエコシステムの健全な機能に不可欠な部分を構成しています。

フラッシュローン

フラッシュローンは、DeFiエコシステムにおけるユニークなイノベーションであり、担保なしの貸付の一形態です。ローンが同じトランザクション内で返済される限り、担保なしで最大10億ドルをフラッシュローンで借りることができます。ローンがそのトランザクション内で返済されない場合、トランザクションがなかったことのように取り消されます。

このメカニズムは、裁定取引やその他のDeFi戦略を活用して、一時的な市場の非効率性を悪用するためによく使用されます。

脆弱性

短縮版

ユーザー入力パラメータの検証が不十分だったため、攻撃者はFakeFlashloanProviderを導入することができました。Vaultコントラクトはこのプロバイダーを利用してフラッシュローンを開始しました。その後、おそらくフラッシュローンの決済のために、VaultコントラクトはFakeFlashloanProviderにトークンを承認し、Vaultからの不正な資産の送金につながりました。

詳細版

悪用されたコントラクトは以下の通りです。

  • Vault: 犠牲者コントラクト 0xd614927acfb9744441180c2525faf4cedb70207f は「Vault」として機能し、リザーブを提供し、AAVEやBalancerなどの他のプロトコルからのフラッシュローンを容易にします。
  • Arbitrage Bot: 脆弱なコントラクト 0x8db0efee6a7622cd9f46a2cf1aedc8505341a1a7 は、「Vault」コントラクトで借入人の役割を果たす「Arbitrage Bot」として機能します。

「Arbitrage Bot」の 0x0582f20f() 関数は、裁定取引を開始するための主要なエントリポイントです。 まず「Vault」の borrow() を呼び出して元の元本を取得し、次に検証なしでcalldataで指定された外部コントラクトへの delegatecall を通じて裁定取引ロジックを実行します。

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() は、まず借入資産を「Arbitrage Bot」MEVBot 0x8db0ef に転送し、次にその 0x7fe3ba8b() を呼び出します。

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

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

}

「Arbitrage Bot」はこの外部呼び出しを信頼し、受け取った資産を FakeFlashloanProvider に戻します。 しかし、「Vault」はこれを認識せず、「Vault」は executeOperation() の最後にフラッシュローンの返済のために FakeFlashloanProvider に承認を付与したままです。

攻撃プロセス

攻撃トランザクション: 0x864c8cfb8c54d3439613e6bd0d81a5ea2c5d0ad25c9af11afd190e5ea4dcfc1f

攻撃者は「Arbitrage Bot」の 0x0582f20f() を呼び出し、それが攻撃者のコントラクトに delegatecall を実行します。

次に hack_contract_2 (https://arbiscan.io/address/0x3c236c919b4174b3123c1da298a30ff7e70d03d2) が victim0x512b7351() 関数を呼び出します。 0x512b7351()msg.sender が許可リストに載っていることを要求しますが、前の delegatecall によって正常にバイパスされ、チェックが回避されました。

次に victim が攻撃者の FakeFlashloanProvider コントラクトを呼び出し、フラッシュローンされたすべての資産を victim に転送し、victimexecuteOperation() を呼び出します。

「Arbitrage Bot」の 0x7fe3ba8b() は、今回はすべての資産を攻撃者に送金することで、再び 攻撃者のコントラクトdelegatecall を実行します。 この時点で、攻撃者のFlashloan Providerが貸し付けた資産は返済されています。

被害者(「Vault」)は、おそらくフラッシュローンの返済を意図して、FakeFlashloanProvider にトークンを承認します。

攻撃者はこの承認を悪用して、transferFrom を使用して被害者から資金を引き出し、利益を得ました。

セキュリティ推奨事項

非オープンソースコードはセキュリティを保証しない

非オープンソースで難読化されたコードがセキュリティを保証するという考えは誤解です。このMEVボットのインシデントは、秘密主義がエクスプロイトから保護するものではなく、開発者に誤った安心感を与える可能性があることを示しています。

厳格な入力検証

フラッシュローンやスワップコールバックのような標準インターフェースを扱う場合、すべてのコントラクトの相互作用とcalldataを綿密に検証することが重要です。データの整合性とセキュリティを確保することは、コントラクトの設計と実装における優先事項であるべきです。

このシリーズの他の記事を読む:

Sign up for the latest updates