DAO攻撃者の足跡を追う

DAO攻撃者の足跡を追う

この投稿は、DAO エクスプロイトの原理とタイムラインを説明した前回のブログ投稿の続編です: http://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/ (http://www.8btc.com/thedao-exploit-analysis)

二次侵略

上記では、現在メディアや研究者の注目も集めているDAOのwithdrawRewardFor脆弱性の再帰送信に主に焦点を当てました。上記では、攻撃者が 30 倍に増幅し、無制限に繰り返すことができる攻撃について説明しました。

当初、実装の詳細は重要ではないと考えていましたが、Joey Krug と Martin Köppelmann は、これらの詳細がいかに重要であるかを示すために懸命に取り組んでくれました。マーティン氏が指摘したように、確かに 2 つの別個のエクスプロイトが、3 つ目のより強力な脆弱性につながります。

  1. splitDAO では、withdrawRewardFor 関数からの再帰攻撃により、アクセスできるはずの DAO トークンの 30 倍を引き出すことができますが、実行できるのは 1 回だけです。

  2. エントリーすることは可能ですが、これは非再帰攻撃であり、splitDAO では withdrawRewardFor 転送を通じて、分割ごとにトークンを 2 倍にすることができます。

  3. (1)と(2)の組み合わせで、権利のあるトークンの30倍を譲渡することができ、何度でもエントリーすることができます。

攻撃者は 3 番目の方法を実装しました。これについては前に説明しましたが、2 番目の方法を見てみましょう。 1 番目と 3 番目の脆弱性が修正された契約を作成します。ループエントリの脆弱性のない完璧なコントラクトである withdrawRewardFor を見てみましょう。前回の投稿を思い出してください。withdrawRewardFor の脆弱性により、DAO 1.1 の splitDAO が再入可能になりましたが、この脆弱性は修正されたかもしれませんが、この関数の最初の行にはまだ問題が残っています。

関数 withdrawRewardFor(address _account) noEther 内部は (bool _success) を返します {
if ((balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply < paidOut[_account])
投げる;

uint 報酬 =
(balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply – paidOut[_account];

報酬 = rewardAccount.balance < 報酬 ? rewardAccount.balance: 報酬;

paidOut[_account] += 報酬;
if (!rewardAccount.payOut(_account, reward))
投げる;

true を返します。
}

報酬アカウントに残高がなく、ユーザーに支払われる金額が 0 の場合でも、payOut の呼び出しは実行され、受信者のコントラクト内の任意のコードが呼び出されることに注意してください。

関数payOut(address _recipient, uint _amount)は(bool)を返します{
if (msg.sender != 所有者 || msg.value > 0 || (payOwnerOnly && _recipient != 所有者))
投げる;
if (_recipient.call.value(_amount)()) { // 脆弱

}

getRewardFor が初めて実行されると、有効な報酬が支払われます。 2 回目の支払いは 0 になり、3 回目は依然として 0、4 回目は依然として同じです... また、ユーザーは splitDAO に戻り、受け取るべき金額を 30 倍に増やすこともできます。

DAO 1.1 で修正された withdrawRewardFor でも、再入脆弱性が残っていることに注意してください。この再入性は、関数を 2 回目 (3 回目、4 回目) に実行すると 0 が支払われるため、報酬アカウントの残高を脅かすことはありません。ただし、再入性攻撃に対しては依然として脆弱です。

DAO 1.2 でこれを修正すると、withdrawRewardFor 関数が再入可能性に対して脆弱にならないように完璧に記述されます。この関数は次のようになります。

関数 withdrawRewardFor(address _account) noEther 内部は (bool _success) を返します {
((balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply <= paidOut[_account]) の場合
false を返します。 // すべてのsplitDAO呼び出しが失敗しないようにする、直交変更

赤く塗られた部分のみが変更され、単に < が ≤ に変更されました。なぜ?この関数を2回目に実行すると、paidOut[_account]の値は左側の式の値と等しくなります。再突入がトリガーされる前にコードが設定されます:

uint 報酬 =
(balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply – paidOut[_account];
paidOut[_account] += 報酬;

したがって、これは、古典的なアンチモデルのベスト プラクティスである再入可能性の脆弱性がない、DAO 1.1 の withdrawFor の外観です。このコードはシンプルで読みやすいです。

このようにすると、前回の記事で説明した splitDAO の無限増幅の弱点は存在せず、攻撃者はこれを行いません。残高がゼロの場合、payOut 呼び出しは実行されないため、この関数を繰り返し実行しても意味がありません。

しかし、Joey Krug 氏が指摘しているように、これによって、withdrawRewardFunction を使用して DAO 1.2 をドレインする同じエクスプロイトの使用を防ぐことはできません。重要なのは、新しいケースで withdrawRewardFor を使用して任意のコードを 1 回呼び出すことができ、1 回で十分であるということです。

関数自体がこの脆弱性を増幅します。報酬を引き出すときに DAO の転送関数を呼び出すと、トークンが子 DAO に転送された後に残高がゼロになり、トークンは新しいアカウントに存在することになります。コードの詳細な説明は前回の記事にあります。主に splitDAO 関数と transfer 関数に関するもので、どちらも同じ残高配列を非アトミックに変更します。

したがって、プロセスに非アトミックに影響を与えるロジックは、任意のコントラクトを実行するための呼び出しによってプロセスが中断された場合に脆弱性を生み出し、攻撃を受ける可能性があります。したがって、「再入不可能な関数を記述する」ことに加えて、外部コントラクトを呼び出さないように注意してください。そうしないと、プログラム フローやステータスを予測できなくなります。

このエクスプロイトには興味深い点がいくつかあります。まず、遅いです。基本的に、トークンを移動するたびにトークンが 2 倍になります。しかし、これは攻撃の成功には影響しません。攻撃は十分に速く、速いからといって誰も止めることはできません。

2 番目に、私たちが修正した DAO 1.1 コードでは、報酬アカウントの残高が必要であったため、再入脆弱性が解消されました。 rewardAccount.accumulatedInput() の戻り値が 0 の場合、ユーザーには支払いが行われず、変更された関数は常に false を返すため、悪意のある可能性のあるコードは実行されません。公開された DAO1.1 コードでは、withdrawRewardFor の脆弱性がまだ存在しており、withdrawRewardFor を実行するために報酬アカウントに残高がなくてもかまいません。

実際には、これらはどれも重要ではなく、意図的であろうとなかろうとボーナス口座に資金が投入される可能性があります。つまり、攻撃者は毎回報酬の一部を転送することができ、DAO 1.2 が修正された後でも withdrawRewardFor 関数を使用して再度侵入することができます。

Solidityのデメリット

私が挙げた最初の脆弱性が存在しなかったら、コミュニティは間違いなく 2 番目の脆弱性を見逃していたでしょう。 1 つ目は反モデルの例であり、この時点ではこれを防止しようとします。2 つ目は、より微妙な反モデルの例です。元の関数の再入性はなく、元のコントラクトの再入性のみです。

要約すると:

  1. Solidity の呼び出し構造を使用して外部コントラクトを呼び出す場合、または変更したコントラクトに外部で呼び出される関数がある場合、コントラクトが外部呼び出しを実行すると、その後の状態を予測することはできません。

  2. これは、DAO エクスプロイトの現状では既知のプログラミング手法ではありません。 Solidity の呼び出しドキュメントを参照できます: https://github.com/ethereum/wiki/wiki/Solidity-Features#generic-call-method この構造を使用すると、多くのセキュリティ上の脆弱性が無視され、開発者が誤ったセキュリティ認識を持つことになります。

  3. 上で示唆したように、コントラクト内から外部コントラクト コードを呼び出すために Solidity の呼び出し構造を使用しないでください。避けられるのであれば、決してそうしないでください。これを行わないと、プログラムの流れに関するすべての保証が失われることに注意してください。

私にとって、上記は、DAO 契約自体の欠陥や脆弱性以上のものを意味します。つまり、技術的には、これらは Ethereum 仮想マシン自体によって設計された機能ですが、Solidity によって契約にセキュリティ上の脆弱性が生じ、コミュニティだけでなく言語の設計者からも無視されました。

私の意見では、この脆弱性の責任の 50% は Solidity 言語の設計者に帰属するはずであり、これにより、このようなケースに対する修正措置が改善される可能性があります。契約コードの書き方が下手なことだけを責めることに同意しません。契約コードがこの言語ドキュメントに完全に従って記述されたとしても、このような脆弱性は残ります。

奇妙な助けの要請

この記事を書いているときに、DAO 報酬アカウントに関する興味深い点に偶然出会いました。攻撃者はなぜ報酬を集めたのか、そして誰がそのお金を報酬アカウントに移したのか? DAO 攻撃中に withdrawRewardFor 関数が実行され続けたのはなぜですか?

DAOの報酬アドレスを見てみましょう。 DAO の会計情報は Slockit から取得されます。アドレスは、0xd2e16a20dd7b1ae54fb0312209784478d069c7b0 (https://github.com/slockit/DAO/wiki/Understanding-the-DAO-accounting) です。トランザクション記録を見てみましょう: https://etherscan.io/txsInternal?a=0xd2e16a20dd7b1ae54fb0312209784478d069c7b0&&zero=true&p=220 攻撃者の悪意のあるコントラクトである 0xf835a0247b0063c04ef22006ebe57c5f11977cc4 と 0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89 に 0.00000002 イーサが 200 ページ転送されていることがわかります。

しかし、これらのコインがどこから来たのか、最後のページのアカウント取引記録を見てください。DAO の作成の最後に、アドレス 0xe76563eb8413ede9b4a1a3c1f3280a95c4b60a33 から 0.001 イーサリアムを送信する単一の金銭取引記録です。

同じアドレスは後にThe DAOに投資し、DigixDAOトークンを保有しています。

私の理論では、彼はおそらく DAO クラウドセールに投資したいと思ってプログラムで購入しようとして失敗した初心者だったと思います。しかし、メインの DAO アドレスが間違っている可能性があるのでしょうか?これらは daohub.org のホームページにありますが、報酬アドレスは DAO wiki の片隅に表示されます。では、なぜこのアドレスに送金するのでしょうか? DAO アーキテクチャを試してみて、どう反応するか見てみようと思っている人ですか?

さらに興味深いのは、このアカウントを検索すると、イーサリアム フォーラムに、イーサを送信するための Javascript API に関するヘルプを求める投稿が見つかります。このアカウントはこのスレッドを投稿してから一度もログインしていません。これは彼らの唯一の投稿です https://forum.ethereum.org/discussion/7109/web3-eth-gettransaction-returned-null。

これはブロックチェーンの歴史を垣間見る興味深い機会となるかもしれないが、その答えは永遠に分からないだろう。あなたがこのアカウントの所有者であれば、当時何を考えていたか知りたいです。

攻撃者は一人ではない

前回の投稿を見ると、私が攻撃者の経路を非常に早く分析できたのは、以前に私自身がそのような攻撃を構築していたからだということがわかります。

1週間前、Emin Gün Sirer からメールを受け取りました。

2016年6月11日土曜日 17:42:37 Emin G Sirer 著 <> 皆さん、こんにちは。
DAO を空にする方法が分かりました。

私はDAOのこの脆弱性を分析するのに数時間を費やしました。週末、私は V1.1 のいくつかの潜在的な脆弱性のトラブルシューティングに数時間を費やし、Sirer から次のような返信がありました。

2016-06-12 13:34:09 Emin G Sirer <> さんが書きました 奇妙なことに、私はこの潜在的な問題に最初に気づいた人の一人でした…
私は依然としてsplitDAOは脆弱であると考えています。この関数が呼び出されるまでbalances[]はクリアされないため、引き出しモードに違反します。したがって、rewardTokens を移動することで DAO を複数回分割できた可能性があると思います。これは、DAO.sol の 640 行目から 666 行目で発生します。私が間違っているでしょうか?
いずれにせよ、これは確かに静的に分析可能な脆弱性です。 Andrew Miller にこの問題の静的分析を行ったかどうか尋ねてみます。

そこで私は数時間かけて splitDAO を分析し、再帰送信の脆弱性を引き起こす可能性はないと判断しました。私の簡単な答えは、それはありそうにないということです。タイミングの問題を挙げましたが、splitDAO 内からでも TokenProxy の作成からも再帰送信をトリガーすることは不可能です。私はいくつかの可能なエクスプロイトを実演し、それから自分の仕事に戻りました。

Sirer 氏のチームにはこの問題を調査している他のメンバーもいましたが、さらに深く調査してみると、この脆弱性を誘発する方法を知っているのは攻撃者だけではないということが興味深いことになってきました。

DAO の失敗は避けられなかった。私はこの一連の記事を、証明しようとするのではなく好奇心から書いているのですが、世間の監視の力について少し希望が持てましたし、私たちはそれにあまり驚いてはいけないと思っています。

短い不在

私のこの一連の投稿を読んでいただきありがとうございます。少しでも参考になれば幸いです。
仕事の都合上、週末は theDAO をフォローしません。私のTwitterで関連ニュースを見ることができます https://twitter.com/phildaian

やるべきことはまだたくさんあります。ハッカーのトークンがどこに行き着いたのか、そしてその理由も含め、攻撃の完全なブロックチェーン像を再構築する必要があります。ハッカーが現在攻撃をテストしているかどうかを確認するには、公開テスト ネットワークを検索する必要があります。ドキュメント化と分析のために、元の Solidity コードを慎重に逆コンパイルして再構築する必要があります。

私たちは経験から学び、ベスト プラクティスを使用する必要があります (いくつかのアイデア: これらのコントラクトを徐々にスケールアップし、Solidity での呼び出し構造の使用を停止します)。コミュニティとして、私たちは前進する道筋を描き、分岐するかどうかを決定する必要があります。

最後に、スマート コントラクト テクノロジーへの関心が現在かつてないほど高まっていることをお伝えしたいと思います。これは、先週よりも強力で、より指導的で、より組織的で、より原則的なコミュニティを紹介する絶好の機会です。

このエクスプロイトの開発とテストに数え切れないほどの時間を費やしてくれたこのハッカーに感謝したいと思います。脱帽です、今回は私たちに勝ちましたね。次回はそんなに幸運ではないでしょうね。


<<:  Bloq CEO ジェフ・ガージック氏との独占インタビュー: 貪欲さが The DAO の悲劇の原因

>>:  スイス政府はブロックチェーン企業に対する規制を緩和し、金融技術改革を推進すると予想される

推薦する

ゴールドマン・サックス:ビットコインは2019年に新たな高値を記録するだろう、これらの下落は安値で買うチャンスとみなすべきだ

世界的金融大手のゴールドマン・サックスは、現在の調整が終われば、ビットコインの価格が2019年に新た...

Ubikeはブロックチェーン技術を目指しており、自転車のシェアリングはより多くの新しいアイデアをもたらすだろう

シェアサイクルがブロックチェーン技術とつながると、どんな新しい形が生まれるのでしょうか?国内シェア自...

暗号通貨市場の暴落が続く中、Celsius は破産を回避できるでしょうか?

本文/金融ニュースセルシウスの仮想通貨ファンは破産を回避する計画を立てている最近、Celsius の...

CoinWallet がデータ侵害を受け、すべてのビットコイン サービスを停止

オンラインビットコインおよびマルチコインウォレットサービスを提供していたCoinWallet社が、サ...

サウジアラムコ、ビットコイン採掘の噂を否定

先週末、ブラジルのビットコインマイナーがビデオインタビューで、石油生産で発生した余剰ガスをビットコイ...

2枚の写真がビットコインが金を段階的に上回る様子を示している

先週の木曜日、ビットコインの価格が金を上回りました!さらに、ビットコインの価格は今年35%上昇し、昨...

Cockli 無料匿名メール登録チュートリアル プライバシーを保護し、安全にメールを送受信する

Cock.li: 10年間続いた匿名メールの伝説インターネットのプライバシーがますます脅かされる中、...

呉氏は毎週の採掘情報:0321-0327

1.ブルームバーグ:国際エネルギー大手エクソンモービルは、ノースダコタ州の油井から燃やされるはずだ...

日本と韓国は停滞、中国は取り組みを強化し、ビットコインの価格は3,000ドルを超えた

今朝、ビットコインの価格は初めて3,000ドルを超え、史上最高値を更新しました(BitcoinWis...

BCHマイニングマシンのシャットダウン価格(2018-11-22)マイニング収入

BCHマイニング情報( 2018-11-22 )リアルタイムビットコインキャッシュ価格: 1641....

拒否から受け入れへ:ロシアにおける暗号通貨マイニングの合法化を推進するものは何でしょうか?

805コイン危機の後、暗号通貨市場は暗雲に包まれ、ビットコインの価格は7月末の7万ドル超から5万ド...

開発者は内部紛争を解決しようとしているのか、それとももう終わったのか?

FX168ニュース:ビットコイン価格は月曜日(1月18日)のアジアセッションで低水準で取引され、前...

NFT の Google 検索の急落は、2018 年の ICO バブルの過ちを繰り返すことになるのでしょうか?

NFTの検索が劇的に減少分散型金融にとっての 2020 年は、これまでのところ NFT にとっての...

ETHマイナーの悪夢はこうなる

ETH 難易度爆弾とは何ですか?ご存知のとおり、ETH の開発は、フロンティア、ホーム、メトロポリ...

Hyperledger と Digital Trade Association が提携し、ブロックチェーンの推進と教育を推進

世界がブロックチェーンによって実現される数多くの金融および記録管理アプリケーションを目にする準備を進...