Par : Jiujiu
arrière-plan
Le 5 décembre 2023, la plateforme de développement de base Web3 thirdweb a déclaré que des problèmes de sécurité avaient été détectés dans des contrats intelligents pré-construits et que tous les jetons ERC20, ERC721 et ERC1155 déployés à l'aide de contrats intelligents pré-construits étaient affectés. (Pour les versions spécifiques du code de contrat affectées, veuillez vous référer à : https://blog.thirdweb.com/security-vulnerability/)

Selon les renseignements de l'équipe de sécurité de SlowMist, le 7 décembre 2023, le jeton Time sur le réseau principal ETH a été attaqué en raison de cette vulnérabilité, et l'attaquant a réalisé un profit d'environ 190 000 USD. De nombreux contrats de jetons présentent encore des vulnérabilités. L'équipe de sécurité de SlowMist est intervenue dans les plus brefs délais et a partagé les résultats comme suit :
Prérequis
1. ERC-2771 est la norme pour les méta-transactions. Les utilisateurs peuvent déléguer l'exécution des transactions à un transitaire tiers, communément appelé relais ou transitaire.
Habituellement, l'adresse de l'appelant direct dans le contrat est obtenue à l'aide de msg.sender, mais lorsque ERC-2771 est utilisé, si msg.sender est un transitaire, les données d'appel entrant sont tronquées et les 20 derniers octets sont obtenus comme adresse de l'appelant direct de la transaction.

2. Multicall est une bibliothèque de contrats intelligents qui permet l'exécution par lots de plusieurs appels de fonctions, réduisant ainsi les coûts de transaction. Cette bibliothèque est souvent utilisée pour optimiser les performances et l'expérience utilisateur des DApps, en particulier lorsque plusieurs opérations de lecture sont requises.
À partir du code, nous pouvons voir que la bibliothèque Multicall utilisée par le contrat vulnérable dans le projet thirdweb exécute d'autres fonctions dans le contrat qui référence la bibliothèque en appelant la fonction DelegateCall dans une boucle.

cause première
La cause première de la vulnérabilité est que le contrat de jeton utilise à la fois les bibliothèques ERC-2771 et Multicall. L'attaquant appelle la fonction multicall du contrat de jeton via la fonction execute du contrat Forwarder pour exécuter d'autres fonctions du contrat (comme la gravure de jetons). Cette méthode a passé avec succès le jugement isTrustedForwarder de l'ERC-2771 et a finalement analysé l'appelant de la fonction comme les 20 derniers octets des données d'appel malveillantes. L’attaquant a ainsi réussi à tromper le contrat en lui faisant croire que l’appelant était l’adresse d’un autre utilisateur, ce qui a entraîné la destruction des jetons d’autres utilisateurs.
Analyse des étapes d'attaque
Ici, nous prenons la transaction d'attaque 0xecdd11...f6b6 comme exemple d'analyse :
1. L'attaquant a d'abord utilisé 5 WETH pour échanger contre 345 539 9346 jetons Time dans le pool Uniswap V2.

2. Appelez ensuite la fonction d'exécution du contrat Forwarder et construisez les données malveillantes pour appeler la fonction multicall du contrat de jeton. À ce moment, le contrat de jeton déléguera l'appel pour exécuter la fonction de gravure du contrat de jeton en fonction des données malveillantes transmises par l'attaquant, détruisant ainsi 62 227 259 510 jetons de temps dans l'adresse du pool.

3. Étant donné qu'une grande quantité de jetons Temps dans le pool ont été brûlés à l'étape précédente, le prix des jetons Temps a été instantanément augmenté, de sorte que l'attaquant a finalement pu inverser l'échange des jetons Temps obtenus à la première étape et vider les 94 WETH dans le pool.

Analyse du principe d'attaque
Dans la fonction d'exécution du contrat Forward, après avoir vérifié la signature de req.from, l'interaction d'appel req.to (adresse du jeton) sera utilisée. Les données requises transmises par l'attaquant sont


Étant donné que 0xac9650d8 est la signature de fonction de la fonction multicall, la fonction multicall du contrat de jeton sera appelée et la valeur de données transmise à la fonction multicall est 0x42966c68000000000000000000000000000000000000000000000000000000c9112ec16d958e8da8180000760dc1e043d99394a10605b2fa08f123d60faf84.
Pourquoi n'y a-t-il pas de req.from dans la valeur de données transmise à la fonction multicall ? Cela est dû au fait que la couche sous-jacente EVM tronquera la valeur requise en fonction du décalage lors du traitement de l'appel, et le décalage de la valeur calldata transmise par l'attaquant est défini sur 38, et la longueur de la valeur est de 1, donc la valeur de données qui vient d'être interceptée est 42966c6800000000000000000000000000000000000000000000000000000c9112ec16d958e8da8180000760dc1e043d99394a10605b2fa08f123d60faf84.

Pour plus de détails, veuillez vous référer à la description de l'appel dans l'opcode EVM (https://www.evm.codes/?fork=shanghai).

Étant donné que 0x42966c68 est la signature de fonction de la fonction de gravure, la fonction de gravure du contrat de jeton sera appelée via delegatecall en fonction de la valeur de données construite par l'attaquant.

La fonction _msgSender() est réécrite par la bibliothèque ERC-2771.

Étant donné que l'appel multiple est appelé via delegatecall, l'expéditeur msg.sender transmis par isTrustedForwarder correspond en réalité à l'adresse du contrat Forward, qui émet le jugement. Finalement, la valeur renvoyée par _msgSender() correspond aux 20 derniers octets des données d'appel transmises, c'est-à-dire l'adresse du pool 0x760dc1e043d99394a10605b2fa08f123d60faf84.
en conclusion
La cause principale de cette attaque est que le contrat référence à la fois Multicall et ERC2771Context. L'attaquant peut insérer des données d'appel malveillantes dans la requête de transfert, utiliser la fonction delegatecall de Multicall pour évaluer le transitaire de confiance et manipuler l'analyse de _msgSender() dans l'appel enfant, manipulant ainsi les jetons de n'importe quel utilisateur.
L'équipe de sécurité de SlowMist recommande aux propriétaires de projets de ne pas utiliser simultanément Multicall et ERC2771Context lors de la rédaction de contrats de jetons. Si la demande attendue nécessite une référence simultanée, il est nécessaire de vérifier si la longueur des données d'appel est conforme aux attentes ou d'utiliser la dernière version officielle des contrats Multicall et ERC2771Context d'OpenZeppelin.
référence
Adresse de l'attaquant : 0xfde0d1575ed8e06fbf36256bcdfa1f359281455a
Contrat d'attaque : 0x6980a47bee930a4584b09ee79ebe46484fbdbdd0
Transactions d'attaque associées : https://etherscan.io/tx/0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6
Détails des versions affectées : https://blog.thirdweb.com/security-vulnerability/
Outil d'atténuation : https://mitigate.thirdweb.com/
