Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
ch55x_firmware_extractor — Extracteur de firmware pour microprocesseurs CH55x | Kitploit
Outils/GitHubGitHub/finngineering/ch55x_firmware_extractor
Sécurité des Systèmes EmbarquésExploitationRétro-ingénierieHacking MatérielSécurité MatérielleSécurité Matériel et IoTAnalyse de Micrologiciel
GitHubfinngineering/ch55x_firmware_extractor

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

ch55x_firmware_extractor

Extracteur de firmware pour microprocesseurs CH55x

Voir le dépôt
12il y a 8 moisPas encore vérifié

Extracteur de firmware CH55x

L'extracteur de firmware CH55x est utilisé pour lire le firmware des circuits intégrés CH55x. Il n'existe pas de support intégré dans les appareils pour lire directement le firmware via le bootloader. Cependant, il existe une fonctionnalité permettant de vérifier le contenu du firmware 8 octets à la fois par rapport à des données fournies. Cette fonctionnalité est vulnérable à une attaque temporelle classique et c'est ce qui est exploité ici pour permettre l'extraction du firmware de ces appareils. Le bootloader peut être accessible via USB ou UART. Cet extracteur de firmware ne fonctionne que via UART, car la latence plus élevée de l'USB rendrait cette attaque difficile. Les puces testées sont CH552 et CH554, et les versions de bootloader 2.4 et 2.5. La solution matérielle pour l'extracteur de firmware est basée sur un STM32 Blue Pill, car ceux-ci sont facilement disponibles, bon marché et offrent les performances nécessaires.

Anatomie de l'exploit

Le bootloader a déjà été lu depuis l'appareil et son protocole de communication a été rétro-conçu. Ci-dessous se trouve une commande de vérification approximativement correcte et la fonction de vérification utilisée dans le bootloader. Certaines protections sont en place, qui exigent que la longueur soit un multiple de 8, que l'adresse soit alignée sur une limite de 8 octets, que l'adresse soit inférieure à 0x3800 et qu'il n'y ait pas d'erreurs de vérification antérieures. La dernière protection signifie qu'un redémarrage du CH55x est nécessaire après chaque vérification infructueuse.

Nous pouvons voir que la fonction de vérification retourne immédiatement lorsqu'un octet de la vérification échoue. Cela signifie que plus le nombre d'octets corrects est élevé, plus la fonction de vérification prendra de temps. C'est l'exemple classique d'une attaque temporelle qui peut être exploitée.

root@kitploit:~
unsigned char verifycmd[] = {
//  0x57, 0xab, // UART magic not included to verify function
    0xa6,       // Verify command
    5 + len,    // Constant 5 plus length of data to verify
    0,          // Unused
    addr_low,   // Low byte of address
    addr_high,  // High byte of address
    0, 0, 0,    // Unused
    0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, // Data to verify against
    checksum
}

unsigned char verify(unsignec char *cmdbuffer)
{
    static char prev_verify_error;

    unsigned char len = cmdbuffer[1]-5
    unsigned short addr = cmdbuffer[3] + cmdbuffer[4] << 8;
    if (len & 0x07 || addr & 0x07 || addr > 0x3800 || prev_verify_error) {
        return 0xfe;
    }

    for (int i=0; i < len; i++) {
        // Key can be set through bootloader, and CBYTE[] means code memory
        if(key[i & 0x07] ^ cmdbuffer[8+i] ^ CBYTE[addr+i]) {
            prev_verify_error = 1;
            return 0xf5;
        }
    }
    return 0;
}

Par essais et erreurs, nous avons constaté que chaque octet correct prolonge le temps d'exécution de la fonction de vérification d'environ 4,2 µs. Le débit en bauds utilisé par le bootloader pour la communication UART est de 57600 (indépendamment de ce que vous lisez ailleurs), ce qui signifie que la transmission d'un bit prend environ 17,4 µs. La relation entre ces deux temps est importante, car il semble que la réponse soit envoyée avec une gigue d'environ 17 µs également. Nous essayons donc de distinguer des réponses qui diffèrent de 4,2 µs dans le temps de réponse de la fonction de vérification, mais qui peuvent différer jusqu'à 17 µs en raison de la gigue UART (temporisation de l'horloge). Cela semble être une tâche difficile, mais elle est possible par des moyens statistiques.

Nous pouvons déterminer si un octet était correct ou non en essayant de le vérifier plusieurs fois et en enregistrant les résultats. Supposons par exemple que le temps le plus court possible pour recevoir une réponse si le premier octet est incorrect est de 30 µs. Alors, avec la gigue UART, nous pouvons nous attendre à un temps de réponse maximal de 30 µs + 17,4 µs = 47,4 µs pour un premier octet invalide. En même temps, un premier octet valide et un second octet invalide pousseraient cette "plage" de 34,2 µs à 51,6 µs. En ajoutant quelques marges, nous pouvons conclure que le premier caractère était invalide si le temps de réponse est inférieur à environ 33 µs. De même, nous pouvons dire que le premier caractère était valide si le temps de réponse était supérieur à 48 µs. C'est la base de l'attaque temporelle utilisée pour extraire le firmware.

Utilisation de l'extracteur de firmware

Ce n'est pas un outil entièrement automatique pour l'extraction de firmware - une modification du code source et une recompilation seront nécessaires (en utilisant VS Code avec PlatformIO). La raison principale est que les caractéristiques de synchronisation exactes pour chaque octet diffèrent entre les configurations et devront être ajustées. Le processus d'ajustement pourrait être automatisé, mais ce n'était pas l'objectif de ce projet. Le réglage principal se fait via la variable prober_limits. Par exemple, prober_limits[0] contient les limites pour l'octet 0 parmi les 8 octets à vérifier. Si le temps de réponse est inférieur à .invalid_under_time, nous savons que l'octet était invalide. S'il est supérieur à .valid_over_time, nous savons que l'octet était correct. Il y a aussi un .min_delta qui permet de passer à l'octet suivant avant de savoir avec certitude si l'octet est correct ou non.

root@kitploit:~
struct ProberByteLimits prober_limits[8] = {
    {
        // Byte 0
        .invalid_under_time = 33,
        .valid_over_time = 50,
        .min_delta = 30
    }, // ...

Pour trouver les bonnes valeurs à utiliser, il est recommandé de mettre .invalid_under_time à 0, .valid_over_time à par exemple 100, et .min_delta peut être conservé à 30. Cela signifie que le sondeur échouera à trouver le premier octet correct, mais la progression sera imprimée sur l'UART du PC hôte. Vous verrez quelque chose comme :

root@kitploit:~
[0x0000]=0x01? min=31 max=47 tries=63
               min=31 max=48 tries=127
               min=31 max=48 tries=191
               min=30 max=48 tries=255
               min=30 max=48 tries=319

À condition que le premier caractère testé soit invalide, nous pouvons utiliser ces valeurs min/max avec un décalage de 1 ou 2 pour déterminer les limites appropriées à utiliser. Par exemple ci-dessus, nous pourrions mettre .invalid_under_time à 33 et .valid_over_time à 50. Le sondeur devrait alors essayer différentes valeurs jusqu'à en trouver une valide, ce qui ressemblerait à ceci :

root@kitploit:~
...
[0x0000]=0x7d? min=31 max=39 tries= 7
[0x0000]=0x02? min=40 max=56 tries= 7
[0x0001]=0x01? min=35 max=52 tries=34

Nous voyons que la dernière tentative à l'adresse 0x0000 avait un temps de réponse maximal de 56 µs, ce qui signifie que c'était l'octet correct. Le sondeur passe ensuite à l'octet suivant et continue le processus. Notez que toutes les limites des 8 octets doivent être réglées séparément, mais une fois fait, cela fonctionnera pour toute la mémoire. Lorsque 8 octets corrects ont été trouvés, il les imprimera au format ihex :

root@kitploit:~
:0800000002002932ffffffff9f

Enregistrer la sortie UART dans un fichier texte permet de faire un grep pour ^: afin d'extraire le contexte mémoire complet au format ihex.

Circuit

Un exemple de circuit pour l'extraction de firmware est montré ci-dessous. Deux transistors permettent de couper l'alimentation du CH55x depuis la Blue Pill. Ceci est recommandé plutôt que d'utiliser uniquement une réinitialisation logicielle, car la réinitialisation logicielle ne fonctionne que lorsque le CH55x est en mode bootloader (et le bootloader a un délai après lequel il lance le code applicatif). Les résistances sur l'UART vers le CH55x sont incluses car je soupçonne que les pull-ups internes du CH55x pourraient alimenter le CH55x depuis l'UART même lorsque l'alimentation est coupée. La résistance de 10k entre V33 et P3.6 est nécessaire pour mettre le CH55x en mode bootloader. Sur la Blue Pill, PA11 est reliée à la broche RX UART pour pouvoir chronométrer la réponse à l'aide du timer 1.

CH55x firmware extractor circuit

Conclusion

En ajustant et en utilisant cet outil, le firmware des appareils CH55X peut être extrait. Le processus d'extraction n'est pas rapide, mais extraira les 14 ko en un ou deux jours. Cela dépend un peu du réglage et de la qualité de la table de fréquences utilisée par rapport à l'assembleur réel du firmware. Malheureusement, le code source est un peu désordonné. J'ai créé cet outil parce que j'avais besoin du firmware d'un appareil CH554, et maintenant que je l'ai obtenu, il n'y a pas de raison réelle de travailler sur l'outil lui-même. Néanmoins, il devrait s'avérer utile si quelqu'un a besoin d'extraire le firmware d'appareils CH55x.

Télécharger l’outil