Le 19 juillet un bug a été exploité dans le contrat multisig que permet de déployer le client Parity v1.5. Au total 83 017 éthers ont été subtilisés, ces fonds avaient été initialement collectés par Edgeless Casino, Swarm City, et æternity lors de leurs ICOs respectives. Cet article revient sur le fonctionnement de l’attaque et les réactions de la communauté.

 

Multisig: un contrat pour partager le contrôle de ses éthers

Les wallets de multisig existent longtemps sur bitcoin, le principe général est de partager entre plusieurs clés le contrôle d’une adresse et donc des bitcoins qui y pointent. On parle alors de signatures M-of-N, ou M-sur-N en français, pour exprimer le fait qu’il faille la signature de M clés sur les N clés qui se partagent le contrôle pour que la transaction émanant de l’adresse multisig soit valide.

Sur Ethereum les wallet multisig prennent la forme de contrats avec leur logique et fonctionnalités propres. Parmi les implémentations les plus populaires on trouve celle de Gnosis avec son interface web et celui maintenu par la Fondation Ethereum dont l’auteur n’est autre que Gavin Wood – fondateur et CTO de Parity technologies.

 

Le multisig de Parity, un contrat de qualité mais mal déployé

Le client Parity possède une interface graphique pour générer un Multisig:

Parity Multisig.png

L’interface graphique de création de Multisig sur Parity

Cette interface permet de déployer facilement un contrat de multisig paramétré qui comportait une vulnérabilité importante dans sa version 1.5 de Parity.

Dans cette version le multisig s’initialise au déploiement en faisant appel à un autre contrat déjà déployé, la librairie « WalletLibrary ». A la ligne 395, le contrat Wallet commence avec la description de son constructor, cette fonction porte le nom du contrat et ne s’exécute qu’une seule fois lors du déploiement. Regardons cette fonction de plus près.

En premier lieu, on passe au constructor les paramètres du futur multisig, à savoir la listes des propriétaires, le nombre d’avis positifs de propriétaires nécessaires à l’exécution d’une transaction et la limite de transactions par jour.

En second lieu, le constructor prépare un appel à « WalletLibrary » avec les paramètres indiqués supra. Cette partie du code est très optimisée et se termine en assembleur par l’appel en lui-même delegatecall ligne 417.

Enfin, la conséquence de ce delegatecall est d’exécuter « initWallet » (ligne 216) qui termine d’initialiser le multisig.

Simple non? Le déploiement de ce multisig est très peu coûteux car il se sert d’une librairie pour externaliser son initialisation et ne contient aucune méthode superflue. En effet, si une transaction vers le multisig contient du code, le traitement de ce code est externalisé vers la librairie (cf.ligne 428)! Au final le multisig est près de 70% moins cher à déployer.

[Alerte Spoiler, le bug exploité est révélé après cette image]

DCEGihXW0AAvWvn.jpg

What could possibly go wrong?

Que se passe-t-il si quelqu’un envoie au contrat Multisig une transaction contenant des données d’initialisation avec un nouveau et unique propriétaire? Le contrat exécute un delegatecall vers la librairie qui exécute initWallet avec les paramètres reçus, tout simplement. La liste des propriétaires est ni plus ni moins mise à jour! Il ne reste plus qu’à envoyer une transaction ordonnant le transfert des fonds.

Le 18 juillet au bloc 4041179,  une première transaction exploitant ce bug est lancée sur un contrat multisig, puis deux autres contrats sont compromis aux blocs 4043791 et 4043802. Au total, 153 037 ETH ont été détournés des Multisig de æternity, Edgeless Casino, et Swarm City par ce  compte.

Hasard ou coïncidence, les 3 compagnies concernées arborent un signe infini dans leur logo tandis que 596 Multisigs étaient vulnérables.

 

La réaction de la communauté

Au bloc 4044981, soit un peu moins de 5 heures après la dernière transaction de l’attaquant, un groupe de White Hat Hackers a pris l’initiative de vider les autres contrats buggés. Ce groupe a par la suite redéployé des contrats mis à jour de multisig avec les paramètres initiaux et les fonds prélevés

Question en suspens, pourquoi n’avoir attaqué que ces 3 contrats ? En effet, les autres comptes vulnérables possédaient près de 78 million de dollars en tokens et plus de 377,105 ETH. Aversion particulière pour le signe ∞ ? Peur d’une fork ? Le mystère reste entier.

 

Comment cette attaque aurait pu être évitée

L’utilisation des librairies n’est pas à écarter, bien au contraire. Outre le fait qu’elles permettent d’économiser le coût de stockage dans la blockchain, elles viennent aussi avec leur lot de tests, de standardisation et d’optimisation. Le problème ici est d’éviter que l’initialisation soit invoquée postérieurement au déploiement. On peut citer au moins deux approches pour éviter cela:

  • retirer la fonction initWallet de la librairie pour l’intégrer dans le contrat Wallet sans oublier de lui ajouter un modifier internal;
  • ajouter un modifier rejetant les transactions en direction du Wallet qui invoquent initWallet (solution choisie par Parity Technologies).
Jacopo da Pontormo - Portrait de deux amis 1524

Jacopo da Pontormo – Portrait de deux amis 1524

 

Protéger ses fonds en Multisig

Si vous cherchez des ressources en anglais sur ce bug, je vous recommande de cliquer ici, , par ici et par là. Si vous souhaitez participer à la sécurisation d’un contrat multisig il y a actuellement une bounty ouvert pour des contributions sur celui-ci. Dérivé de Gnosis, ce dernier simplifie beaucoup le fonctionnement et prévoit un mode récupération après une période d’inactivité des autres signataires.

Au-delà des différents contrats Multisig évoqués supra, on peut citer la solution entreprise proposée récemment par Ledger, la startup française spécialisé dans les hardware wallets. Cette dernière a développé Ledger Vault un produit modulable qui permet de faire du Multisig directement en hardware.