J’ai signalé de manière responsable à SatoshiLabs le problème décrit ci-dessous le 1er octobre 2019. Ils ont publié un correctif dans la version 2.1.8 du firmware le 6 novembre 2019. SatoshiLabs a fait preuve d’une grande coopération et a communiqué très clairement avec moi.

SatoshiLabs a publié le problème sur sa page sécurité, a invité ses utilisateurs à mettre à niveau leur appareil, en a parlé sur Twitter pour les y encourager, et a rédigé un article de blog à ce sujet.

Je suis ravi qu’ils aient versé une généreuse prime de bug bounty 😍.

Le Trezor Model T est le successeur du Trezor One. Comme pour beaucoup de passionnés de Bitcoin, Trezor a été mon premier portefeuille matériel, et je suis reconnaissant envers SatoshiLabs d’avoir inventé et publié de nombreux standards de l’industrie encore utilisés aujourd’hui, ainsi que d’avoir créé le tout premier portefeuille matériel commercial. ❤

J’ai mené l’attaque avec succès en modifiant de façon interactive des transactions dans Electrum, sur Bitcoin Testnet.

Le Trezor One n’était pas affecté.

Préface

En réfléchissant à la manière d’implémenter de façon sécurisée la prise en charge du multi-signature sur le portefeuille matériel BitBox02, mes collègues Kaspar Etter et Sebastian Küng chez Shift Cryptosecurity m’ont mis en garde contre différents problèmes potentiels. Kaspar m’a alerté sur des problèmes possibles autour de la vérification des co-signataires multisig (il publiera bientôt un article à ce sujet). Sebastian m’a aiguillé en soulignant que des problèmes de vérification multisig pourraient aussi affecter la vérification singlesig, si le code de vérification ne les sépare pas clairement. En combinant leurs conseils et en examinant le code multisig d’autres fabricants de portefeuilles matériels, j’ai remarqué un bug exploitable dans le Trezor Model T.

Une transaction Bitcoin est composée d’entrées et de sorties.

Les entrées définissent quelles pièces seront dépensées, et les sorties définissent où vous envoyez vos pièces.

Chaque fois que vous recevez des fonds sur une adresse Bitcoin, une sortie de transaction non dépensée (unspent transaction output, ou UTXO) est créée.

Supposons que vous ayez reçu 0.3 BTC et 0.5 BTC dans votre portefeuille. Vous contrôlez alors ces deux UTXO. Le solde de votre compte est la somme des UTXO, soit 0.8 BTC dans ce cas. Les portefeuilles matériels et logiciels n’affichent généralement pas ces détails et gèrent vos pièces en arrière-plan.

Si vous voulez envoyer par exemple 0.7 BTC à l’adresse d’un destinataire, votre portefeuille créera une transaction contenant deux entrées et deux sorties. 0.7 BTC vont au destinataire, 0.1 BTC correspondent au change et retournent dans votre propre portefeuille.

La sortie de change est une sortie spéciale qui renvoie le change vers votre portefeuille. Sans elle, votre portefeuille déduirait 0.8 BTC (la somme des entrées) au lieu de 0.7 BTC de votre solde. Dans tous les cas, tous les UTXO utilisés comme entrées d’une transaction sont détruits lorsque la transaction est minée dans la blockchain. La différence entre les entrées et les sorties correspond aux frais de transaction collectés par les mineurs.

Multi-signature

Les concepts ci-dessus s’appliquent de la même façon aux comptes multi-signature. Si vous aviez une configuration multisig 2-sur-3, la transaction devrait alors être signée par deux co-signataires sur trois, la sortie de change retournant généralement vers le même compte multisig 2-sur-3.

Notez que chaque entrée est configurée individuellement comme entrée singlesig ou multisig.

Vérification du change dans les portefeuilles matériels

Lorsque vous signez une transaction sur votre portefeuille matériel, il vous est demandé de vérifier les détails de la transaction. Le plus souvent, cela signifie l’adresse du destinataire et le montant que vous souhaitez envoyer, ainsi que les frais de transaction.

Le portefeuille matériel vous demande de vérifier ces détails parce qu’on part du principe que le logiciel de portefeuille sur votre ordinateur (ou téléphone mobile) ne peut pas être considéré comme fiable, car il peut être compromis par un logiciel malveillant et afficher de fausses informations dans son interface utilisateur.

En particulier, la sortie de change n’est généralement pas affichée pour vérification par l’utilisateur. Le portefeuille matériel, du moins en théorie, sait qu’il pourra la dépenser à nouveau plus tard. Sinon, la sortie de change serait montrée à l’utilisateur pour vérification. Certains portefeuilles, comme le BitBox02, rejettent complètement la transaction dans ce cas, tandis que d’autres, comme le Trezor, affichent à l’utilisateur l’adresse et le montant de la sortie de change pour vérification. En outre, un utilisateur ne peut pas vérifier facilement l’adresse de change. C’est différent pour l’adresse du destinataire et le montant, que l’utilisateur peut confirmer avec le destinataire hors bande, par exemple en l’appelant au téléphone.

Exploitation d’un bug de vérification du change dans le Trezor Model T

L’idée de base est la suivante : une application de portefeuille malveillante peut essayer de remplacer la sortie de change de votre transaction par une sortie de change multisig 1-sur-2, où l’un des co-signataires est vous-même (ou plutôt votre Trezor) et l’autre co-signataire est l’attaquant. En envoyant le change vers cette sortie, l’attaquant peut immédiatement transférer les fonds vers un portefeuille qu’il contrôle exclusivement. L’attaquant peut le faire sans la coopération de l’utilisateur, car dans une configuration multisig 1-sur-2, une seule des deux signatures participantes est nécessaire, pas les deux.

Parmi les règles pertinentes que Trezor utilise pour déterminer s’il faut accepter une sortie de change, on trouve les deux suivantes :

Ces deux vérifications reposent sur une même idée : si vous avez déjà reçu des fonds auparavant et que vous êtes capable de les dépenser en les utilisant comme entrées, alors cela restera possible plus tard lorsque vous dépenserez le change, puisque celui-ci retourne vers le même compte.

Contourner la première vérification pour cette attaque est simple : l’attaquant peut tout simplement utiliser le même préfixe de keypath pour sa sortie de change malveillante.

La seconde vérification est pertinente, mais elle comportait un bug : Trezor vérifiait qu’une sortie de change multisig avait la même configuration que toutes les entrées multisig, mais il ne vérifiait pas en plus que toutes les entrées étaient du même type. Par conséquent, le change d’une transaction qui contenait à la fois des entrées singlesig et des entrées multisig était accepté, tant que toutes les entrées multisig avaient la même configuration que la sortie de change.

Il suffisait alors à l’attaquant d’injecter une entrée multisig 1-sur-2 supplémentaire, et la sortie de change malveillante passait toutes les vérifications et était acceptée silencieusement.

Remarque : ajouter une entrée modifie les frais de transaction. Les frais « attendus » précédents peuvent être rétablis en ajustant la valeur du change en conséquence, de sorte que même des utilisateurs très attentifs ne remarqueront rien d’anormal.

Exemple

Un exemple détaillé suit.

Supposons qu’un utilisateur dépense une entrée de 10 BTC : 1 BTC vers le destinataire prévu, 8.99 BTC vers une sortie de change (ce qui donne des frais de 0.01 BTC).

Un portefeuille non malveillant créerait la transaction suivante :

Le logiciel de portefeuille malveillant prend la transaction et ajoute une entrée multisig 1-sur-2 :

  • La première clé est la même que la clé du compte singlesig de l’utilisateur.
  • La seconde clé est contrôlée par l’attaquant.

L’entrée multisig (UTXO) est préparée on-chain par l’attaquant et contient un petit montant arbitraire, par exemple 0.0001 BTC.

Le portefeuille remplace également la sortie de change de 8.99 BTC par une sortie de change multisig ayant la même configuration multisig.

La valeur du change est ajustée pour que les frais restent identiques : change.value = originalChange.value + multisigInput.value. Le keypath est choisi de sorte qu’il ait le même préfixe que les keypaths des entrées.

La transaction malveillante ressemble alors à ceci :

L’ensemble est envoyé au Trezor pour signature.

  • Le destinataire prévu (1 BTC, adresse) est confirmé.
  • Les frais sont confirmés.
  • La nouvelle sortie de change n’est pas affichée à l’utilisateur pour vérification, car elle passe le contrôle output_is_change : multifp est basé sur l’entrée multisig ajoutée, qui correspond à la sortie de change multisig.

Le Trezor renvoie les deux signatures (une par entrée). Le portefeuille peut diffuser la transaction modifiée, ce qui aboutit à une garde partagée du change de 8.9901 BTC.

L’attaquant utilise rapidement sa clé pour déplacer les fonds vers un portefeuille qu’il est le seul à contrôler.

L’attaquant a ainsi volé avec succès 8.99 BTC (et récupéré son paiement initial de 0.0001 BTC).

Bien sûr, le portefeuille malveillant n’afficherait pas à l’utilisateur l’entrée malveillante ni le change malveillant, mais présenterait les détails de la transaction comme si elle avait été créée par le portefeuille d’origine, de sorte que l’utilisateur ne puisse détecter aucune divergence.

Impact

L’attaquant n’est pas seulement capable de voler le change d’une transaction normale, mais aussi de voler tous les fonds restants dans le même compte après que l’utilisateur a confirmé une seule transaction single-sig. Pour cela, il ajoute tous les UTXO du compte à la transaction au lieu du sous-ensemble normalement choisi.

Une fois que l’attaquant a compromis l’ordinateur ou le téléphone mobile de l’utilisateur, l’attaque est facile à exécuter, avec un rendement attendu élevé. Un portefeuille malveillant ou falsifié se comporterait exactement comme l’original, sauf lorsqu’il exécute l’attaque, qui reste invisible pour l’utilisateur.

De plus, même si le montant du change serait perdu au profit de l’attaquant, le portefeuille peut tout de même afficher le solde attendu comme si de rien n’était, retardant le moment où l’utilisateur remarquera le vol.

L’attaquant doit générer à l’avance une sortie multisig par utilisateur visé, avec cet utilisateur comme co-signataire. Il existe plusieurs manières d’y parvenir, par exemple en faisant communiquer le portefeuille malveillant avec son serveur, ou en installant le portefeuille malveillant avec une clé privée préchargée afin qu’il puisse créer lui-même une telle sortie.

L’attaquant peut aussi concevoir des heuristiques pour maximiser son gain, par exemple en n’exécutant l’attaque que si le compte contient une grande quantité de pièces, ou en ne ciblant que les utilisateurs peu susceptibles de remarquer rapidement le vol. Dans ce cas, davantage d’utilisateurs peuvent être attaqués avant que le problème ne soit connu et corrigé.

Ce qui rend cette attaque intéressante, c’est que les exploitations laissent une trace sur la blockchain publique sous la forme d’un motif particulier : des transactions avec à la fois des entrées singlesig et multisig, et une sortie de change ayant la même configuration M-sur-N, qui est dépensée immédiatement après.

Une autre observation intéressante est que l’attaquant pourrait aussi utiliser une entrée et un change en 2-sur-3, de sorte que l’utilisateur n’ait jamais la possibilité de dépenser le change, alors que dans le cas du change 1-sur-2, l’attaquant doit transférer le change immédiatement. Cela se fait en envoyant la transaction modifiée à l’attaquant pour signature, au lieu de la diffuser directement.

Enseignements

Je pense que ce problème est intéressant, car il met en évidence des limites présentes dans presque tous les portefeuilles matériels, y compris le BitBox02, ainsi que des pistes d’amélioration.

Je souhaite mentionner quelques extensions possibles aux portefeuilles matériels qui auraient pu atténuer à la fois ce problème et le problème de validation de keypath découvert récemment sur le ColdCard. Les idées suivantes proviennent de discussions internes et restent encore assez vagues, donc j’ai hâte d’en comprendre les compromis et de voir s’il est pertinent d’implémenter ces extensions.

Avec une approche de défense en profondeur, des problèmes comme celui-ci pourraient être atténués.

1. Enregistrer la configuration du compte sur l’appareil avec vérification par l’utilisateur

Avant que l’utilisateur puisse recevoir sur une adresse d’un certain compte, il devrait d’abord activer/enregistrer le compte en confirmant tous les détails pertinents :

  • dans un compte single-sig, vérifier par exemple "Bitcoin: Segwit, compte n°2"
  • dans un compte multi-sig, vérifier le type, ainsi que la configuration M-sur-N et tous les xpubs des co-signataires.

Idéalement, l’utilisateur devrait pouvoir choisir un nom pour le compte afin de reconnaître facilement sur quel compte il opère.

Lors de la confirmation d’une adresse de réception ou d’une transaction, l’appareil afficherait le nom choisi par l’utilisateur et vérifierait que tous les détails correspondent (toutes les entrées et tous les changes correspondent à la configuration du compte enregistrée, etc.).

Cela atténuerait toutes sortes de problèmes accidentels et réduirait la dépendance à des heuristiques de validation susceptibles d’échouer, en particulier lors de la validation des adresses de réception et de change.

Le ColdCard fait quelque chose de similaire avec ses comptes multisig, ce qui était très appréciable à voir.

2. Le mode de signature « tout vérifier »

Ce mode s’adresserait aux utilisateurs experts, familiers avec les concepts d’entrées et de sorties de transaction, de types de script et de change.

Comme décrit plus haut, le nombre d’éléments d’une transaction réellement vérifiés par l’utilisateur est généralement assez limité :

  • adresse du destinataire et montant (plusieurs occurrences possibles)
  • frais de transaction
  • LockTime, si pris en charge et défini.

Ce qui n’est pas affiché pour vérification, mais pourrait l’être :

  • type de compte : (Native) Segwit Pay-To-PubkeyHash, multisig avec configuration M-sur-N et tous les xpubs des co-signataires, etc.
  • nombre d’entrées, nombre de sorties.
  • toutes les entrées : hash de la transaction précédente et index de sortie, montant, séquence, keypath, type de script (doit correspondre au type de compte)
  • toutes les sorties de change : adresse, montant, keypath, type de script (doit correspondre au type de compte), marquées comme change
  • autre chose ?

Les utilisateurs experts qui activeraient ce mode pourraient repérer tout élément suspect, comme une entrée ou un change déplacé, ou un keypath inhabituel utilisé dans des attaques par rançon, ce qui atténuerait une catégorie d’exploits reposant sur une validation absente ou défaillante.

3. Davantage d’avertissements sur les transactions inhabituelles

L’ensemble des transactions possibles est bien plus vaste que l’ensemble des transactions qu’un utilisateur ou un portefeuille Bitcoin typique crée en pratique. Les portefeuilles matériels pourraient mieux avertir en cas de comportement inhabituel et, si possible, préférer rejeter la transaction plutôt que de laisser l’utilisateur vérifier manuellement le cas limite.

Exemples :

  • Avertir en cas de frais anormalement élevés (fait par Trezor, absent du BitBox02 en novembre 2019).
  • Avertir ou rejeter les keypaths non standard, par exemple ne pas autoriser l’utilisation d’un keypath destiné aux entrées/changes single-sig dans des entrées/changes multi-sig (purpose BIP44), ou le mauvais coin BIP44. Le BitBox02 applique déjà cette règle.
  • Avertir s’il y a plus d’entrées que nécessaire pour couvrir le montant du destinataire et les frais. À ma connaissance, aucun portefeuille matériel n’implémente cela. Cela empêcherait l’escalade des attaques basées sur des changes malveillants, de sorte que l’attaquant ne puisse pas voler ou prendre en rançon tous les fonds de l’utilisateur d’un seul coup. Même s’il existe des raisons valables d’inclure des entrées inutiles, comme l’amélioration de la confidentialité, cela reste peu courant aujourd’hui, donc un avertissement pourrait être affiché.

Shift Crypto est une société privée basée à Zurich, en Suisse. Notre équipe internationale de spécialistes en ingénierie, en cryptosécurité et en développement Bitcoin core conçoit les produits BitBox et fournit des services de conseil. Le BitBox02, portefeuille matériel de deuxième génération, permet aux particuliers de stocker, protéger et utiliser facilement des cryptomonnaies. Son compagnon, BitBoxApp, fournit une solution tout-en-un pour gérer vos actifs numériques en toute sécurité et en toute simplicité.

Publié à l’origine sur https://benma.github.io le 18 novembre 2019.

This post was translated with the help of AI