Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ch55x_firmware_extractor — Estrattore di firmware per microprocessori CH55x | Kitploit
Strumenti/GitHubGitHub/finngineering/ch55x_firmware_extractor
Sicurezza Sistemi EmbeddedExploitReverse EngineeringHacking HardwareSicurezza HardwareSicurezza Hardware e IoTAnalisi del Firmware
GitHubfinngineering/ch55x_firmware_extractor

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

ch55x_firmware_extractor

Estrattore di firmware per microprocessori CH55x

Vedi Repository
128 mesi faNon ancora revisionato

Estrattore di firmware CH55x

L'estrattore di firmware CH55x viene utilizzato per leggere il firmware dai circuiti integrati CH55x. I dispositivi non dispongono di un supporto integrato per la lettura diretta del firmware tramite il bootloader. Tuttavia, esiste una funzionalità per verificare il contenuto del firmware 8 byte alla volta rispetto a dati forniti. Questa funzionalità è vulnerabile a un classico attacco basato sui tempi ed è ciò che viene sfruttato qui per consentire l'estrazione del firmware da questi dispositivi. Il bootloader è accessibile sia tramite USB che UART. Questo estrattore di firmware funziona solo tramite UART, perché la latenza più elevata della USB renderebbe difficile questo attacco. I chip testati sono CH552 e CH554, con versioni del bootloader 2.4 e 2.5. La soluzione hardware per l'estrattore di firmware si basa su una STM32 Blue Pill, perché sono facilmente reperibili, economiche e hanno le prestazioni necessarie.

Anatomia dell'exploit

Il bootloader è stato precedentemente estratto dal dispositivo e il suo protocollo di comunicazione è stato sottoposto a reverse engineering. Di seguito sono riportati un comando di verifica approssimativamente corretto e la funzione di verifica utilizzata nel bootloader. Sono presenti alcuni controlli che richiedono che la lunghezza sia un multiplo di 8, che l'indirizzo sia allineato a un confine di 8 byte, che l'indirizzo sia inferiore a 0x3800 e che non ci siano errori di verifica precedenti. L'ultimo controllo implica che sia necessario un riavvio del CH55x dopo ogni verifica non riuscita.

Possiamo notare che la funzione di verifica restituisce immediatamente il controllo quando un byte della verifica fallisce. Questo significa che più byte sono corretti, più tempo impiegherà la funzione di verifica. Questo è il classico esempio di un attacco basato sui tempi che può essere sfruttato.

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;
}

Attraverso tentativi ed errori abbiamo scoperto che ogni byte corretto estende il tempo di esecuzione della funzione di verifica di circa 4,2 µs. Il baud rate utilizzato dal bootloader per la comunicazione UART è 57600 (indipendentemente da quanto letto altrove), il che significa che la trasmissione di un bit richiede circa 17,4 µs. La relazione tra questi due tempi è importante, perché sembra che la risposta venga inviata con un jitter di anch'esso ~17 µs. Cerchiamo quindi di distinguere risposte che differiscono di 4,2 µs nel tempo di risposta dalla funzione di verifica, ma che possono differire fino a 17 µs a causa del jitter UART (temporizzazione dell'orologio). Questo sembra un compito difficile, ma è possibile realizzarlo con metodi statistici.

Possiamo determinare se un byte è corretto o meno provando a verificarlo più volte e registrando i risultati. Supponiamo, ad esempio, che il tempo più breve possibile per ricevere una risposta se il primo byte è sbagliato sia 30 µs. Quindi, con il jitter UART, possiamo aspettarci un tempo di risposta massimo di 30 µs + 17,4 µs = 47,4 µs per un primo byte non valido. Allo stesso tempo, un primo byte valido e un secondo byte non valido sposterebbero questo "intervallo" da 34,2 µs a 51,6 µs. Aggiungendo alcuni margini, possiamo concludere che il primo carattere non era valido se il tempo di risposta è inferiore a ~33 µs. Analogamente, possiamo affermare che il primo carattere era valido se il tempo di risposta è superiore a 48 µs. Questa è la base dell'attacco basato sui tempi utilizzato per estrarre il firmware.

Utilizzo dell'estrattore di firmware

Questo non è uno strumento completamente automatico per l'estrazione del firmware: sarà necessario modificare il codice sorgente e ricompilare (usando VS Code con PlatformIO). Il motivo principale è che le caratteristiche temporali esatte per ogni byte variano tra le diverse configurazioni e dovranno essere calibrate. Il processo di calibrazione potrebbe essere automatizzato, ma non era l'obiettivo di questo progetto. La calibrazione principale viene effettuata tramite la variabile prober_limits. Ad esempio, prober_limits[0] contiene i limiti per il byte 0 degli 8 byte da verificare. Se il tempo di risposta è inferiore a .invalid_under_time, sappiamo che il byte non era valido. Se è superiore a .valid_over_time, sappiamo che il byte era corretto. C'è anche un .min_delta che consente di passare al byte successivo prima di sapere con certezza se il byte è corretto o meno.

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

Per trovare i valori corretti da usare, si consiglia di impostare .invalid_under_time a 0, .valid_over_time a, ad esempio, 100, e .min_delta può essere mantenuto a 30. Questo significa che il prober non riuscirà a trovare il primo byte corretto, ma l'avanzamento verrà stampato sulla UART del PC host. Si vedrà qualcosa di simile a:

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

Supponendo che il primo carattere testato non sia valido, possiamo usare questi valori min/max con un offset di 1 o 2 per determinare i limiti appropriati da utilizzare. Ad esempio, in precedenza, potremmo impostare .invalid_under_time a 33 e .valid_over_time a 50. Il prober dovrebbe quindi provare diversi valori finché non trova uno valido, che apparirebbe come sotto:

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

Vediamo che l'ultimo tentativo all'indirizzo 0x0000 ha avuto un tempo di risposta massimo di 56 µs, il che significa che quello era il byte corretto. Il prober passa quindi al byte successivo e continua il processo. Si noti che tutti i limiti degli 8 byte devono essere calibrati separatamente, ma una volta fatto, funzionerà per l'intera memoria. Quando sono stati trovati 8 byte corretti, li stamperà in formato ihex:

root@kitploit:~
:0800000002002932ffffffff9f

Registrando l'output UART su un file di testo, è possibile usare grep per ^: ed estrarre l'intero contenuto della memoria in formato ihex.

Circuito

Di seguito è mostrato un esempio di circuito per l'estrazione del firmware. Due transistor permettono di spegnere l'alimentazione del CH55x dalla Blue Pill. Questo è consigliato rispetto all'utilizzo del solo reset software, perché il reset software funziona solo quando il CH55x è in modalità bootloader (e il bootloader ha un timeout dopo il quale avvia il codice applicativo). I resistori sulla UART verso il CH55x sono inclusi perché sospetto che le pull-up interne del CH55x possano alimentarlo dalla UART anche quando l'alimentazione è spenta. Il resistore da 10k tra V33 e P3.6 è necessario per mettere il CH55x in modalità bootloader. Sulla Blue Pill, PA11 è collegato al pin RX della UART per poter misurare il tempo di risposta usando il timer 1.

Circuito dell'estrattore di firmware CH55x

Conclusione

Calibrando e utilizzando questo strumento, è possibile estrarre il firmware dei dispositivi CH55X. Il processo di estrazione non è veloce, ma estrarrà i 14 kb in uno o due giorni. Dipende un po' dalla calibrazione e da quanto la tabella delle frequenze utilizzata corrisponde all'assembler effettivo del firmware. Purtroppo, il codice sorgente è un po' caotico. Ho creato questo strumento perché avevo bisogno del firmware da un dispositivo CH554 e, ora che l'ho ottenuto, non c'è un vero motivo per lavorare ulteriormente sullo strumento stesso. Tuttavia, dovrebbe rivelarsi utile nel caso qualcuno abbia bisogno di estrarre firmware da dispositivi CH55x.

Scarica lo strumento