Le 8 décembre 2023, OpenZeppelin a publié un avertissement important concernant la sécurité. Il s'avère qu'en utilisant le standard ERC-2771 et des fonctions de type Multicall, il existe un risque de substitution d'adresse ! J'ai profondément étudié cette vulnérabilité et je souhaite partager mes découvertes.
L'attaquant a échangé 5 WETH contre environ 3,455,399,346 TIME
Ensuite, j'ai construit des paramètres calldata astucieux et j'ai appelé [Forwarder].execute
Cette fonction a lancé multicall dans le contrat TIME, et le reste de calldata a été utilisé pour burn() - destruction de tokens dans le pool!
Comment ça fonctionne ?
Dans cette attaque, les étoiles se sont alignées : ERC-2771, Multicall et des données soigneusement élaborées. Le contrat TOKEN hérite de ERC2771Context, et c'est ici que les choses deviennent vraiment intéressantes !
ERC-2771 donne un msg.sender virtuel, permettant de déléguer des transactions à un tiers. L'adresse réelle est ajoutée dans le calldata. Lorsque [Forwarder] appelle le contrat, _msgSender() vérifie ces données et coupe les 20 derniers octets comme "vrai" msg.sender.
Multicall transforme un appel en plusieurs, économisant du gaz. Il prend un tableau d'appels et les exécute via deleGatecall().
Et là, c'est le piège ! L'attaquant décale le calldata de sorte que les 4 premiers octets des nouvelles données correspondent à la fonction burn(), et le paramètre est une énorme somme de tokens. À la ligne 0x20, l'adresse de la piscine de liquidité TIME-ETH est ajoutée, ce qui devient le msg.sender "attendu" !
Racine du problème
Dans ERC-2771, [Forwarder] n'était jamais prévu pour fonctionner avec multicall ! L'attaquant a ajouté les paramètres _msgSender() à l'appel externe multicall. À l'intérieur de la fonction multicall, certaines fonctions ont également ajouté ces paramètres, ce qui a permis de simuler un appel depuis N'IMPORTE QUEL adresse !
Mesures de protection
La nouvelle version d'OpenZeppelin Multicall conserve désormais la longueur du contexte ERC-2771 et en tient compte à chaque appel enfant.
ThirdWeb est allé plus loin en interdisant à tout contrat d'appeler multicall, empêchant l'utilisation de [Forwarder].
Cette vulnérabilité est un exemple frappant de la manière dont une combinaison de composants sûrs séparément peut créer une faille catastrophique ! Tous les développeurs doivent se rappeler : vérifiez toujours l'interaction entre les différents standards.
Cette page peut inclure du contenu de tiers fourni à des fins d'information uniquement. Gate ne garantit ni l'exactitude ni la validité de ces contenus, n’endosse pas les opinions exprimées, et ne fournit aucun conseil financier ou professionnel à travers ces informations. Voir la section Avertissement pour plus de détails.
Analyse du principe de la vulnérabilité de substitution d'adresse arbitraire dans ERC2771 Multicall de SharkTeam
Le 8 décembre 2023, OpenZeppelin a publié un avertissement important concernant la sécurité. Il s'avère qu'en utilisant le standard ERC-2771 et des fonctions de type Multicall, il existe un risque de substitution d'adresse ! J'ai profondément étudié cette vulnérabilité et je souhaite partager mes découvertes.
Analyse de l'attaque
Considérons l'une des attaques :
Le schéma de l'attaque est brillamment simple :
Comment ça fonctionne ?
Dans cette attaque, les étoiles se sont alignées : ERC-2771, Multicall et des données soigneusement élaborées. Le contrat TOKEN hérite de ERC2771Context, et c'est ici que les choses deviennent vraiment intéressantes !
ERC-2771 donne un msg.sender virtuel, permettant de déléguer des transactions à un tiers. L'adresse réelle est ajoutée dans le calldata. Lorsque [Forwarder] appelle le contrat, _msgSender() vérifie ces données et coupe les 20 derniers octets comme "vrai" msg.sender.
Multicall transforme un appel en plusieurs, économisant du gaz. Il prend un tableau d'appels et les exécute via deleGatecall().
Et là, c'est le piège ! L'attaquant décale le calldata de sorte que les 4 premiers octets des nouvelles données correspondent à la fonction burn(), et le paramètre est une énorme somme de tokens. À la ligne 0x20, l'adresse de la piscine de liquidité TIME-ETH est ajoutée, ce qui devient le msg.sender "attendu" !
Racine du problème
Dans ERC-2771, [Forwarder] n'était jamais prévu pour fonctionner avec multicall ! L'attaquant a ajouté les paramètres _msgSender() à l'appel externe multicall. À l'intérieur de la fonction multicall, certaines fonctions ont également ajouté ces paramètres, ce qui a permis de simuler un appel depuis N'IMPORTE QUEL adresse !
Mesures de protection
La nouvelle version d'OpenZeppelin Multicall conserve désormais la longueur du contexte ERC-2771 et en tient compte à chaque appel enfant.
ThirdWeb est allé plus loin en interdisant à tout contrat d'appeler multicall, empêchant l'utilisation de [Forwarder].
Cette vulnérabilité est un exemple frappant de la manière dont une combinaison de composants sûrs séparément peut créer une faille catastrophique ! Tous les développeurs doivent se rappeler : vérifiez toujours l'interaction entre les différents standards.