投稿者: 九九

背景

2023 年 12 月 5 日、Web3 基本開発プラットフォーム thirdweb は、事前構築されたスマート コントラクトにセキュリティ上の問題が見つかり、事前構築されたスマート コントラクトを使用してデプロイされたすべての ERC20、ERC721、および ERC1155 トークンが影響を受けると発表しました。 (影響を受ける具体的な契約コードのバージョンについては、https://blog.thirdweb.com/security-vulnerability/ を参照してください。)

SlowMist セキュリティ チームの情報によると、2023 年 12 月 7 日、ETH メインネット上の Time トークンがまさにこの脆弱性を理由に攻撃され、攻撃者は約 190,000 米ドルの利益を得ました。脆弱性を抱えたトークンコントラクトが依然として多く攻撃されており、SlowMist セキュリティチームは直ちに分析に介入し、次のように結果を共有しました。

前提知識

1. ERC-2771 はメタトランザクションの標準です。ユーザーは、トランザクションの実行をサードパーティのフォワーダー (リレーまたはフォワーダーと呼ばれることが多い) に委任できます。

通常、コントラクト内の直接呼び出し元のアドレスは msg.sender を使用して取得されますが、ERC-2771 を使用する場合、msg.sender がフォワーダーの役割である場合、着信通話データは切り捨てられ、最後の 20 ワードが取得されます。 . セクションはトランザクションの直接呼び出し元アドレスとして使用されます。

2. Multicall は、複数の関数呼び出しをバッチで実行できるスマート コントラクト ライブラリであり、それによってトランザクション コストを削減します。このライブラリは、特に複数の読み取り操作が必要な場合に、DApps のパフォーマンスとユーザー エクスペリエンスを最適化するためによく使用されます。

コードからわかるように、 thirdweb プロジェクトの脆弱なコントラクトによって使用される Multicall ライブラリは、DelegateCall 関数を周期的に呼び出すことによって、ライブラリを参照するコントラクト内の他の関数を実行します。

根本的な原因

この脆弱性の根本原因は、トークン コントラクトが ERC-2771 ライブラリとマルチコール ライブラリの両方を使用していることです。攻撃者は、フォワーダー コントラクトの実行関数を通じてトークン コントラクトのマルチコール関数を呼び出し、コントラクト内の他の関数 (トークンの書き込みなど) を実行します。このメソッドは ERC-2771 の isTrustedForwarder 判定を正常に通過し、最終的に関数の呼び出し元を悪意のある呼び出しデータの最後の 20 バイトに解決します。したがって、攻撃者は、呼び出し元が別のユーザーのアドレスであると思わせるようにコントラクトを騙すことに成功し、その結果、他のユーザーのトークンが焼き付けられることになりました。

攻撃手順の分析

ここでは、分析の例として攻撃トランザクション 0xecdd11...f6b6 を取り上げます。

1. 攻撃者はまず 5 WETH を使用して、Uniswap V2 プール内の 345,539,9346 個の Time トークンを交換しました。

2. 次に、フォワーダー コントラクトの実行関数を呼び出し、悪意のあるデータを構築して、トークン コントラクトのマルチコール関数を呼び出します。このとき、トークン コントラクトは、攻撃者が delegateCall に渡した悪意のあるデータを使用して、書き込み関数を実行します。トークンコントラクトとプールアドレスの書き込み 62,227,259,510 タイムトークン。

3. 前のステップでプール内の大量のタイム トークンが焼き付けられ、タイム トークンの価格が瞬時に上昇したため、攻撃者は最終的に最初のステップで取得したタイム トークンをリバース スワップしてプールを空にすることができます。

攻撃原理の分析

Forward コントラクトの実行関数では、req.from の署名を検証した後、call を使用して req.to (トークン アドレス) と対話します。攻撃者によって渡された req.data は次のとおりです。

0xac9650d8 はマルチコール関数の関数シグネチャであるため、トークン コントラクトのマルチコール関数が呼び出され、マルチコール関数によって渡されるデータ値は 0x42966c680000000000000000000000000000000000000000c9112ec16d958e8da8180000760dc になります。 1 e043d99394a10605b2fa08f123d60faf84。

マルチコール関数に渡されるデータ値に req.from がないのはなぜですか?これは、EVM の最下層が呼び出しの処理時にオフセットに基づいて必要な値を切り捨てるためです。攻撃者によって渡された calldata 値に設定されたオフセットは 38 で、値の長さは 1 であるため、データ値は単にインターセプトされます。 42966c6800000000000000000000000000000000000000000000c9112ec16d958e8da8180000760dc1e043d99394a10605b2fa08f123d60faf84。

詳細については、EVM オペコードの呼び出しの説明 (https://www.evm.codes/?fork=shanghai) を参照してください。

0x42966c68 は書き込み関数の関数シグネチャであるため、トークン コントラクトの書き込み関数は、攻撃者が構築したデータ値に基づいて delegatecall を通じて呼び出されます。

_msgSender() 関数は、ERC-2771 ライブラリによってオーバーライドされます。

マルチコールは delegatecall を通じて呼び出されるため、isTrustedForwarder によって渡される msg.sender は実際には Forward コントラクトのアドレスであるため、判定が通過し、最終的に _msgSender() によって返される値は、渡された calldata の最後の 20 バイトになります。つまり、プールのアドレスは 0x760dc1e043d99394a10605b2fa08f123d60faf84 です。

結論は

この攻撃の根本原因は、コントラクトが Multicall と ERC2771Context の両方を参照していることです。攻撃者は、転送リクエストに悪意のある通話データを挿入し、Multicall の delegatecall 関数を使用して信頼できるフォワーダーの判断を渡し、コントラクト内の _msgSender() を操作することができます。サブコール: 分析により、任意のユーザーのトークンを操作できるようになります。

SlowMist セキュリティ チームは、プロジェクト パーティがトークン コントラクトを作成するときに Multicall と ERC2771Context を同時に使用しないことを推奨しています。予想される需要で同時参照が必要な場合は、呼び出しデータの長さが期待を満たしているかどうかを確認するか、openzeppelin の Multicall と ERC2771Context の最新の公式バージョンを使用する必要があります。 ERC2771コンテキストコントラクト。

参考

攻撃者のアドレス: 0xfde0d1575ed8e06fbf36256bcdfa1f359281455a

攻撃コントラクト: 0x6980a47bee930a4584b09ee79ebe46484fbdbdd0

関連する攻撃トランザクション: https://etherscan.io/tx/0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6

影響を受けるバージョンの詳細: https://blog.thirdweb.com/security-vulnerability/

緩和ツール: https://mitigate.thirdweb.com/