Interchaînes, DeFi et contrats intelligents · Leçon 5 sur 6
Analyser les exploitations de vulnérabilités et les piratages
12 min de lecture
Lorsqu’un protocole ou une plateforme d'échange est piraté, les analystes se voient poser les mêmes questions en quelques heures : que s’est-il passé, combien a été dérobé, où se trouvent les fonds maintenant et qui en est l’auteur ? Les réponses proviennent d’un petit nombre de transactions examinées dans les moindres détails, suivi d’un long travail de traçage. Cette leçon rassemble les compétences de décodage de ce module et des précédents (tokens, proxys, swaps, prêts flash et ponts) et les applique à des cas publics.
Le cycle de vie d’une exploitation de vulnérabilité dans les données
La plupart des incidents, quelle que soit leur cause racine, passent par les mêmes phases, et chaque phase laisse des éléments de preuve différents :
| Phase | Ce que fait l’attaquant | Éléments de preuve à recueillir |
|---|---|---|
| Financement | Obtient des fonds pour payer le gas de nouvelles adresses | Premier transfert entrant vers chaque adresse de l’attaquant et sa source |
| Préparation | Déploie des contrats d’attaque, effectue des tests, parfois d’abord sur d’autres chaînes | Créations de contrats, tentatives échouées et motifs d’annulation associés, bytecode |
| Exécution | Exécute une ou plusieurs transactions d’attaque | Traces, journaux, variations de solde par adresse et par token |
| Consolidation | Échange les tokens susceptibles d’être gelés ou peu liquides contre de l’ETH ou d’autres actifs neutres, regroupe les fonds | Swaps sur DEX ayant un fort impact sur le prix, transferts entre adresses de l’attaquant |
| Dispersion | Fractionne les fonds, les transfère par des ponts, utilise des mixeurs, les échange contre des bitcoins, les convertit en monnaie fiduciaire | Schémas de distribution vers de multiples adresses, dépôts sur des ponts, dépôts dans des mixeurs, adresses de dépôt de plateformes d'échange |
Les phases se chevauchent et, en cas de compromission de clés, la préparation se déroule hors chaîne. Néanmoins, organiser les éléments de preuve de cette manière évite qu’une enquête se concentre directement sur la transaction la plus visible et passe à côté du financement susceptible d’identifier l’attaquant.
Lire la transaction d’attaque
Commencez par la trace, et non par les journaux. Les journaux enregistrent ce que les contrats ont choisi d’annoncer ; la trace enregistre chaque appel, sa valeur et sa réussite ou son échec. Voici un ordre de travail pratique :
- Recensez les acteurs : le compte détenu par un utilisateur externe qui a envoyé la transaction, le contrat d’attaque qu’il a appelé, les contrats victimes et toute adresse qui réalise finalement un bénéfice.
- Calculez les variations de solde par adresse et par token pour l’ensemble de la transaction (la requête de calcul des soldes nets présentée dans la leçon Swaps sur DEX, plateformes d'échange instantané et flux de liquidité convient ici). Le gain net de l’attaquant et la perte nette de la victime permettent de cadrer tout le reste.
- Parcourez l’arbre des appels depuis le sommet, en repérant les prêts flash (des prêts sans garantie qui doivent être remboursés, majorés d’une commission, avant la fin de la transaction, faute de quoi celle-ci est entièrement annulée), afin que le capital emprunté ne soit pas comptabilisé comme une perte.
- Repérez l’étape à laquelle l’état du protocole est devenu incohérent. Il s’agit de la cause racine, généralement un seul appel de fonction.
Un récapitulatif des variations de solde d’une transaction d’attaque fictive montre ce que produit l’étape 2 :
{
"tx_hash": "0x7c0d…e91a",
"block_number": 21000417,
"balance_changes": [
{"address": "0xa77a…c0de", "role": "contrat d’attaque", "token": "DAI", "delta": "+2400000.00"},
{"address": "0x5af3…71b2", "role": "pool victime", "token": "DAI", "delta": "-2401000.00"},
{"address": "0x87f1…4e2a", "role": "prêteur du prêt flash", "token": "DAI", "delta": "+1000.00"},
{"address": "0x3e9d…02f7", "role": "EOA expéditeur", "token": "ETH", "delta": "-0.041"}
]
}
Le prêt flash de 2 000 000 DAI du prêteur n’apparaît pas du tout, car il est sorti puis revenu au cours de la même transaction ; seule sa commission de 1 000 DAI (0,05 %) subsiste. La victime a perdu 2 401 000 DAI, le contrat d’attaque en a conservé 2 400 000, et l’expéditeur a payé 0,041 ETH de gas.
L’exploitation de vulnérabilité d’Euler Finance du 13 mars 2023 illustre cette méthode. Les analyses publiées par des chercheurs en sécurité ramènent l’une des transactions d’attaque aux étapes suivantes :
Contrat d’attaque, l’une des plusieurs transactions d’attaque (pool DAI)
1. Prêt flash de 30 000 000 DAI auprès d’Aave
2. Dépôt de 20 000 000 DAI dans Euler -> tokens de garantie (eDAI)
3. mint() : auto-effet de levier -> dette de 200 000 000 dDAI, 195 600 000 eDAI
4. Remboursement de 10 000 000 DAI -> destruction de 10 000 000 dDAI
5. Nouvel appel à mint() -> 200 000 000 dDAI et 195 600 000 eDAI supplémentaires
6. donateToReserves(100,000,000 eDAI) -> aucun contrôle de solvabilité : compte désormais insolvable
7. Un second contrat d’attaque liquide le premier avec une décote de 20 %
8. Retrait de 38 900 000 DAI, remboursement du prêt flash et de la commission, conservation du reste
L’étape 6 est la cause racine : une fonction qui réduisait la garantie sans vérifier la santé du compte. Les étapes 1 et 8 se compensent pour le capital emprunté. Répétée sur plusieurs pools, l’attaque a permis de dérober environ 197 millions de dollars en DAI, WETH, WBTC, stETH et USDC. L’attaquant en a échangé la majeure partie contre de l’ETH et du DAI, a envoyé 100 ETH à un mixeur, puis a négocié avec le protocole au moyen de messages sur la chaîne et a restitué tous les fonds récupérables au plus tard le 3 avril 2023. Les messages sur la chaîne méritent d’être décodés : il s’agit de texte dans les données d’entrée de simples transferts, et ils font partie des éléments du dossier.
Financement, préparation et imitateurs
Le financement d’une adresse de l’attaquant est souvent la meilleure piste d’attribution. Les sources courantes sont les retraits de mixeurs (les pools Tornado Cash utilisaient des montants fixes tels que 0,1, 1, 10 et 100 ETH), les ponts depuis une autre chaîne, les services de plateforme d'échange instantané et, occasionnellement, un retrait d’une plateforme d'échange, qui peut faire l’objet d’un suivi par voie judiciaire (voir la leçon Traçage à travers les plateformes d'échange et les services de conservation). Vérifiez également :
- Le déployeur de chaque contrat d’attaque et les autres contrats qu’il a déployés, y compris les versions de test sur d’autres chaînes.
- La similarité du bytecode avec des contrats d’attaque antérieurs, qui peut permettre de relier des incidents.
- Les tentatives échouées avant celle qui a réussi : leurs motifs d’annulation montrent ce que l’attaquant testait et quand il a commencé.
Toutes les adresses qui réalisent un bénéfice ne sont pas celles de l’attaquant initial. Les bots MEV copient des transactions rentables en attente, et certains groupes de hackers éthiques devancent les attaques pour sauver des fonds. Dans le cas d’Euler, une adresse qui affirmait que son bot avait accidentellement copié la première attaque a finalement transmis le DAI à l’attaquant malgré tout, car l’adresse de celui-ci était codée en dur dans le contrat copié. Lors de l’incident du pont Nomad d’août 2022, des centaines d’adresses ont simplement rejoué la transaction du premier attaquant en y substituant leur propre adresse. Étiquetez ces acteurs séparément, en indiquant le degré de confiance, et ne publiez jamais l’identité d’un particulier sur la seule base de tels liens (voir la leçon De l’adresse à l’entité, puis à la personne : attribution et étiquetage).
Lorsque le bug n’est pas dans le code
Certains des vols les plus importants n’impliquaient aucune faille de contrat intelligent. Lors du vol sur le pont Ronin de mars 2022, les attaquants contrôlaient cinq des neuf clés de validation requises par le pont, ce qui suffisait pour signer des retraits d’environ 173 600 ETH et 25,5 millions d’USDC ; le vol est passé inaperçu pendant six jours. Les autorités américaines ont attribué le vol au Lazarus Group de Corée du Nord en avril 2022. Sur la chaîne, les retraits étaient valablement signés ; seul le contexte (montant, destinataire et moment inhabituels) permettait de les repérer.
Le vol de Bybit du 21 février 2025, d’environ 1,5 milliard de dollars, était le plus important vol de cryptomonnaies jamais enregistré au moment des faits et constitue une leçon sur la lecture de ce que les signataires ont réellement approuvé. Le portefeuille froid de la plateforme d'échange était un proxy multisignature Safe. Les enquêteurs ont constaté que l’interface du portefeuille avait été compromise par l’intermédiaire de la machine d’un développeur chez le fournisseur du portefeuille : les signataires voyaient donc un transfert courant, tandis que leurs portefeuilles matériels signaient autre chose. Une fois décodée, la transaction signée se présente ainsi :
SafeProxy.execTransaction(...) -- sélecteur 0x6a761202, trois signatures valides
to = contrat de l’attaquant
data = transfer(...) -- nom de fonction d’apparence inoffensive
operation = 1 -- DELEGATECALL, et non CALL
DELEGATECALL contrat de l’attaquant.transfer(...) -- s’exécute avec le stockage du proxy
SSTORE slot 0 := implémentation malveillante -- pointeur singleton de Safe remplacé
Puis : sweepETH(...) et sweepERC20(...) appelées sur le proxy, sans signatures nécessaires
Comme un proxy Safe conserve son pointeur d’implémentation dans l’emplacement de stockage 0 (voir la leçon Décoder les interactions avec les contrats intelligents), un delegatecall qui écrit dans l’emplacement 0 cède le contrôle de l’ensemble du portefeuille. Les transactions de vidage ont ensuite déplacé environ 401 346 ETH, 90 375 stETH, 15 000 cmETH et 8 000 mETH. Le 26 février 2025, le FBI a attribué le vol à des acteurs nord-coréens qu’il appelle TraderTraitor, a publié une liste d’adresses et a signalé que les fonds étaient en cours de conversion en bitcoins et répartis sur des milliers d’adresses sur plusieurs chaînes. Les enseignements pour l’analyste : décoder chaque champ operation dans les transactions multisignatures, déclencher une alerte pour tout delegatecall vers un contrat inconnu et surveiller les emplacements d’implémentation des proxys détenant des montants élevés.
Traçage après l’incident
Les premières heures déterminent la quantité de fonds qui pourra être gelée ou signalée. Voici une séquence typique :
- Constituez l’ensemble initial d’adresses : toutes les adresses contrôlées par l’attaquant identifiées à partir des transactions d’attaque, du financement et des liens avec les déployeurs.
- Surveillez les actifs susceptibles d’être gelés. Certains émetteurs de stablecoins peuvent geler les soldes, ce qui explique pourquoi les attaquants les échangent en premier ; signalez rapidement les adresses.
- Communiquez les adresses et les empreintes de transaction aux plateformes d'échange, aux ponts et aux autres services susceptibles de recevoir les fonds, par leurs canaux de signalement établis.
- Tracez la consolidation et la dispersion vers l’aval, saut par saut, d’une chaîne à l’autre (voir les leçons Traçage conforme aux exigences de preuve, Passage entre chaînes et traçage interchaînes et Mixeurs dépositaires).
-- Deux premiers sauts depuis les adresses initiales d’un incident, flux les plus importants en premier
WITH seeds AS (
SELECT address FROM incident_addresses WHERE incident_id = 'INC-0142'
), hop1 AS (
SELECT t.to_address, SUM(t.amount_usd) AS usd, MIN(t.block_timestamp) AS first_seen
FROM value_transfers t JOIN seeds s ON t.from_address = s.address
WHERE t.to_address NOT IN (SELECT address FROM seeds)
GROUP BY t.to_address
)
SELECT h.to_address AS hop1, t.to_address AS hop2, SUM(t.amount_usd) AS usd
FROM hop1 h
JOIN value_transfers t
ON t.from_address = h.to_address AND t.block_timestamp >= h.first_seen
GROUP BY h.to_address, t.to_address
ORDER BY usd DESC;
La requête suppose l’existence d’une table value_transfers qui combine déjà les transferts natifs issus des traces et les transferts de tokens, chacun étant valorisé au moment du transfert. La première CTE trouve les adresses ayant reçu des fonds de l’ensemble initial (en excluant les mouvements entre adresses de cet ensemble) ; l’étape finale suit chacune d’elles un saut plus loin, en ne comptabilisant que les transferts postérieurs à la première réception. Les flux importants du deuxième saut vers des services connus sont ceux pour lesquels des enregistrements hors chaîne peuvent exister.
Rédiger le compte rendu d’un incident
Classez la cause racine, car elle détermine quels éléments de preuve sont pertinents :
| Catégorie de cause racine | Exemple public | Signature typique dans les données |
|---|---|---|
| Faille logique | Euler, 2023 | Prêt flash associé à une séquence d’appels inhabituelle laissant un état impossible |
| Initialisation ou contrôle d’accès | Nomad, 2022 | De nombreux appelants réussissent avec les mêmes données d’appel |
| Vérification des signatures | Wormhole, 2022 | Tokens créés sans dépôt correspondant |
| Compromission de clés | Ronin, 2022 | Retraits valablement signés, aucun bug dans le code |
| Interface ou chaîne d’approvisionnement | Bybit, 2025 | Transaction valablement signée avec un delegatecall inattendu |
| Gouvernance | Beanstalk, 2022 | Pouvoir de vote emprunté, proposition exécutée dans la même transaction |
Évaluez les pertes aux prix en vigueur au bloc de chaque transaction d’attaque, répertoriez chaque transaction d’attaque avec la hauteur de bloc et consignez les montants récupérés séparément de la perte. Les leçons Rédiger le rapport d’investigation numérique : degré de confiance et formulation et Éthique, vie privée, protection des données et sécurité des enquêteurs expliquent comment présenter et partager ces constatations.
Points clés pour l'examen : les cinq phases d’une exploitation de vulnérabilité et les éléments de preuve laissés par chacune ; la lecture de la transaction d’attaque à partir de la trace, le calcul des variations de solde et la neutralisation du capital des prêts flash ; les étapes de l’attaque Euler et sa cause racine (donateToReserves sans contrôle de santé du compte) ; les sources de financement, les liens entre déployeurs et bytecodes, les tentatives échouées et les imitateurs comme pistes d’attribution ; les compromissions de clés et d’interfaces (Ronin, Bybit) et le delegatecall de Safe qui a réécrit l’emplacement 0 ; les priorités des premières heures (ensemble initial d’adresses, actifs susceptibles d’être gelés, notification des services) ; les requêtes par sauts sur les transferts natifs et de tokens combinés ; les catégories de causes racines et l’évaluation des pertes aux prix du bloc.
Questions d’entraînement
Vérifiez votre compréhension. Ces questions ne comptent pas pour l’examen.
Connectez-vous pour enregistrer votre progression et reprendre là où vous vous êtes arrêté. C’est gratuit. Se connecter