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) が victim の 0x512b7351() 関数を呼び出します。 0x512b7351() は msg.sender が許可リストに載っていることを要求しますが、前の delegatecall によって正常にバイパスされ、チェックが回避されました。

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

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

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

攻撃者はこの承認を悪用して、transferFrom を使用して被害者から資金を引き出し、利益を得ました。
セキュリティ推奨事項
非オープンソースコードはセキュリティを保証しない
非オープンソースで難読化されたコードがセキュリティを保証するという考えは誤解です。このMEVボットのインシデントは、秘密主義がエクスプロイトから保護するものではなく、開発者に誤った安心感を与える可能性があることを示しています。
厳格な入力検証
フラッシュローンやスワップコールバックのような標準インターフェースを扱う場合、すべてのコントラクトの相互作用とcalldataを綿密に検証することが重要です。データの整合性とセキュリティを確保することは、コントラクトの設計と実装における優先事項であるべきです。
このシリーズの他の記事を読む:
- リードイン: 2023年のトップ10「素晴らしい」セキュリティインシデント
- #1: Flashbots Relayの脆弱性を悪用したMEVボットの収穫
- #2: Euler Financeインシデント: 2023年最大のハッキング
- #3: KyberSwapインシデント: 極めて微妙な計算による丸め誤差の巧妙な悪用
- #4: Curveインシデント: コンパイラエラーが無害なソースコードから不正なバイトコードを生成
- #5: Platypus Finance: 幸運にも3回の攻撃を生き延びる
- #6: Hundred Financeインシデント: 脆弱なフォークされたプロトコルにおける精度関連エクスプロイトの波を触媒
- #7: ParaSpaceインシデント: 業界で最も重大な攻撃を阻止するための時間との戦い
- #8: SushiSwapインシデント: 不器用な救出の試みが一連のコピーキャット攻撃につながる
- #10: ThirdWebインシデント: 信頼されたモジュール間の非互換性が脆弱性を露呈



