BitDAOの3.5億ドルがほぼ盗まれそうになり、ホワイトハットハッカーが壮絶な救出劇を語る

バビット
2021-08-18 11:13:43
コレクション
一場心躍るホワイトハットハッカーの救出作戦。

8月17日、ブロックチェーン投資機関Paradigmの研究パートナーであり、有名なホワイトハットハッカーのsamczsunが、BitDAOがSushiSwapのIDOプラットフォームMISOで行ったオランダ式オークションのスマートコントラクトにセキュリティの脆弱性が存在することを発表し、複数のホワイトハットハッカーが共同でクラウドファンディングプールから10.9万ETH(約3.5億ドル)を救出した経緯を明らかにしました。

原文タイトル:《正正得負》(Two Rights Might Make A Wrong

執筆:samczsun

翻訳:Kyle、バビット

この記事の目次:

  1. 出会い

  2. 発見

  3. 開示

  4. 準備

  5. 救助

  6. 反省

ソフトウェアを構築する際によくある誤解の一つは、システム内の各コンポーネントが個別に安全であると検証されている場合、システム自体も安全であるということです。この考え方はDeFiプロジェクトでより顕著に表れています。DeFiプロジェクトの開発において、コンポーザビリティは開発者の第二の本能です。

残念ながら、二つの安全なコンポーネントを組み合わせることは、ほとんどの場合安全であるかもしれませんが、同時に一つの脆弱性があれば、数百人または数千人の無実のユーザーに深刻な経済的損失をもたらす可能性があることを意味します。

今日は、私がどのようにして109,000ETH(今日の為替レートで約3.5億ドル)の盗難リスクにさらされる重大な脆弱性を発見し、修正を手助けしたかをお話ししたいと思います。

一、出会い

午前9:42

私がTwitterで@ivangbi_と@bantgの間でSushiSwapのMISOプラットフォーム上の新しいトークンセールプロジェクトについての議論に気づいたとき、私はTelegramのLobsterDAOグループチャットを適当にブラウジングしていました。私は通常、公の場で劇的なことをするのを避けるようにしていますが、何が起こっているのかを確認するためにGoogleで素早く検索せずにはいられませんでした。

私が得た結果は特に興味深いものではありませんでしたが、何か面白いものが見つかるかもしれないと思い、さらに検索を続けました。

MISOプラットフォームは、オランダ式オークションとバッチオークションの二つのトークンオークションモデルをサポートしています。そして、今日話しているこのトークンセールはオランダ式オークションで行われています。もちろん、私が最初にしたことはEtherscanでそのプロジェクトのコントラクトアドレスを開くことでした。

午前9:44

私はそのプロジェクトの参加契約を通じて、このオランダ式オークションのコントラクトを素早く確認し、興味深い関数をチェックしました。コントラクトの提出関数(commitEth、commitTokens、commitTokensFrom)はすべて正しく実装されているように見えました。オークション管理関数(setDocument、setListなど)にも適切なアクセス制御がありました。

しかし、下部近くでinitMarket関数にアクセス制御がないことに気づき、非常に懸念しました。さらに、それが呼び出すinitAuction関数にもアクセス制御チェックが含まれていませんでした。

しかし、私はSushiチームがこんな明白なミスを犯すとは思っていなかったので、こんな脆弱性を見つけるとは思ってもみませんでした。案の定、initAccessControls関数はコントラクトがまだ初期化されていないことを検証しました。

しかし、その時、私は別の発見をしました。すべてのファイルをスクロールしていると、SafeTransferとBoringBatchableライブラリに気づきました。私はこの二つに非常に精通しており、BoringBatchableライブラリの潜在的な危険にすぐに驚きました。

ここで説明しますが、BoringBatchableは、任意のコントラクトにバッチ呼び出しを簡単に導入することを目的としたハイブリッドライブラリです。これは、入力で提供された各呼び出しデータに対して、現在のコントラクトで委任呼び出しを実行することによって実現されます。

function batch(bytes[] calldata calls, bool revertOnFail) external payable returns (bool[] memory successes, bytes[] memory results) {
successes = new bool[](calls.length);
results = new bytes[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(calls[i]);
require(success || !revertOnFail, _getRevertMsg(result));
successes[i] = success;
results[i] = result;
}
}

上記の関数を見てみると、正しく実装されているようです。しかし、私の心の片隅で何かが警告を発していました。その時、私は過去に非常に似たものを見たことがあることに気づきました。

二、発見

午前9:47

今日の印刷から1年以上前、私はOpynチームとのZoomビデオ通話で、壊滅的なハッキング攻撃を受けた後にユーザー資金を回復し保護する方法を模索していました。

ハッキング手法自体は単純ですが巧妙でした:それは1回のETH支払いを使用して複数のオプションを行使するもので、Opynコントラクトがループ内でmsg.value変数を使用していました。

トークン支払いを処理するには、各ループの反復ごとに個別のtransferFrom呼び出しが必要ですが、ETH支払いを処理するのはmsg.valueが十分かどうかを確認するだけです。これにより、攻撃者は同じETHを何度も再利用することができました。

今日に戻ると、私は見ているのが二つの全く同じ脆弱性で、ただ形式が異なることに気づきました。委任呼び出しの中で、msg.senderとmsg.valueが永続化されます。これは、私がcommitEthをバッチ呼び出しし、各commitmentで私のmsg.valueを再利用できるはずであり、これによりオークションで無料で入札できることを意味します。

午前9:52

私の直感はこれが実際の取引であることを示していましたが、実際に確認するまでは確信できませんでした。私はすぐにRemixを開き、概念実証を作成しました。

残念なことに、私のメインネットフォーク環境はつい最近完全に壊れてしまいました。私はロンドンハードフォークの際にうっかり壊してしまったに違いありません。これほど多くの資金が危険にさらされているのに、私は十分な時間がありませんでした。私はすぐにコマンドラインで簡素なメインネットフォークを組み立て、私の脆弱性をテストしました。結果は私が考えていた通りでした。

午前10:13

この脆弱性を外部に報告する前に、私は同僚のGeorgios Konstantopoulosに電話をかけ、もう一度確認してもらいました。返事を待っている間、私はコントラクトに戻り、深刻さを確認する方法を探しました。この場合、オークションに無料で参加できることは一つのことですが、他の参加者の入札を盗むことができるのは別のことです。

私は最初のスキャンプロセスでいくつかの返金ロジックに気づきましたが、その時はあまり考えませんでした。今、これはETHをコントラクトから引き出す方法になっていました。私はすぐにコントラクトが私に返金を提供するために満たす必要がある条件を確認しました。

驚いたことに(そして恐怖を感じたことに)、私はオークションのハード上限を超えるETHを送信すると返金されることを発見しました。ハード上限に達してもこれが適用されるため、コントラクトは取引を完全に拒否するのではなく、単にあなたのすべてのETHを返金するだけです。

突然、私が発見したこの脆弱性は巨大なものになりました。私は他の参加者よりも入札を超えることができる脆弱性を扱っているのではなく、3.5億ドルの脆弱性を見ているのです。

三、開示

午前10:38

Georgiosとこの脆弱性を確認した後、私は彼にDan Robinsonと一緒にSushiのCTOであるJoseph Delongに連絡を取るように頼みました。数分後、Josephが応答し、その後私はGeorgios、Joseph、Mudit、Keno、Omakaseと一緒にZoom通話を行いました。私は脆弱性について他の参加者に迅速に報告し、彼らは応答を調整し始めました。通話は数分しか続きませんでした。

四、準備

午前11:26

救助作業室で、Mudit、Keno、Georgiosと私は簡単な救助コントラクトを書くのに忙しくしていました。私たちは、最もクリーンな方法はフラッシュローンを開始し、ハード上限に直接購入してオークションを終了し、その後オークション自体の収益を使用してフラッシュローンを返済することだと決定しました。この方法は前もって資金を準備する必要がなく、非常に効果的でした。

午後1:36

救助コントラクトの作業を終えたとき、私たちはバッチオークションの次のステップについて議論しました。Muditは、オークションが進行中でもポイントリストを設定でき、各ETHコミットメントの間にそれを呼び出すことができることを指摘しました。私たちはすぐにこれが私たちが探している一時停止機能であることに気づきました。

私たちはこの方法を使用するためのさまざまな方法を考えました。即時復元は明白な解決策ですが、私たちはより良い解決策を求めていました。

私は、各ソースが各ブロックに対して1つのcommitmentしか行えないようにチェックを追加することを考えましたが、その関数がビューとしてマークされていることに気づきました。これは、Solidityコンパイラが静的呼び出しオペコードを使用することを意味します。私たちの方法では、状態の変更は許可されません。

考えた結果、私たちはポイントリストを使用してオークションコントラクトが行ったcommitmentに対して十分なETHを持っているかどうかを検証できることに気づきました。言い換えれば、誰かがこの脆弱性を利用しようとした場合、commitmentはETHよりも多くなるでしょう。私たちはこれを簡単に検出し、取引を復元することができます。MuditとKenoは検証のためのテストを作成し始めました。

五、救助

午後2:01

通信突入チームと救助突入チームが進捗を同期するために合流しました。彼らはオークションを実行しているチーム(BitDAO)と連絡を取りましたが、そのチームはオークションを手動で完了させたいと考えていました。私たちはリスクについて議論し、誰かの自動化されたボットがこの取引に気づくか、何らかの行動を取る可能性は非常に低いと考えました。

午後2:44

オークションを実行しているチームがオークションを完了し、直接的な脅威を排除しました。私たちは成功を祝福し、それぞれ解散しました。このバッチオークションは、その日の後半に静かに終了する予定です。知らない人は、どれほど深刻な災害を回避したのか全く知らないでしょう。

六、反省

午後4:03

過去数時間は非常にぼんやりとした感覚で、時間が止まっているように感じました。私はこのプロジェクトに出会ってから脆弱性を発見するまでにわずか30分以上、20分で開示し、さらに30分で作戦室を経て、3時間以内に脆弱性を修正しました。総じて、わずか5時間で3.5億ドルを悪人の手に渡らないように守りました。

金銭的な損失がなかったとしても、関与したすべての人が最初からこのプロセスを経験しなかった方が良かったと信じています。この事件に関して、私には二つの主なポイントがあります。

まず、複雑なシステムでmsg.valueを使用することは非常に困難です。それはグローバル変数であり、変更できず、委任呼び出しの中で不変です。もしmsg.valueを使用して支払いが受け取られたかどうかを確認する場合、そのロジックをループ内に置いてはいけません。

コードベースの複雑さが増すにつれて、どこで何が起こっているかを忘れ、誤って間違った場所で何かをループさせてしまうことが容易です。ETHのカプセル化と解放は面倒であり、追加のステップを導入しますが、こうした事態を避けたいのであれば、WETHと他のERC20トークン間の統一インターフェースを試してみる価値があるかもしれません。

次に、二つの安全なコンポーネントを組み合わせることで、不安全なものが生まれる可能性があります。私は以前、コンポーザビリティとDeFiプロトコルの文脈でこれを述べたことがありますが、この事件は、安全なコントラクトレベルのコンポーネントであっても、不安全なコントラクトレベルの動作を引き起こす方法で混合される可能性があることを示しています。「チェック-効果-インタラクション」のような包括的なアドバイスはありませんので、新しいコンポーネントがもたらす追加の相互作用を理解する必要があります。

私はSushiの貢献者、Joseph、Mudit、Keno、Omakaseがこの問題に迅速に対応してくれたこと、そして私の同僚Georgios、Dan、Jimがこのプロセス全体で提供してくれた支援、この記事のレビューを含めて感謝します。

ChainCatcherは、広大な読者の皆様に対し、ブロックチェーンを理性的に見るよう呼びかけ、リスク意識を向上させ、各種仮想トークンの発行や投機に注意することを提唱します。当サイト内の全てのコンテンツは市場情報や関係者の見解であり、何らかの投資助言として扱われるものではありません。万が一不適切な内容が含まれていた場合は「通報」することができます。私たちは迅速に対処いたします。
チェーンキャッチャー イノベーターとともにWeb3の世界を構築する