Post-mortems · 6 min · démo interactive

Bybit : signer sans voir

L'écran montrait un transfert ordinaire. La signature autorisait tout autre chose. Rejoue l'écart entre ce qu'on voit et ce qu'on signe.

L’idée en une phrase

Les signataires de Bybit ont approuvé ce que l'interface leur montrait, alors que la donnée réellement signée était une autre, qui donnait le contrôle du coffre à l'attaquant.

Le contrat n'a pas été cassé et la cryptographie a tenu. Les signatures étaient valides. L'attaque s'est logée dans l'écart entre l'écran et la donnée, un endroit que le multisig ne protège pas. Un seuil de plusieurs signatures n'aide pas si tous les signataires regardent le même écran trompeur.

La démo

Ce que l'interface affiche

to 0xC0FFEE00…A1B2 (destinataire prévu) value 30 000 ETH (fictif) operation 0 (call) data 0x safeTxGas 0

Ce que l'appareil fait signer

Une empreinte à 64 caractères, sans aucun détail lisible.
–hash de ce qui est affiché
–hash de ce qui est signé
–slot 0 du coffre (logique)
–fonds du coffre

Compare les deux écrans, puis signe.

Sans JavaScript, compare deux champs. L'écran affiche operation = 0, un appel ordinaire, vers le destinataire prévu. La donnée signée contient operation = 1, un delegatecall vers le contrat de l'attaquant. Un chiffre change, et le sens de la transaction bascule. Les adresses et montants de cette démo sont inventés.

Intégrer cette démo

Copie ce code sur ton site, ton cours ou ton blog. La démo reste gratuite ; garde simplement le lien vers protocole.org.

Pourquoi ça compte

Le 21 février 2025, Bybit effectue un transfert courant d'ETH depuis un coffre multisig, un contrat Safe, vers un wallet chaud. Peu après, le coffre se vide. Plus de 400 000 ETH et dérivés partent vers des adresses de l'attaquant, soit environ 1,5 milliard de dollars selon le FBI. Une analyse de NCC Group compte 401 347 ETH.

Le 26 février 2025, le FBI publie un avis attribuant ce vol à la Corée du Nord, sous le nom d'activité « TraderTraitor », et demande de bloquer les transactions liées aux adresses listées.

Safe a indiqué que l'attaque avait commencé par la compromission du poste d'un de ses développeurs, ce qui a permis de proposer une transaction malveillante déguisée. Les enquêtes publiées par Sygnia et Verichains décrivent un fichier JavaScript modifié, servi aux utilisateurs de l'interface, et ciblant spécifiquement Bybit. Safe a précisé qu'une revue externe n'avait trouvé aucune faille dans ses contrats ni dans le code source de son interface : c'est le fichier distribué qui était altéré. Sygnia n'a trouvé aucune preuve de compromission de l'infrastructure de Bybit.

Le code

Ce script montre pourquoi une signature ne protège que ce qu'elle couvre, et comment un delegatecall peut réécrire le coffre. Remplace operation: 1 par operation: 0 dans signee et relance : le coffre reste intact.

Clique sur Lancer pour exécuter ce code dans ton navigateur.

Ce qui se passe vraiment

Lis les deux panneaux. À gauche, un transfert ordinaire. À droite, si l'appareil ne décode pas la transaction, une empreinte seule. C'est le blind signing, la signature à l'aveugle. Tu ne vérifies rien, tu confirmes une suite de caractères que personne ne sait lire de tête. Coche L'appareil de signature décode la transaction : l'écart apparaît aussitôt.

Clique sur Signer et exécuter avec le fichier compromis. La signature est parfaitement valide, car elle porte sur la donnée piégée. Le code de l'interface affichait la transaction attendue, remplaçait les données au moment de la signature, puis remettait l'original, comme le décrit l'analyse de NCC Group.

Pourquoi le seul changement d'operation est-il si grave ? Un call ordinaire exécute le code de la cible dans le stockage de la cible. Un delegatecall exécute le code de la cible dans le stockage de l'appelant. Le coffre Safe est un proxy : son emplacement de stockage 0 contient l'adresse de sa logique. Le contrat de l'attaquant a écrit dans ce slot. Regarde le chiffre « slot 0 » changer : le coffre garde sa place et ses fonds, mais obéit désormais à une autre logique.

Le champ data piégé commençait par le sélecteur de transfer(address,uint256), ce qui lui donnait l'apparence d'un transfert de token. Selon NCC Group, une transaction de janvier 2025 suivait déjà un schéma semblable, ce qui rendait l'opération moins suspecte.

Le bouton Recalculer le hash ailleurs illustre la parade : un outil indépendant de l'interface calcule le hash à partir des champs attendus, et l'écart saute aux yeux. La démo simplifie : un vrai Safe calcule un hash EIP-712 avec Keccak-256, et l'exécution exige plusieurs signataires. Ici, SHA-256 et un seul clic suffisent à montrer le principe.

Dans la vraie vie

Le point dur est que chaque maillon pris seul semblait sain. Le contrat Safe n'avait pas de faille connue exploitée ici. Les signataires ont produit eux-mêmes leurs signatures. Les signatures étaient mathématiquement correctes. La confiance reposait sur une page web, et un fichier JavaScript servi depuis un bucket cloud : selon Sygnia, il a été modifié deux jours avant le vol, puis remplacé par une version propre environ deux minutes après.

Un wallet matériel protège la clé, pas ton jugement. Il n'aide que si son écran montre le sens de l'opération et que quelqu'un le lit. Certains modèles et certaines configurations ne peuvent afficher qu'un hash : la vérification doit alors passer par un second chemin, indépendant de l'interface de signature.

Pour une organisation, cela se traduit par des règles simples. Décoder les transactions sur une machine séparée. Refuser tout delegatecall inattendu. Faire vérifier le hash par chaque signataire avec son propre outil. Le problème concerne aussi le particulier : le même écart est au cœur du phishing crypto, à une échelle plus modeste.

Selon les enquêtes, le code malveillant se déclenchait uniquement pour certaines adresses de Bybit et se comportait normalement ailleurs. D'après les enquêtes publiées ensuite, le poste du développeur a été compromis le 4 février 2025 par un projet Docker piégé, téléchargé à la suite d'une manœuvre d'ingénierie sociale. Les chiffres indiqués ici sont donc à lire avec leurs sources : FBI pour l'attribution et le montant global, Sygnia, Verichains et NCC Group pour le déroulé technique. Pour comparer, Ronin illustre l'autre façon de faire tomber un multisig : voler les clés, au lieu de tromper leurs détenteurs.

Ce qui peut mal tourner

  • Signer un hash illisible. Si l'appareil ne montre pas ce que fait l'opération, la signature repose entièrement sur l'écran de l'ordinateur.
  • Multiplier les signataires sans multiplier les écrans. Dix personnes devant la même interface partagent le même point de défaillance. L'indépendance des vérifications compte plus que leur nombre.
  • Faire confiance à un fichier parce que son code source est sain. Le code revu n'est pas forcément celui que reçoit le navigateur. Une chaîne de distribution compromise échappe à l'audit du code.
  • Ignorer operation. Un delegatecall vers une adresse inattendue doit bloquer la signature, quel que soit le reste.
  • Cibler un seul client. Un code qui ne s'active que pour une victime précise passe inaperçu chez tous les autres utilisateurs, et les tests publics ne voient rien.
  • Accorder un accès large à un poste de développeur. Le poste devient une porte vers la production. Des droits limités et une séparation des accès réduisent ce que cette intrusion peut atteindre.

Teste-toi

1. Dans quel cas la signature était-elle invalide ?
2. Que fait un delegatecall ?
3. Quelle pratique aurait détecté l'écart ?