Vulnérabilité du wallet matériel Coldcard entraîne le vol de plus de 88 millions de dollars en bitcoin

iconMetaEra
Partager
AI summary iconRésumé
Une faille du portefeuille matériel Coldcard liée à un RNG mal configuré a entraîné le vol de plus de 594 BTC, évalués à plus de 88 millions de dollars. Le problème a touché les modèles Coldcard Mk2, Mk3, Mk4, Q et Mk5, exposant les clés privées à des attaques par force brute. Beosin a suivi les fonds regroupés vers plusieurs adresses Bitcoin. Cet incident soulève des préoccupations au titre de la CFT et met en lumière l'urgence de se conformer au MiCA alors que l'UE renforce sa réglementation sur les crypto-monnaies.

Pertes dépassant 88 millions de dollars américains : Analyse de la vulnérabilité du portefeuille matériel Coldcard et traçage des fonds volés Le 31 juillet, environ 500 portefeuilles matériels Coldcard ont été piratés, entraînant le vol de 594 bitcoins, d’une valeur d’environ 38 millions de dollars américains. Par la suite, Coinkite, l’entreprise chargée de la production des portefeuilles Coldcard, a confirmé l’existence d’une vulnérabilité de sécurité dans le processus de génération des clés, affectant plusieurs générations de produits, notamment les Coldcard Mk2, Mk3, Mk4, Q et Mk5.

Actuellement, les pertes causées par cette exploitation de vulnérabilité dépassent 88 millions de dollars américains, et l'attaque est toujours en cours. Les utilisateurs de portefeuilles Coldcard doivent transférer leurs fonds vers d'autres adresses dès que possible. Voici l'analyse de Beosin sur cette vulnérabilité ainsi que les informations sur le suivi des fonds volés.

I. Analyse de la vulnérabilité

En analysant les historiques de commits du firmware Coldcard, on peut constater que, dans le commit précédent 37e4af5451c260c1e7d429fe8972c4cb5e68ee59, l'équipe de développement a mis à jour plusieurs éléments de code liés à la configuration MK4, incluant dans mpconfigboard.h :

// Nous avons notre propre version de ce code. #define MICROPY_HW_ENABLE_RNG (0)

Sur la plateforme MicroPython STM32, cette macro contrôle le chemin de compilation pour le générateur aléatoire matériel (RNG) par défaut et l'implémentation aléatoire générique. La définir à 0 empêche le chemin RNG matériel par défaut d'être utilisé comme backend pour rng_get().

Ses remarques indiquent que le développeur implémentera lui-même le RNG ; en examinant le fichier rng.h personnalisé, on constate qu'il ne déclare que deux objets MicroPython :

MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj);MP_DECLARE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj);

L'implémentation correspondante est :

/// \function pyb_rng_get()///// Retourne un nombre aléatoire généré par le matériel sur 30 bits : ou échoue !//STATIC mp_obj_t pyb_rng_get(void){    // Récupère et retourne le nouveau nombre aléatoire    return mp_obj_new_int(rng_get_or_fault() >> 2);}
/// \function rng_get_bytes()/// Remplit un tampon avec des bits aléatoires ; l'appelant doit fournir un tampon de taille adaptée.STATIC mp_obj_t pyb_rng_get_bytes(mp_obj_t buffer_io) {
    mp_buffer_info_t bufinfo;    mp_get_buffer_raise(buffer_io, &bufinfo, MP_BUFFER_WRITE);
    mp_uint_t count = bufinfo.len;    if(count < 1) {        mp_raise_ValueError(NULL);    }
    // Lit des mots de 32 bits et les décompose dans le tampon fourni    random_buffer(bufinfo.buf, count);
    return mp_const_none;}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);MP_DEFINE_CONST_FUN_OBJ_1(pyb_rng_get_bytes_obj, pyb_rng_get_bytes);

rng_get_or_fault() lit directement le périphérique RNG STM32 :

static uint32_t rng_get_or_fault(void){    // Activer le périphérique RNG s'il n'est pas déjà activé    rng_init();
    // Attendre que le nouveau nombre aléatoire soit prêt, environ 10 µs    uint32_t start = HAL_GetTick();
    while (!(RNG->SR & RNG_SR_DRDY)) {        if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) {            // défaillance matérielle... ne rien retourner !            mp_raise_OSError(MP_EFAULT);        }    }
    // Récupérer et retourner le nouveau nombre aléatoire    last_value = RNG->DR;
    return last_value;}

Cela indique que le code personnalisé de Coldcard souhaite effectivement utiliser le RNG matériel, mais il ne garantit l'utilisation de cette fonction matérielle que lors de l'appel de pyb_rng_get* ou de son internal random_buffer().

Lors de la création du portefeuille, le code suivant est effectivement appelé, où la fonction de création de portefeuille dans shared/seed.py est :

async def make_new_wallet(nwords):    # Choisir une nouvelle graine aléatoire.    await ux_dramatic_pause('Génération...', 3)    seed = generate_seed()    words = await approve_word_list(seed, nwords)    if words:        await commit_new_words(words)

Cet appel entre d'abord dans le module shared/random.py de Coldcard. Dans les versions précédentes, random.py dépendait explicitement de ngu.random et conservait :

# random.py - sous-ensemble du module random, sans compatibilité, utilisant un GNR de qualité cryptographique  
# pour les octets, utilisez ngu.random.byte(len)  
# bytes = ngu.random.bytes

Le wallet est initialisé à l'aide de random.bytes, et non de pyb.rng(), et pyb_rng_get_obj personnalisé ne remplace pas automatiquement random.bytes.

Étant donné que MICROPY_HW_ENABLE_RNG est défini sur 0, le générateur de portefeuille n'utilise pas de RNG matériel, mais appelle pyb_rng_yasmarang depuis micropython/ports/stm32/rng.c :

#if MICROPY_HW_ENABLE_RNG
uint32_t rng_get(void) {    // utilise le générateur matériel RNG STM32    ...}
#else
// Pour les microcontrôleurs ne disposant pas de RNG, nous devons quand même fournir une fonction rng_get()// Un générateur pseudo-aléatoire n'est pas idéal, mais nous l'adoptons pour l'instant.
// Générateur de nombres aléatoires Yasmarangstatic uint32_t pyb_rng_yasmarang(void) {    static bool seeded = false;    static uint32_t pad = 0, n = 0;    ...}
uint32_t rng_get(void) {    return pyb_rng_yasmarang();}
#endif

pyb_rng_yasmarang est un générateur de nombres pseudo-aléatoires et est extrêmement peu sécurisé pour la génération de semences de portefeuille matériel ; un attaquant peut obtenir la clé par force brute. Coinkite a désormais explicitement exclu stm32/rng.c dans le fichier makefile :

# Ne compilez pas le PRNG de secours de MicroPython. Le fichier rng.c spécifique à la carte
# fournit rng_get(), et cet objet vide satisfait la liste d'objets amont.
$(BUILD)/rng.o: CFLAGS += -Dpyb_rng_yasmarang=error-do-not-want-this
$(BUILD)/rng.o:
$(ECHO) "SKIP stm32/rng.c"
$(Q)$(CC) $(CFLAGS) -x c -c /dev/null -o $@

Deuxième partie : Suivi des fonds volés

Actuellement, les fonds de plusieurs portefeuilles victimes ont été transférés et regroupés dans plusieurs adresses, sans être encore nettoyés. Grâce à des renseignements sur les menaces et une analyse des comportements sur la chaîne, Beosin Trace a détecté les adresses de regroupement suivantes :

bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r (562 BTC)

https://wdcdn.qpic.cn/MTMxMDI3MDE1MTgxMDU0NzA_369595_usmImxZpHsKmu9X__1785899827?w=1080&h=656

bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3 (398,47 BTC)

https://wdcdn.qpic.cn/MTMxMDI3MDE1MTgxMDU0NzA_304781_-IeWjFtIQ4RhvCbz_1785899827?w=1080&h=674

De plus, les adresses de regroupement suivantes présentent un schéma de flux de fonds similaire à celui ci-dessus et n'ont pas encore effectué de transferts supplémentaires :

  • bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q (89,62 BTC)
  • bc1q0rvn88w08j75k4h48lf9fvhan7unjp7vjf5q6m (64,9 BTC)
  • bc1qtfrwa4j6rmj9rsgspv6a0yjumkg39js2numu75 (45,9 BTC)
  • bc1qmd5m5ktv7m5ffujxv4248fxv36myvdx79n8jp6 (30,18 BTC)

Les attaques contre le portefeuille Coldcard se poursuivent, et l'équipe Beosin surveille en continu d'autres adresses de regroupement et analyse les flux de fonds associés.

III. Conclusion

Cet important incident de sécurité sur le portefeuille matériel Coldcard provient d'une erreur d'implémentation par l'équipe de développement concernant la génération de nombres aléatoires, ayant utilisé un générateur de nombres pseudo-aléatoires lors de la création cruciale de la graine du portefeuille. L'équipe de développement doit effectuer des tests et des audits continus et complets du code, tandis que les utilisateurs de Coldcard doivent transférer leurs actifs au plus vite et rester attentifs aux annonces de sécurité à venir de Coinkite.

Beosin est une entreprise leader en matière de sécurité blockchain et de conformité réglementaire, spécialisée dans l'audit de sécurité des contrats intelligents avant le lancement de projets, la surveillance et la blocage des risques sécuritaires pendant leur fonctionnement, le recouvrement d'actifs volés, la lutte contre le blanchiment d'argent (AML) pour les actifs virtuels, ainsi que l'enquête et le suivi. Beosin fournit des produits de conformité blockchain « tout-en-un » et des services de sécurité à plus de 200 fournisseurs d'actifs virtuels, ainsi qu'à 4 500 projets Web3, dans plus de 20 pays et régions à travers le monde.

Clause de non-responsabilité : les informations sur cette page peuvent avoir été obtenues auprès de tiers et ne reflètent pas nécessairement les points de vue ou opinions de KuCoin. Ce contenu est fourni à titre informatif uniquement, sans aucune représentation ou garantie d’aucune sorte, et ne doit pas être interprété comme un conseil en investissement. KuCoin ne sera pas responsable des erreurs ou omissions, ni des résultats résultant de l’utilisation de ces informations. Les investissements dans les actifs numériques peuvent être risqués. Veuillez évaluer soigneusement les risques d’un produit et votre tolérance au risque en fonction de votre propre situation financière. Pour plus d’informations, veuillez consulter nos conditions d’utilisation et divulgation des risques.