
Fuzzer basato su emulazione per firmware MSP430 che trova e analizza bug di corruzione della memoria con report di crash dettagliati e input riproducibili.
Crash trovati nei binari MSP430 da Icicle.
| # | Target | Descrizione |
|---|---|---|
| I03 | Goodwatch | Confronto errato durante la scrittura su dmesg_buffer |
| I04 | Goodwatch | Lunghezza zero del messaggio |
| I05 | Goodwatch | Overflow RNG |
| I06 | Goodwatch | Accesso fuori dai limiti nella pressione dei tasti OOK |
| I07 | Goodwatch | Accesso fuori dai limiti dopo 60 ore nel cronometro |
| I08 | Goodwatch | Accesso fuori dai limiti durante la visualizzazione del giorno della settimana |
| I09 | Goodwatch | Applicazione Hex Viewer |
| I10 | Goodwatch | Comandi monitor PEEK/POKE |
| I11 | H4_PacketProtocol | Indice di interfaccia non controllato in Get Descriptor |
| I12 | H4_PacketProtocol | Buffer overflow in Set Report |
dmesg bufferputchar causa una scrittura OOB di un singolo byte all'indirizzo 0x2c00.Esempio di call-stack durante il crash:
UnhandledException(code=WriteUnmapped, value=0x2c00):
0x000000c81a: putchar+0x1c
0x000000c832: dmesg_putc+0x6
0x0000009706: tfp_format+0x22
0x000000ad9c: tfp_printf+0x12
0x000000b924: key_scan.part.0+0x68
0x000000cd3c: PORT2_ISR+0x1a
0x0000008e04: <unknown>
I messaggi inviati all'interfaccia UART con il campo lunghezza impostato a zero vengono gestiti in modo non corretto. Nello stato MSG, dopo aver memorizzato il byte appena ricevuto all'indice corrente index nel uart_buffer, incrementa index e verifica se ora è uguale a length; tuttavia, poiché la memorizzazione e l'incremento di index avvengono prima del confronto con length, per i messaggi a lunghezza zero la condizione index == length non sarà mai vera.
Alla fine index supererà l'array uart_buffer, consentendo la modifica delle variabili globali memorizzate dopo uart_buffer. Questo di solito causa il crash del programma quando vengono sovrascritti i puntatori a funzione stdout_putf o stdout_putp e viene stampato un messaggio di debug.
Input che causa il crash:
./run_goodwatch.sh I04a
Call-stack durante il crash:
UnhandledException(code=InvalidInstruction)
0x000000d3d3: <unknown>
0x0000009648: putchw+0x40
0x0000009826: tfp_format+0x142
0x000000ad9c: tfp_printf+0x12
0x000000b924: key_scan.part.0+0x68
0x000000cd3c: PORT2_ISR+0x1a
0x0000008e04: <unknown>
appindex (o subindex) venga sovrascritto, causando un crash la prossima volta che un applet viene caricato usando appindex (ad esempio in app_draw).Call-stack durante il crash:
UnhandledException(code=InvalidInstruction)
0x000000531c: <unknown>
0x0000009a96: app_init+0xe
0x000000c0a8: settime_draw+0x28
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
RANDINT fa sì che il firmware generi e invii un elenco di numeri casuali. Tuttavia, il numero di valori casuali da generare è controllato dal comando ricevuto. Se il numero di valori da generare è troppo grande, rints supererà lo spazio riservato allo stack, innescando una scrittura OOB.Input che causa il crash:
./run_goodwatch.sh I05
Call-stack durante il crash:
UnhandledException(code=WriteUnmapped, value=0x6e6a)
0x000000cbd4: USCI_A0_ISR+0x24c (inlined `send_randint`)
0x0000008e04: <unknown>
ook keypressL'applicazione OOK invia un pacchetto OOK preconfigurato da button_array quando viene premuto uno dei tasti numerici (0-9). Tuttavia ook_keypress non verifica che il tasto premuto sia all'interno dei limiti dell'array button_array. Ci sono 10 pulsanti numerici (0-9), ma button_array contiene solo 9 voci.
button_array contiene un array di puntatori; quando il tasto 9 viene premuto nell'applicazione OOK, la funzione setrate legge un puntatore fuori dai limiti di button_array e lo dereferenzia, causando il crash del programma.
Il puntatore che legge è il primo valore di ook_settings (0x3012), che non esiste in memoria.
Input che causa il crash:
./run_goodwatch.sh I06
Call-stack durante il crash:
UnhandledException(code=ReadUnmapped, value=0x3012)
0x000000b87a: ook_keypress+0x2c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Il firmware implementa la conversione da intero a decimale codificato in binario (BCD) usando una tabella di lookup, ma la tabella (bcdtable) contiene solo valori per convertire gli interi da 0 a 59. Per la conversione di secondi e minuti va bene, poiché questi valori si azzerano a 60 durante il conteggio, mentre la variabile hour può superare 60 causando un indice fuori dai limiti.
Questo bug è stato trovato dal fuzzer solo come effetto collaterale della corruzione causata dal bug della lunghezza del messaggio zero. Nel crash trovato dal fuzzer, sia la variabile globale min che hour vengono corrotte quando uart_buffer subisce un overflow.
Input che causa il crash:
./run_goodwatch.sh I07
Call-stack durante il crash:
UnhandledException(code=ReadUnmapped, value=0x4b57)
0x000000a3e4: stopwatch_draw+0x9e
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
Bug falso positivo causato dal fuzzer che genera un valore elevato per il periferico RTCDOW.
Premendo il tasto 9 nell'applicazione orologio si tenta di disegnare il giorno corrente della settimana sul LCD. Il giorno della settimana viene letto direttamente dal registro RTCDOW del periferico RTC; il datasheet di questo registro specifica che il valore restituito è compreso tra 0 e 6, ma durante il fuzzing il valore di questo registro non è vincolato. Poiché il valore viene usato come indice nell'array dayofweek, se il fuzzer genera un valore maggiore di 6 per il registro RTCDOW, il programma legge un puntatore fuori dall'array daysofweek, causando un crash (falso positivo).
Questo crash può verificarsi sia in clock_keypress che in hebrew_keypress.
Input che causa il crash:
./run_goodwatch.sh I08a
Call-stack durante il crash:
UnhandledException(code=ReadUnmapped, value=0x5150)
0x0000009e6e: lcd_string+0x8
0x000000c1dc: clock_keypress+0x6c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Input che causa il crash:
./run_goodwatch.sh I08b
Call-stack durante il crash:
UnhandledException(code=ReadPerm, value=0x1006)
0x0000009e6e: lcd_string+0x8
0x000000b2aa: hebrew_keypress+0x116
0x000000c48c: clock_keypress+0x31c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Input che causa il crash:
./run_goodwatch.sh I09
Call-stack durante il crash:
UnhandledException(code=ReadUnmapped, value=0x7000)
0x0000009c74: hex_draw.part.0+0x3c
0x0000009c88: hex_draw+0x8
0x0000009b0a: app_draw+0x3e
0x000000cd8c: PORT2_ISR+0x6a
0x0000008e04: <unknown>
Input che causa il crash per PEEK:
./run_goodwatch.sh I10a
Call-stack durante il crash:
UnhandledException(code=ReadUnmapped, value=0x5100)
0x000000cb00: USCI_A0_ISR+0x178
0x0000008e04: <unknown>
Input che causa il crash per POKE:
./run_goodwatch.sh I10b
Call-stack durante il crash:
UnhandledException(code=WritePerm, value=0x4b00)
0x000000cb32: USCI_A0_ISR+0x1aa
0x0000008e04: <unknown>
Get_Descriptor. Questo può causare un accesso fuori dai limiti. Ad esempio:GetHidDescriptor:
./run_H4_PacketProtocol.sh I11a
Call-stack durante il crash:
UnhandledException(code=ReadUninitialized, value=0xe90e)
0x0000011176: usbSendNextPacketOnIEP0 at ./USB_API/USB_Common/usb.c:1082.13
0x0000011c12: usbGetHidDescriptor at ./USB_API/USB_HID_API/UsbHidReq.c:78.5
0x0000010fb0: usbDecodeAndProcessUsbRequest at ./USB_API/USB_Common/usb.c:1655.5
0x0000011724: SetupPacketInterruptHandler at ./USB_config/UsbIsr.c:250.5
0x0000004410: iUsbInterruptHandler at ./USB_config/UsbIsr.c:88.9
0x0000004572: _c_int00_noargs
GetReportDescriptor:
./run_H4_PacketProtocol.sh I11b
Call-stack durante il crash:
UnhandledException(code=ReadUninitialized, value=0xa44c)
0x0000011c28: usbGetReportDescriptor at ./USB_API/USB_HID_API/UsbHidReq.c:85.5
0x0000010fb0: usbDecodeAndProcessUsbRequest at ./USB_API/USB_Common/usb.c:1655.5
0x0000011724: SetupPacketInterruptHandler at ./USB_config/UsbIsr.c:250.5
0x00000044fe: iUsbInterruptHandler at ./USB_config/UsbIsr.c:166.9
0x0000004572: _c_int00_noargs
Set_Report, il firmware assegna un buffer per memorizzare il report in pbOEP0Buffer e la lunghezza del report in wBytesRemainingOnOEP0. Tuttavia, il firmware non verifica che il report rientri nel buffer assegnato, causando un buffer overflow quando il buffer viene successivamente scritto in usbReceiveNextPacketOnOEP0.Nell'input che causa il crash riportato di seguito, l'indirizzo di un array di 8 byte (0x24a4: abUsbRequestIncomingData) viene assegnato a pbOEP0Buffer; dopo aver superato i limiti dell'array, un puntatore a funzione (0x24b4: USB_RX_memcpy) viene corrotto, causando un crash quando il puntatore a funzione viene successivamente chiamato.
./run_H4_PacketProtocol.sh I12
Call-stack durante il crash:
UnhandledException(code=InvalidInstruction, value=0xf95b7)
0x00000f95b7: <unknown>
0x0000011066: HidCopyUsbToBuff at ./USB_API/USB_HID_API/UsbHid.c:417.5
0x0000010172: USBHID_receiveData at ./USB_API/USB_HID_API/UsbHid.c:577.13
0x000001026a: main at ./main.c:115.25
0x0000004572: _c_int00_noargs