
La bataille pour les 97 millions de dollars de la chaîne Blast, un hacker d'un certain pays aurait-il perdu la main ?
TechFlow SélectionTechFlow Sélection

La bataille pour les 97 millions de dollars de la chaîne Blast, un hacker d'un certain pays aurait-il perdu la main ?
Qu'est-ce qui s'est passé ? Le projet Munchables attaqué, environ 97 millions de dollars exposés au risque
Rédaction : CertiK
Contexte
Blast est un réseau Ethereum Layer2 lancé par Pacman (Tieshun Roquerre, alias Tieshun), le fondateur de Blur. Le réseau principal a été activé le 29 février, et compte actuellement environ 19 500 ETH et 640 000 stETH mis en jeu sur le réseau principal Blast.
Le projet attaqué, Munchables, est un projet de qualité ayant remporté le concours Bigbang organisé par Blast.
Les utilisateurs ayant mis en jeu leur ETH sur le réseau principal Blast reçoivent des points ordinaires de la part de l'équipe officielle de Blast :

Afin d'encourager les utilisateurs à participer aux projets DeFi présents dans l'écosystème Blast, l'équipe officielle sélectionne certains projets qualitatifs pour les promouvoir. En incitant les utilisateurs à engager une seconde fois leurs ETH dans ces projets DeFi, ceux-ci peuvent accumuler plus rapidement des points ainsi que des points dorés. Par conséquent, un grand nombre d'utilisateurs ont réengagé leurs ETH placés initialement sur le réseau principal Blast vers de nouveaux projets DeFi.
Cependant, la maturité et la sécurité de ces projets DeFi restent à évaluer. Les contrats associés sont-ils suffisamment sécurisés pour gérer des fonds allant jusqu'à plusieurs dizaines, voire centaines de millions de dollars ?

Résumé de l'incident
Moins d'un mois après le lancement du réseau principal Blast, un incident a eu lieu le 21 mars 2024 ciblant le token SSS (Super Sushi Samurai). Une erreur logique dans le contrat du token permettait à un attaquant d'augmenter arbitrairement le solde SSS d'un compte spécifié, causant une perte totale au projet dépassant 1 310 ETH (environ 4,6 millions de dollars).
Moins d'une semaine après cet incident, un nouvel événement encore plus important s'est produit sur Blast : le projet Munchables a été piraté, entraînant le vol de 17 413,96 ETH, soit environ 62,5 millions de dollars.
Une demi-heure après cette transaction d'attaque, 73,49 WETH présents dans le contrat du projet ont également été transférés vers une autre adresse contrôlée par le pirate.
À ce moment-là, le contrat du projet conservait encore 7 276 WETH, 7 758 267 USDB et 4 ETH, tous exposés au risque d'être entièrement subtilisés par le pirate, qui disposait désormais des droits nécessaires pour accéder à l'intégralité des fonds du projet — un montant total exposé d'environ 97 millions de dollars.
Peu après l'incident, zachXBT, un célèbre détective blockchain sur X (Twitter), a indiqué que l'attaque était liée à l'embauche d'un pirate informatique provenant d'un certain pays.
Examinons maintenant comment ce « pirate d'un certain pays » a pu mener une attaque approchant les 100 millions de dollars.

Reconstitution des faits
Prise de parole de la victime
[UTC+0] Le 26 mars 2024 à 21h37 (soit 5 minutes après l'attaque), Munchables a publié sur X (Twitter) un message annonçant qu'il avait été attaqué.

Selon l'enquête menée par le détective blockchain ZachXBT, l'un des développeurs du projet serait un « pirate d'un certain pays ». Coderdannn, fondateur de Aavegotchi, a également confirmé sur X (Twitter) : « L'équipe de développement Pixelcraft Studios, derrière Aavegotchi, avait brièvement embauché l'attaquant de Munchables en 2022 pour effectuer quelques travaux de développement de jeu. Il était techniquement médiocre, clairement semblable à un pirate dudit pays. Nous l'avons licencié au bout d'un mois. Il avait aussi tenté de nous faire embaucher un ami, qui était probablement lui aussi un pirate. »
Compte tenu de l'ampleur des pertes subies par la communauté, nous avons immédiatement lancé une enquête sur chaîne. Examinons maintenant en détail les actions de ce « pirate d'un certain pays ».
Première scène
[UTC+0] Le 26 mars 2024 à 21h32, une attaque impliquant 17 413,96 ETH a eu lieu.
Via Blastscan, on peut consulter cette transaction d'attaque : https://blastscan.io/tx/0x9a7e4d16ed15b0367b8ad677eaf1db6a2a54663610696d69e1b4aa1a08f55c95

Le contrat compromis (0x29..1F) est un contrat proxy contenant les fonds mis en jeu par les utilisateurs. On observe que l'attaquant a appelé la fonction unlock du contrat de mise en gage, a passé tous les contrôles d'autorisation, puis a transféré la totalité des ETH du contrat vers l'adresse de l'attaquant 1 (0x6E..c5).

On dirait que l'attaquant a simplement appelé une fonction unlock similaire à un retrait, récupérant ainsi la majorité des ETH présents sur le contrat compromis (0x29..1F).
La trésorerie du projet aurait-elle oublié de verrouiller ses fonds ?
La fonction unlock du contrat compromis (0x29..1F) comporte deux vérifications importantes. Analysons-les une par une.
Premièrement, dans le processus de vérification des permissions, le contrat appelle la méthode isRegistered du contrat (0x16..A0) afin de vérifier si l'expéditeur actuel (msg.sender), c'est-à-dire l'adresse pirate 1 (0x6E..c5), a bien été enregistrée :


La réponse est : la vérification a réussi.

Cette opération concerne le contrat (0x16..A0) et son contrat logique le plus récent (0xe7..f1).
[UTC+0] Le 24 mars 2024 à 08h39 (soit deux jours avant l'attaque), le contrat logique associé au contrat (0x16..A0) a été mis à jour.

Transaction de mise à jour du contrat logique :
https://blastscan.io/tx/0x9c431e09a80d2942319853ccfdaae24c5de23cedfcef0022815fdae42a7e2ab6
Le contrat logique a été mis à jour vers l'adresse 0xe7..f1.
L'adresse initiale du contrat logique pouvait être consultée ici : 0x9e..CD.
https://blastscan.io/tx/0x7ad050d84c89833aa1398fb8e5d179ddfae6d48e8ce964f6d5b71484cc06d003

Nous soupçonnons alors que l'attaquant aurait modifié le contrat logique du proxy, remplaçant le contrat initial 0x9e..CD par un contrat malveillant 0xe7..f1, permettant ainsi de contourner les contrôles d'accès.
Était-ce vraiment le cas ?
Dans le monde Web3.0, il n'est jamais nécessaire de spéculer ni de croire aveuglément aux dires des autres ; il suffit de maîtriser la technique pour trouver soi-même la vérité.
En comparant les deux contrats (non ouverts), on observe des différences notables entre le contrat initial 0x9e..CD et le contrat mis à jour 0xe7..f1 :
Voici la partie concernant la fonction initialize du contrat 0xe7..f1 :

Et voici celle du contrat 0x9e..CD :

On constate que l'attaquant a intégré dès le départ dans le contrat logique initial (0x9e..CD) l'adresse de l'attaquant (0x6e..c5) comme étant enregistrée. Deux autres adresses pirates, 0xc5..0d et 0xbf..87, ont également été enregistrées, avec leur champ field0 défini à la valeur du timestamp du bloc d'initialisation. Ce champ field0 sera expliqué ultérieurement.
En réalité, contrairement à notre hypothèse initiale, c'est précisément le contrat logique initial qui contenait la porte dérobée, tandis que celui mis à jour par la suite était normal !
Attendez… Cette mise à jour date du [UTC+0] 24 mars 2024 à 08h39 (deux jours avant l'attaque), ce qui signifie que le contrat logique avait déjà été remplacé par une version sans backdoor avant même l’incident. Alors pourquoi l'attaquant a-t-il pu réussir son attaque ?
Cela s'explique par l'utilisation de delegatecall : les modifications d'état sont appliquées directement dans le contrat (0x16..A0). Ainsi, même après la mise à jour du contrat logique vers une version saine (0xe7..f1), les données stockées dans les slots du contrat (0x16..A0) ne sont pas restaurées.
Vérifions cela :

On constate bien que le slot correspondant dans le contrat (0x16.....A0) contient une valeur.
Cela permet à l'attaquant de passer la vérification via la méthode isRegistered :

L'attaquant a ensuite remplacé le contrat piégé par un contrat normal pour brouiller les pistes, mais la porte dérobée était déjà activée.
Par ailleurs, lors du processus unlock, une deuxième vérification intervient :
La vérification de la durée de verrouillage, destinée à empêcher le transfert prématuré d'actifs encore bloqués.

L'attaquant devait s'assurer que le timestamp du bloc au moment de l'appel à unlock soit supérieur à la date d'expiration définie (field3).
Cette vérification concerne le contrat compromis (0x29..1F) et son contrat logique associé 0xf5..cd.
Dans la transaction du [UTC+0] 21 mars 2024 à 11h54 (soit cinq jours avant l'attaque),
https://blastscan.io/tx/0x3d08f2fcfe51cf5758f4e9ba057c51543b0ff386ba53e0b4f267850871b88170

On observe que le contrat initial du contrat compromis (0x29..1F) était 0x91..11. Quatre minutes plus tard,
https://blastscan.io/tx/0xea1d9c0d8de4280b538b6fe6dbc3636602075184651dfeb837cb03f8a19ffc4f

il a été mis à jour vers 0xf5..cd.
En comparant les deux contrats, on remarque que l'attaquant a encore agi de la même manière dans la fonction initialize.
Voici la fonction initialize du contrat 0xf5..cd :

Et celle du contrat 0x91..11 :

Encore une fois, on observe clairement la même méthode : modification frauduleuse du nombre d'ETH détenus et du temps de déverrouillage, suivie du remplacement par un contrat normal pour masquer les traces. Lorsque l'équipe du projet ou des chercheurs en sécurité analysent le code, ils ne voient que des contrats logiques normaux. Comme les contrats ne sont pas open source, il devient extrêmement difficile d'identifier la racine du problème.
Jusqu'ici, nous comprenons comment la transaction impliquant 17 413 ETH a pu avoir lieu. Mais y a-t-il davantage derrière cet incident ?
Dans nos analyses précédentes, nous avons vu que le pirate avait intégré trois adresses dans le contrat :
0x6e..c5 (adresse pirate 1)
0xc5..0d (adresse pirate 2)
0xbf..87 (adresse pirate 3)
Pourtant, dans la transaction d'attaque analysée plus haut, seule l'adresse 0x6e..c5 apparaît. Que font les deux autres adresses ? Et que cachent les valeurs address(0), _dodoApproveAddress et _uniswapV3Factory ?
Deuxième scène
Analysons d'abord l'adresse pirate 3 (0xbf..87), qui a utilisé la même méthode pour voler 73,49 WETH :
https://blastscan.io/tx/0xfc7bfbc38662b659bf6af032bf20ef224de0ef20a4fd8418db87f78f9370f233
Et l'adresse source des frais de gaz (0x97..de) a fourni des frais de transaction à la fois à 0xc5..0d (adresse pirate 2) et à 0xbf..87 (adresse pirate 3).

L'adresse source des frais de gaz (0x97..de) tire ses 0,1 ETH d'owlto.finance (un pont cross-chain).
Après avoir reçu les frais de transaction, l'adresse 0xc5..0d (attaquant 2) n'a effectué aucune attaque. Pourtant, elle joue un rôle dans un plan caché. Continuons notre analyse.
En réalité, selon la transaction de sauvetage publiée par l'équipe officielle, le contrat compromis (0x29..1F) contenait bien plus que les 73,49 WETH mentionnés. À la fin de l'attaque, il restait encore 7 276,5 WETH et 7 758 267 USDB sur le contrat.
Transaction de sauvetage :
https://blastscan.io/tx/0x1969f10af9d0d8f80ee3e3c88d358a6f668a7bf4da6e598e5be7a3407dc6d5bb

Initialement, l'attaquant prévoyait de voler tous ces actifs. On voit que l'adresse 0xc5..0d (attaquant 2) était destinée à subtiliser les USDB.

Ici, _dodoApproveAddress vaut 0x0000000000000000000000004300000000000000000000000000000000000003

qui correspond à l'adresse du token USDB

L'adresse 0xbf..87 (attaquant 3) visait quant à elle le vol des WETH :

Ici, _uniswapV3Factory vaut 0x0000000000000000000000004300000000000000000000000000000000000004

qui correspond à l'adresse du WETH

Quant à l'adresse 0x6e..c5 (attaquant 1), elle était chargée de subtiliser address(0), c'est-à-dire l'actif natif ETH.
L'attaquant, en définissant correctement le champ field0, pouvait ainsi voler les actifs correspondants via la logique suivante :


Questions
Pourquoi l'attaquant n'a-t-il pas volé tous les actifs ?
Théoriquement, il aurait pu subtiliser tous les fonds restants, notamment les WETH et les USDB.
L'adresse 0xbf..87 (attaquant 3) n'a récupéré que 73,49 WETH, alors qu'elle aurait pu prendre les 7 350 WETH disponibles. Elle aurait aussi pu utiliser l'adresse 0xc5..0d (attaquant 2) pour prendre l'intégralité des 7 758 267 USDB. Pourquoi s'est-il arrêté après avoir pris une petite quantité de WETH ? Nous l'ignorons. Une enquête approfondie d'un détective blockchain pourrait peut-être y répondre.
https://blastscan.io/tx/0xfc7bfbc38662b659bf6af032bf20ef224de0ef20a4fd8418db87f78f9370f233

Pourquoi l'attaquant n'a-t-il pas transféré les 17 413 ETH vers le réseau principal Ethereum ?
Comme chacun sait, le réseau principal Blast pourrait intercepter ces ETH de manière centralisée, les immobilisant définitivement et évitant ainsi des pertes réelles pour les utilisateurs. En revanche, une fois transférés sur le réseau principal Ethereum, ces fonds deviendraient impossibles à bloquer.
Nous avons évalué les ponts cross-chain actuels de Blast : le pont officiel n'impose aucune limite de quantité, mais exige un délai de sortie de 14 jours, laissant ample temps à l'équipe Blast pour organiser une interception.
Les ponts tiers permettent quant à eux un retrait quasi instantané, comme l'a montré la source des frais de l'attaquant, qui a franchi le pont très rapidement. Alors pourquoi l'attaquant n'a-t-il pas immédiatement initié un retrait cross-chain ?
En réalité, l'attaquant a effectué un transfert cross-chain dès les premières secondes (dans les 2 minutes suivant l'attaque) :
https://blastscan.io/tx/0x10cf2f2b884549979a3a1dd912287256229458ef40d56df61738d6ea7d9d198f

Les fonds ont été crédités sur le réseau principal Ethereum en seulement 20 secondes. Théoriquement, l'attaquant aurait pu continuer à effectuer des transferts successifs et évacuer une grande partie des ETH avant que les équipes du pont n'interviennent manuellement.

La raison pour laquelle chaque transfert était limité à 3 ETH réside dans les contraintes de liquidité du pont cross-chain reliant Blast à Ethereum :

Un autre pont prenant en charge Blast offre encore moins de capacité :

Après cette transaction de retrait, l'attaquant n'a effectué aucun autre transfert cross-chain. La raison reste inconnue. On dirait que le « pirate d'un certain pays » n'était pas suffisamment préparé à sortir les fonds de Blast.
Évolution après l'attaque
Suite aux retours d'un utilisateur de la communauté nommé Nearisbuilding, ce dernier a découvert davantage d'informations identifiant l'attaquant et a cherché à le convaincre de restituer les
Bienvenue dans la communauté officielle TechFlow
Groupe Telegram :https://t.me/TechFlowDaily
Compte Twitter officiel :https://x.com/TechFlowPost
Compte Twitter anglais :https://x.com/BlockFlow_News










