菠菜菠菜|bocaibocai.eth

菠菜菠菜|bocaibocai.eth

Web3 Researcher|RMIT Master of Blockchain|Web3caff Reseacher|Buidler DAO Core Contributor |ENFP|DYOR|Mirror: http://mirror.xyz/bocaibocai.eth
twitter

ハッカー体験カード:NFTプロジェクトへの再入攻撃の方法は?

あなたはハッカーの世界を理解したいですか?ハッカーの感覚を体験してみたいですか?再入攻撃契約を使用して NFT プロジェクトを攻撃する方法は?ボタナは、ハッカーの視点から、スマートコントラクトの脆弱性を見つけて攻撃する方法を体験させてくれます。

この記事はスマートコントラクトのコード技術に関するものであるため、ボタナは技術を理解していない仲間のために、各行のコードのロジックを明確に説明し、仲間がスマートコントラクトを理解し、その中の論理的な脆弱性を見つけられるようにします。

注意してください:この記事のケースは教育目的のみで使用され、スマートコントラクトを攻撃することは倫理に反する行為です。これは、ユーザーが意図せずに暗号資産を失う可能性があり、ブロックチェーンネットワーク全体の安全性に脅威を与える可能性があります。

この記事のケースは、スタンフォード大学の 2021 年の暗号技術コースの期末試験問題に由来しています。問題のリンク:https://cs251.stanford.edu/hw/final2021.pdf

もしあなたがスマートコントラクト(Smart Contract)や関数(Function)について理解していないなら、ボタナがまず説明します:スマートコントラクトは、ブロックチェーン上で自動化されたプログラムであり、プログラム可能です。私たちはスマートコントラクトに特定のパラメータを入力し、作成者が書いたコードのロジックに基づいて特定の操作を自動的に実行します。私たちがよく知っているさまざまな NFT プロジェクトやトークンは、すべてスマートコントラクトの一部です。

関数は、スマートコントラクト内の特定の機能です。私たちがスマートコントラクト内の関数を呼び出し、パラメータを渡すと、その関数のコードロジックがトリガーされます。たとえば、ボタナがチェーン上でジャイアントに 100USDT を送った場合、実際には USDT スマートコントラクトの transfer(転送)関数を呼び出しています。図の中で、私は関数に送信先のアドレスや数量などのパラメータを渡しました。スマートコントラクトは、私が渡したパラメータに基づいて操作を実行します。

image

では、再入攻撃とは何ですか?#

ブロックチェーンにおける再入攻撃とは、攻撃者がスマートコントラクト内の特定の関数を繰り返し実行し、契約の異常な動作を引き起こすことを指します。再入攻撃はスマートコントラクトにおいて最も一般的な攻撃の一つであり、毎年数回の再入攻撃事件が発生し、さまざまなプロジェクトに数千万ドルの損失をもたらしています。

最も有名な再入攻撃事件は、2016 年に Ethereum 上の The DAO 契約が再入攻撃を受け、ハッカーが契約内の 3,600,000ETH を盗んだ事件です。この事件は、Ethereum がハッカーの攻撃前に帳簿をロールバックする原因となり、Ethereum のハードフォークである Ethereum Classic(ETC)が誕生しました。興味深いことに、現在の Ethereum の帳簿にはこの再入攻撃事件は発生していません。

さて、ハッカーの視点に入り、ハッカーがどのように脆弱性を見つけて再入攻撃を行うのかを理解しましょう。
問題を見てみましょう:以下の Solidity コードスニペットは、16384 個の非同質化トークン(NFT)を含むエアドロップのためのものです。ユーザーは、NFT コントラクトの mintNFT()関数を呼び出すことで、一度に最大 20 個の NFT を受け取ることができます。
(下の図はその関数のソースコードであり、技術を理解している仲間は脆弱性を探してみてください)

image

問題は 3 つあります:

A) すでに 16370 個の NFT が鋳造されていると仮定します。したがって、totalSupply()== 16370。悪意のある契約がどのようにして 16384 個を超える NFT を鋳造させることができるかを説明してください。攻撃者が引き起こすことができる NFT の最大数はいくつですか?
ヒント:呼び出しアドレスの onERC721Received()が悪意のある場合、何が起こりますか?鋳造ループを注意深く確認し、再入脆弱性を考慮してください。

A の質問では、契約内の論理的な脆弱性を見つける必要があります。B の質問では、具体的な攻撃の契約コードを実装する必要があります。

B)悪意のある Solidity 契約コードを作成し、(a)の攻撃を実現してください。totalSupply()の現在の値が 16370 であると仮定します。

C の質問では、再入攻撃の脆弱性を修正します。

C)攻撃を防ぐために、前のページのコードにどの行の Solidity コードを追加または変更しますか?単一の取引で 20 個を超える NFT を鋳造しないようにしてください。

ボタナがまとめます:

この問題は、総供給量が 16384 の NFT 契約の鋳造(mint)関数についてです。1 つのアドレスが一度に最大 20 個の NFT を鋳造できると仮定し、現在 16370 個の NFT が鋳造されているとします。どのようにすれば、鋳造される NFT の数が規定の総量上限を超えることができるでしょうか?最大でどれだけ超えることができるでしょうか?攻撃コードをどのように実装しますか?脆弱性をどのように修正しますか?

次に、問題を解決し始めましょう。技術を理解している仲間は自分で試してみてください。技術を理解していない仲間のために、ボタナは各行のコードを中国語で説明し、次にロジックを整理しますので、心配しないでください。

image

まず、MintNFT 関数を呼び出すには、入力するパラメータが符号なし整数(数字として理解してください)であり、いくつかの前提条件(require)があることがわかります:

1. 呼び出すとき、総供給量(total supply)は 16384 未満でなければならない

2. 鋳造する数量は 0 より大きくなければならない

3. 一度に鋳造する数量は 20 個を超えてはならない

4. 既に鋳造された数量 + 今回の鋳造数量は 16384 を超えてはならない

5. 価格は数量に一致しなければならない

前提条件を満たす限り、関数を呼び出すと for ループがトリガーされます。for ループが何であるかは気にしないでください。とにかくトリガーされると、現在の NFT の数量をチェックし、入力したパラメータ(数字)に基づいて SafeMint 関数をループで呼び出します。たとえば、14 を入力すると、SafeMint 関数が 14 回繰り返し呼び出され、14 個の NFT を取得します。

SafeMint 関数が呼び出されると、契約は鋳造される NFT がすでに鋳造されているかどうかをチェックします。問題がなければ、あなたのウォレットアドレスに NFT が送られ、現在の NFT 発行量が + 1 されます。この契約を正常に鋳造する場合、私たちは最大で 16384-16370=14 回 MintNFT 関数を呼び出すことができます。なぜなら、毎回呼び出すたびに現在の発行量が + 1 され、この数は上限 16384 を超えることはできないからです。

では、どのように操作すれば、鋳造される数量が規定の総量 16384 を超えることができるでしょうか?#

私たちは、呼び出しアドレスが契約アカウントである場合、ERC721 標準(NFT)のトークンを受け取ることができるかどうかを最初に検査する必要があることに注意できます。受け取れない場合は拒否され、同時に NFT 契約の onERC721Received 関数がトリガーされます。

この IERC721Receiver と onERC721Received は何でしょうか?
簡単に言えば、IERC721Receiver はインターフェースであり、契約はこのインターフェースを実装しなければ ERC721 標準(NFT)のトークンを受け取ることができません。これが、最初にこの契約アドレスが ERC721 を受け取ることができるかどうかを検査する理由です。相手の契約がこのインターフェースを実装していない場合、NFT を受け取ることはできません。

IERC721Receiver インターフェースを実装するには、契約内に onERC721Received コールバック関数を追加する必要があります。
ERC721 標準では、ある契約が別の契約に NFT を送信する際に、相手の onERC721Received 関数が呼び出され、送信者のアドレス、NFT の元の所有者のアドレス、NFT の番号、追加データなどのパラメータが渡されます。同時に、この関数は成功裏に受け取ったことを示す値を返します。

image

コールバック関数とは何ですか?#

コールバック関数は、外部データを受信したときに処理するために通常使用されます。たとえば、他の契約からの送金を受け取ったり、他の契約から NFT を受け取ったときにトリガーされる処理ロジックです。簡単に言えば、送金を受け取った後に自動的にロジックを実行する関数です。成功裏に受け取ったことを知らせる値を返すだけでなく、カスタムのコードロジックを記述することもできます。

このコールバック関数は、実際に NFT 契約を攻撃するための重要なポイントです。まず、私たちは自分のウォレット(Metamask など)を使用して MintNFT 関数を呼び出すと、最大で 14 個の NFT しか鋳造できないことを知っています。
しかし、スマートコントラクトを使用して MintNFT 関数を呼び出す場合はどうでしょうか?NFT 契約の脆弱性はどこにあるのでしょうか?攻撃ロジックは何でしょうか?

まず、私たちは、5 つの前提条件(require)を満たす限り、MintNFT 関数を呼び出すことができることを知っておく必要があります。NFT 契約内の論理的な脆弱性を見つけるためには、前提条件からアプローチする必要があります。
再入攻撃を実現するためには、前提条件を満たした状態で MintNFT 関数を繰り返し呼び出し、鋳造される NFT の数量が規定の総量を超えるようにする必要があります。

攻撃のロジックは:

攻撃契約のコールバック関数 onERC721Received に攻撃コードを追加します。攻撃契約が NFT 契約から NFT を受け取ると、自動的にコールバック関数の攻撃ロジックがトリガーされ、再び NFT 契約の mintNFT 関数を呼び出すことで再入攻撃の効果を得ることができます。
具体的なロジックをボタナがゆっくり説明します:

まず、攻撃契約は 14(16384-16370=14)を入力して MintNFT 関数を呼び出します。15 を入力すると、前提条件(4. 既に鋳造された数量 + 今回の鋳造数量は 16384 を超えてはならない)を満たさないため、呼び出しは失敗します。前提条件を満たした後、MintNFT 関数は for ループをトリガーし、14 回 SafeMint 関数を繰り返し呼び出します。各ループ呼び出しは攻撃契約のコールバック関数をトリガーします。

NFT が 1 つ鋳造されて攻撃契約に転送されるたびに、コールバック関数の攻撃ロジックがトリガーされます。このコールバック関数の攻撃ロジックは、NFT を受け取るたびに自動的に NFT 契約の mintNFT 関数を呼び出すことです。少し複雑に聞こえるかもしれませんが、整理します:

1. 攻撃契約は 14 という数字をパラメータとして NFT 契約の mintNFT 関数を呼び出します。

2. 14 というパラメータは前提条件を満たしているため、呼び出しに成功し、mintNFT 関数は for ループを実行し、14 回 SafeMint 関数を呼び出して NFT を鋳造します。このステップで攻撃契約は最終的に 14 個の NFT を取得します。

3. 攻撃契約はスマートコントラクトであるため、NFT 契約が鋳造時に攻撃契約の onERC721Received 関数を呼び出して、ターゲット契約が IERC721Receiver インターフェースを実装しているかどうかを確認します。

4. NFT 契約は 14 回 SafeMint 関数を実行するため、攻撃契約のコールバック関数が 14 回呼び出され、攻撃ロジックがトリガーされます。

5. 具体的な攻撃ロジックは、最初の NFT を受け取った後、コールバック関数がトリガーされ、再度 mintNFT 契約を呼び出します。入力パラメータは 13 です。なぜなら、すでに 1 つの NFT を受け取っているため、総量上限まであと 13 個の NFT が必要だからです。したがって、パラメータ 13 は前提条件を満たします。

6. 2 つ目の NFT を受け取った後、コールバック関数は攻撃ロジックをトリガーし、mintNFT 関数を呼び出します。入力パラメータは 12 です。12+2=14 となり、その後、受け取るたびにこのように続きます。14 を超えない限り、前提条件の検査を通過できます。

7. したがって、A の質問の答えは:前提条件に論理的な脆弱性があり、悪意のある攻撃ロジックを持つコールバック関数を利用することで、総量 16384 を超える NFT を鋳造することができます。

8. 元々鋳造された 14 個の NFT に加えて、攻撃者が最大で鋳造できる NFT の数は:13+12+11+10+9+8+7+6+5+4+3+2+1=91 個の NFT です。

さて、技術を理解していない仲間は混乱するかもしれません。すでに 14 個の NFT が鋳造されているのに、なぜさらに鋳造できるのでしょうか?前提条件の脆弱性はどこにあるのでしょうか?#

ボタナが続けて説明します。

まず、皆さんは Ethereum のブロック生成メカニズムを理解する必要があります。簡単に言えば、スマートコントラクトを呼び出すときに渡されるすべてのパラメータと契約の状態は、マイナーによって処理されるためにトランザクションとしてパッケージ化されます。ブロックが生成される前に、これらのトランザクションは本質的に「事実」にはなりません。つまり、ブロックが生成される前に最初に呼び出された 14 個の NFT は、実際にはまだ鋳造されていないのです。

実際に鋳造されていないということは、契約を呼び出すときに、このトランザクションを含むブロックが生成される前に、現在の発行量は常に 16370 のままであるということです。前提条件の脆弱性を再確認しましょう。私たちはこの 2 つに注目する必要があります:
1. 呼び出すとき、総供給量(total supply)は 16384 未満でなければならない
4. 既に鋳造された数量 + 今回の鋳造数量は 16384 を超えてはならない

ブロック生成メカニズムと前提条件を組み合わせると、問題がどこにあるのかがわかります。ブロックが生成される前に、現在の発行量は常に 16370 のままであるため、最初の前提条件は何度呼び出しても通過します。次に、4 番目の条件を見てみましょう。すでに発行された数量 + 鋳造数量が 16384 を超えない限り、通過できます。

つまり、鋳造される数量が 14 を超えない限り、4 番目の前提条件を通過できます。このロジックが明確になります:
1. ブロック生成前は数字が変動しない(契約の状態)
2. 鋳造される数量が 14 を超えない限り、最初の条件と 4 番目の条件を完璧に回避して再入攻撃を行うことができます。
3. 攻撃契約が NFT を 1 つ受け取るたびに、再び mintNFT を呼び出して、総数が 14 を超えない NFT を鋳造します。

ブロック生成後、NFT 契約の最終状態は、mintNFT 関数が実際には 14 回呼び出されたことになります。それぞれが 14+13+12+11+10+9+8+7+6+5+4+3+2+1=105 個の NFT を鋳造します。B の質問では、この攻撃の契約を実装する必要があります。では、攻撃契約を設計し始めましょう。

1. まず、攻撃契約で IERC721Receiver インターフェースを実装する必要があります。これにより、ERC721 標準の NFT を受け取ることができます。

2. NFT 契約のアドレスを hashmasks(名前)として定義します。

3. 次に、攻撃関数を作成し、攻撃のロジックを記述します。

4. num を攻撃契約が保持している NFT の数量とします。

5. num が 14 未満である限り、NFT 契約の mintNFT 関数を呼び出し、渡すパラメータは 14-num で、減少し続けます。

6. 次に、onERC721Received コールバック関数を記述します。まず、公式の形式に従って受信するパラメータの形式を設定し、次に自分の攻撃ロジックを追加します:NFT を受け取ると、自動的に attack 攻撃関数がトリガーされ、NFT 契約の mintNFT 関数を呼び出します。

image

具体的な攻撃ロジックがわかったところで、C の質問を見てみましょう。

C)前のページのコードにどの行の Solidity コードを追加または変更しますか?攻撃を防ぐために。

_totalSupply++; この行を_safeMintメソッドで NFT の呼び出しを検証した後に置くことができます:

image

こうすることで、契約が再入攻撃を受けた場合、_totalSupplyはまだ増加していないため、2 回目にmintNFT関数に入るとmintIndexの値は最初の mint の値になります。これにより、'ERC721: token already minted'というエラーが発生し、契約の安全性が効果的に保証され、再入攻撃は失敗します。

B の質問と C の質問の答えは、https://github.com/qiwihui/blog/issues/157に由来しています。

最後に、すべての暗号業界のセキュリティ分野の作業者とホワイトハットに敬意を表します。暗号の世界は暗い森であり、同時にハッカーの楽園でもあります。毎日多くのセキュリティ事故が頻繁に発生しています。
この挑戦と機会に満ちた業界で、安全のために貢献しているすべての探求者に感謝し、ボタナの記事が画面の前の仲間たちの認識を高める手助けになることを願っています。

私の記事が気に入ったら、私の WeChat 公式アカウントをフォローしてください。
間違いがあれば指摘してください~
記事のリンク:

https://mp.weixin.qq.com/s?__biz=Mzg4NDc1NDkwNw==&mid=2247483815&idx=1&sn=811eff65b2cc50e5b5028641353339e0&chksm=cfb21113f8c598051bd52629031e42de3cf6ae58383a228b4014a60efa0756d71d04ebe897be&token=491716498&lang=zh_CN#rd

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。