Attaques sur les contrats intelligents : ce qu’un auditeur repère avant les pirates

Réentrance, manipulation d'oracle, prêt flash, clés mal gardées : les milliards perdus depuis 2021 se rangent dans un petit nombre de familles. Reste à savoir ce qu'un audit de contrat couvre réellement, et ce qu'il laisse dehors.

Voir la table des matières Ne plus voir la table des matières

Un contrat intelligent est un programme déposé sur une blockchain, qui exécute automatiquement les termes d’un accord dès que les conditions prévues sont réunies. Nick Szabo en a formulé le concept dès 1996, bien avant qu’Ethereum ne le rende praticable à son lancement en 2015. Depuis, ces programmes gèrent des sommes considérables sans intermédiaire humain, ce qui constitue à la fois leur promesse et leur faiblesse.

La faiblesse est arithmétique. Un contrat déployé est public, immuable et manipule des fonds : n’importe qui peut lire son code, aucun correctif ne s’applique après coup, et une erreur se monétise immédiatement. Chainalysis a estimé à 2 milliards de dollars les fonds dérobés dans treize piratages de ponts inter-chaînes sur les seuls sept premiers mois de 2022, soit 69 % du total volé cette année-là. La quasi-totalité de ces pertes vient d’un défaut de conception ou de vérification dans un contrat.

Face à cela s’est constituée une profession, celle de l’auditeur de contrats intelligents, dont le métier consiste à trouver la faille avant qu’un attaquant ne la trouve. Certaines catégories d’attaques sont devenues si documentées qu’un auditeur compétent les repère en quelques heures de lecture, tandis que d’autres exigent des semaines de modélisation. Comment un auditeur travaille-t-il concrètement, et jusqu’où sa signature protège-t-elle réellement les fonds déposés ?

Qu’est-ce qu’un contrat intelligent et pourquoi son code est-il si exposé ?

Un contrat intelligent est un programme stocké sur une blockchain, exécuté à l’identique par tous les nœuds du réseau. Son code source est presque toujours public et vérifiable, et son comportement ne peut plus être modifié après déploiement sur Ethereum. Cette combinaison de transparence totale et d’immuabilité fait de chaque ligne écrite un engagement définitif, lisible par tous les attaquants du monde.

Un programme qui exécute lui-même les termes d’un accord

Le principe est simple à énoncer. Un utilisateur envoie une transaction au contrat, celui-ci vérifie des conditions, met à jour son état interne et déclenche éventuellement un transfert de fonds. Aucune autorité ne valide l’opération, ce qui supprime le délai, le coût et l’arbitraire d’un intermédiaire, mais supprime aussi le recours en cas d’erreur.

Ce fonctionnement a permis l’apparition de la finance décentralisée, où des protocoles de prêt et d’échange fonctionnent sans banque ni courtier. Le prix de cette autonomie est que le contrat doit anticiper lui-même tous les cas de figure, y compris ceux que son auteur n’avait pas imaginés. Une clause oubliée dans un contrat papier se plaide ; une clause oubliée dans un contrat intelligent se pille.

L’immuabilité, qualité et défaut à la fois

L’argument commercial de la blockchain repose sur l’idée qu’un contrat déployé ne peut plus être altéré, ni par son auteur ni par un tiers. Cette garantie protège l’utilisateur contre une modification unilatérale des règles. Elle le prive symétriquement de tout correctif d’urgence lorsqu’une faille est découverte après coup.

Les équipes ont donc développé des mécanismes de mise à jour, souvent fondés sur un contrat mandataire qui redirige les appels vers une implémentation remplaçable. Ces schémas résolvent le problème de la correction, mais en créent un autre : quiconque contrôle la clé de mise à jour contrôle le protocole entier. Une part notable des incidents recensés ces dernières années tient à cette porte laissée ouverte au nom de la maintenance.

Comprendre ces deux propriétés fondamentales permet de saisir pourquoi les familles d’attaques se ressemblent d’un protocole à l’autre.

Quelles sont les principales familles d’attaques sur les contrats intelligents ?

Cinq familles concentrent l’essentiel des pertes recensées : la réentrance, la manipulation d’oracle, les défauts de contrôle d’accès, les erreurs de logique métier et les vulnérabilités propres aux ponts inter-chaînes. La réentrance a servi dès juin 2016 lors de l’attaque contre The DAO, qui a coûté 3,6 millions d’ethers et provoqué la scission d’Ethereum. Les quatre autres ont mûri depuis.

Chacune de ces familles répond à une logique différente, et la première étape d’un audit consiste à établir laquelle s’applique au contrat examiné.

  • la réentrance, où le contrat appelle un contrat externe avant d’avoir mis à jour son propre état, ce qui permet à l’attaquant de rappeler la fonction en boucle ;
  • la manipulation d’oracle, où l’attaquant fausse la source de prix dont dépend le protocole, souvent en la déséquilibrant avec un capital emprunté ;
  • les défauts de contrôle d’accès, où une fonction sensible reste appelable par n’importe qui, ou dépend d’une clé unique mal protégée ;
  • les erreurs de logique métier, où le code fait exactement ce qui a été écrit, mais ce qui a été écrit ne correspond pas à l’intention économique ;
  • les vulnérabilités des ponts inter-chaînes, où la vérification des messages entre deux réseaux se révèle contournable.

Un audit sérieux passe systématiquement en revue ces cinq axes, même lorsque le protocole examiné n’en expose visiblement que deux ou trois. Les incidents les plus coûteux naissent souvent d’une combinaison, par exemple un prêt flash qui alimente une manipulation d’oracle, laquelle déclenche une liquidation absurde.

La réentrance, l’attaque fondatrice

Le scénario se déroule toujours de la même façon. Un contrat de retrait envoie les fonds à l’appelant avant de décrémenter le solde comptabilisé. L’appelant, qui est lui-même un contrat, profite de la réception pour rappeler immédiatement la fonction de retrait, avant que la première exécution ne soit terminée. Le solde n’ayant pas encore bougé, le contrat autorise un second retrait identique, puis un troisième.

Grim Finance a perdu 30 millions de dollars par ce mécanisme en décembre 2021, un attaquant ayant injecté de faux dépôts pendant que les précédents restaient incomplets. Rari Capital, adossé au protocole Fei, a subi une variante plus élaborée en avril 2022, chiffrée à 80 millions de dollars de pertes, qui échappait aux outils de détection automatique de l’époque.

Le prêt flash comme accélérateur

Le prêt flash permet d’emprunter une somme arbitraire sans garantie, à condition de la rembourser dans la même transaction. Cet instrument légitime de la finance décentralisée devient une arme redoutable entre les mains d’un attaquant, parce qu’il annule la barrière du capital. Une faille exploitable avec 200 millions de dollars devient exploitable sans fonds propres.

Beanstalk en a fait l’expérience en avril 2022. L’attaquant a emprunté de quoi acquérir temporairement la majorité des droits de vote, a fait adopter une proposition qui transférait la trésorerie vers son adresse, puis a remboursé le prêt dans la même transaction. 182 millions de dollars ont disparu en un bloc, sans qu’aucune ligne de code ne soit techniquement violée.

Les oracles, point de contact avec le monde extérieur

Un contrat ne peut pas consulter un prix de marché par lui-même. Il dépend d’un oracle, mécanisme qui injecte une donnée externe sur la chaîne. Si cet oracle se contente de lire le prix instantané d’un pool d’échange décentralisé, un attaquant peut le déséquilibrer volontairement le temps d’une transaction et obtenir une valorisation absurde.

La parade tient en peu de choses : recourir à des moyennes pondérées dans le temps, agréger plusieurs sources et poser des bornes de variation. Le fonctionnement détaillé de ces mécanismes d’oracle conditionne directement la robustesse de tout protocole de prêt ou de dérivés. Un auditeur y consacre une part disproportionnée de son temps par rapport au nombre de lignes concernées.

Comment un auditeur détecte-t-il ces vulnérabilités ?

L’auditeur combine trois approches : la lecture manuelle du code, l’analyse statique automatisée et le test dynamique par génération d’entrées aléatoires. Aucune des trois ne suffit isolément. Les outils automatiques repèrent les motifs connus en quelques minutes, mais échouent sur les erreurs de logique métier, qui exigent de comprendre l’intention économique du protocole.

La lecture manuelle, irremplaçable sur la logique

La lecture ligne à ligne reste le cœur du métier. L’auditeur reconstitue les invariants du protocole, ces propriétés qui doivent rester vraies quoi qu’il arrive, puis cherche des séquences d’appels qui les violent. Un invariant mal formulé rend l’audit entier caduc, puisque le vérificateur cherche alors la mauvaise propriété.

Cette phase inclut l’examen des dépendances externes. Un contrat sûr qui appelle un contrat vulnérable hérite de sa vulnérabilité, et la composabilité de la finance décentralisée multiplie ces chaînes d’appels. Un protocole récent peut ainsi reposer sur quatre ou cinq briques tierces, chacune auditée séparément, sans que personne n’ait examiné leur combinaison.

L’outillage automatique, rapide mais borné

Les analyseurs statiques parcourent le bytecode ou le code source à la recherche de motifs dangereux : appel externe avant mise à jour d’état, absence de modificateur de contrôle d’accès, opération arithmétique non protégée. Ils produisent beaucoup de faux positifs, ce qui rend leur exploitation chronophage. Leur valeur tient à leur exhaustivité, pas à leur précision.

Les tests par entrées aléatoires, souvent désignés par le terme anglais de fuzzing, complètent le dispositif en soumettant le contrat à des milliers de séquences imprévues. Ils attrapent parfois ce que la relecture a manqué. Leur efficacité dépend de la qualité des propriétés qu’on leur demande de vérifier, ce qui ramène à l’étape manuelle.

La vérification formelle, pour les protocoles critiques

Sur les contrats qui gèrent les montants les plus importants, certaines équipes vont jusqu’à la preuve mathématique. La vérification formelle démontre qu’une propriété est vraie pour tous les états atteignables, et non seulement pour ceux qui ont été testés. Le coût de cette méthode reste dissuasif pour la plupart des projets, et elle ne couvre que les propriétés effectivement énoncées.

Reste que les preuves les plus solides n’empêchent pas une clé privée de fuiter, ce qui déplace le problème hors du code.

Les attaques réelles qui ont servi de manuel

Les grands incidents de 2021 et 2022 constituent le corpus de référence de la profession. Chacun a fait apparaître un vecteur que la génération précédente ignorait, et chacun a modifié les grilles de vérification employées depuis.

ProtocoleDateMontantVecteur principal
Poly NetworkAoût 2021611 millions de dollarsContrôle d’accès entre contrats
WormholeFévrier 2022325 millions de dollarsVérification de signature défaillante
RoninMars 2022624 millions de dollarsClés de validateurs compromises
BeanstalkAvril 2022182 millions de dollarsPrêt flash et gouvernance
NomadAoût 2022190 millions de dollarsInitialisation de contrat erronée

La lecture de ce tableau réserve une surprise. Les deux montants les plus élevés ne relèvent pas d’une faille de code au sens strict : Ronin a été vidé après compromission de cinq des neuf clés de validateurs du réseau, et Poly Network a exploité une confusion de privilèges entre contrats. Le cas Nomad est plus troublant encore, une mise à jour ayant rendu valide n’importe quel message, ce qui a transformé le pillage en libre-service ouvert à des centaines d’adresses en quelques heures.

Ces épisodes ont durablement modifié la pratique. Un audit ne s’arrête plus au périmètre du code déployé : il examine la répartition des clés, les procédures de mise à jour et la gouvernance, autant d’éléments qui échappent aux outils d’analyse statique.

Pourquoi les ponts inter-chaînes concentrent-ils autant de pertes ?

Un pont immobilise des fonds sur une chaîne pour émettre leur équivalent sur une autre, ce qui crée un point de stockage unique et massif. Chainalysis relevait en août 2022 que les attaques sur les ponts représentaient 69 % des fonds volés depuis le début de l’année. La conception d’un pont sûr reste un problème technique non résolu.

La difficulté est structurelle, pas conjoncturelle. Le pont doit prouver qu’un événement s’est produit sur l’autre chaîne, alors même que les deux réseaux n’ont aucun moyen natif de se vérifier mutuellement. Chaque modèle proposé, du comité de signataires au client léger embarqué, déplace le compromis sans le supprimer.

Vitalik Buterin avait formulé cette limite avant la série d’incidents, dans une publication du 7 janvier 2022 sur le forum Reddit consacré à Ethereum, relayée le même jour sur son compte public.

Si Ethereum subit une attaque des 51 % et se réorganise, Arbitrum et Optimism se réorganisent aussi ; les applications inter-rollups qui conservent un état sur Arbitrum et Optimism restent donc cohérentes même en cas d’attaque des 51 % sur Ethereum. Et si Ethereum ne subit pas d’attaque des 51 %, il n’y a aucun moyen d’attaquer Arbitrum et Optimism séparément.

Vitalik Buterin, publication du 7 janvier 2022 sur le forum Reddit consacré à Ethereum

Son raisonnement distingue les couches qui héritent de la sécurité d’une chaîne des ponts reliant deux chaînes souveraines, qui n’héritent de rien. L’attaque contre le pont Horizon d’Harmony en juin 2022, chiffrée à 100 millions de dollars, puis celle contre Nomad deux mois plus tard lui ont donné raison plus vite que prévu.

Que couvre réellement un audit de contrat intelligent ?

Un audit standard couvre la revue du code source, la vérification des dépendances, le test des scénarios d’attaque connus et la rédaction d’un rapport hiérarchisant les découvertes par gravité. Il ne couvre ni les clés privées, ni les serveurs, ni les évolutions apportées après la remise du rapport. Cette délimitation explique une bonne part des incidents survenus sur des protocoles pourtant audités.

Le déroulé d’une mission suit généralement les mêmes étapes, quelle que soit la société retenue.

  • la définition du périmètre, qui fige les fichiers examinés et le commit exact concerné ;
  • la revue manuelle, phase la plus longue, menée par deux auditeurs travaillant en parallèle pour croiser les regards ;
  • l’outillage automatique, analyse statique et tests par entrées aléatoires, appliqué en complément et non en remplacement ;
  • la remise d’un rapport intermédiaire, suivie d’un aller-retour avec l’équipe de développement ;
  • la vérification des correctifs et la publication du rapport définitif.

La dernière étape est celle que l’on néglige le plus souvent. Un rapport qui liste douze vulnérabilités ne vaut rien si les correctifs n’ont pas été revérifiés, et il arrive qu’un correctif introduise lui-même une faille. La date du commit audité mérite d’être comparée à celle du déploiement avant de faire confiance à un badge d’audit affiché sur un site.

Ce qu’un audit ne garantit jamais

Un audit réduit le risque, il ne l’annule pas. Aucune méthode ne prouve l’absence de bug dans un système complexe, et les auditeurs les plus réputés ont signé des protocoles ultérieurement pillés. Le rapport est un instantané daté, pas une assurance.

Trois angles morts reviennent régulièrement. Le premier concerne la composabilité, un contrat sûr devenant dangereux une fois branché sur un autre. Le deuxième concerne la gouvernance, dont les mécanismes échappent souvent au périmètre contractuel examiné. Le troisième concerne l’exploitation courante, avec des clés mal conservées ou des accès administratifs partagés, sujet traité par les procédures de sécurisation d’un réseau plutôt que par la relecture de code.

Comment lire un rapport d’audit avant de déposer des fonds ?

Trois vérifications suffisent à écarter la majorité des faux signaux : le rapport est-il public et daté, le commit audité correspond-il au code effectivement déployé, et les vulnérabilités critiques ont-elles été corrigées puis revérifiées ? Un rapport non publié ne vaut rien, quelle que soit la réputation du cabinet cité.

Quelques signaux complémentaires méritent attention. Plusieurs audits indépendants sur le même code valent mieux qu’un seul, même prestigieux. Un programme de primes aux bugs actif et correctement doté indique une équipe qui accepte le regard extérieur en continu. À l’inverse, un protocole qui met en avant un audit vieux de dix-huit mois sur un code réécrit depuis communique sur un objet qui n’existe plus.

La méthode s’applique aussi aux applications décentralisées les plus modestes, dont les principes de relecture restent identiques à ceux des grands protocoles. La différence tient au budget consacré, pas à la nature des vérifications.

Un enjeu qui dépasse la qualité du code

Le secteur a longtemps traité la sécurité comme une case à cocher avant le lancement. Les montants perdus depuis 2021 ont déplacé le curseur : la surveillance continue, les primes aux bugs permanentes et les mécanismes de pause d’urgence deviennent des composants d’architecture, pas des ajouts de dernière minute. Cette professionnalisation coûte cher et ralentit la mise sur le marché, ce qui explique la résistance qu’elle rencontre encore.

Un déplacement plus intéressant s’opère du côté des utilisateurs. Savoir lire un rapport d’audit ou repérer une clé de mise à jour détenue par une adresse unique relève désormais de la diligence élémentaire, au même titre que la lecture d’un document d’information réglementé sur un placement classique. Ces réflexes se transposent d’un protocole à l’autre et ne se démodent pas.

Ce qui se joue derrière ces vérifications techniques est plus large que la sécurité d’un protocole particulier. Une infrastructure qui perd chaque année plusieurs milliards par défaut de conception peine à convaincre les investisseurs institutionnels, et donc à accéder aux capitaux qui financeraient sa maturité. La courbe des pertes est, à sa manière, un indicateur d’adoption.

Associé à : , , , ,


Vous appréciez cet article ?

Partagez-le avec vos proches Ajoutez-nous comme source préférée