
Fuzzer basé sur l'émulation pour les firmwares MSP430 qui détecte et analyse les bugs de corruption mémoire avec des rapports de crash détaillés et des entrées reproductibles.
Crashes trouvés dans les binaires MSP430 par Icicle.
| # | Cible | Description |
|---|---|---|
| I03 | Goodwatch | Comparaison incorrecte lors de l'écriture dans dmesg_buffer |
| I04 | Goodwatch | Longueur de message nulle |
| I05 | Goodwatch | Débordement du RNG |
| I06 | Goodwatch | Accès hors limites lors de l'appui de touche OOK |
| I07 | Goodwatch | Accès hors limites dans le chronomètre |
| I08 | Goodwatch | Accès hors limites lors de l'affichage du jour de la semaine |
| I09 | Goodwatch | Application Hex Viewer |
| I10 | Goodwatch | Commandes du moniteur PEEK/POKE |
| I11 | H4_PacketProtocol | Index d'interface non vérifié dans Get Descriptor |
| I12 | H4_PacketProtocol | Débordement de tampon dans Set Report |
dmesg bufferputchar provoque une écriture OOB d'un seul octet à 0x2c00.Exemple de pile d'appels lors du 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>
Les messages envoyés à l'interface UART avec le champ de longueur défini à zéro sont traités incorrectement. Dans l'état MSG, après avoir stocké l'octet qui vient d'être reçu à l'index courant dans uart_buffer, le code incrémente index et vérifie s'il est maintenant égal à length. Cependant, comme le stockage et l'incrémentation de index se produisent avant la comparaison avec length, la condition index == length ne sera jamais vraie pour les messages de longueur nulle.
Finalement, index dépassera le tableau uart_buffer, ce qui permet de modifier les variables globales stockées après uart_buffer. Cela entraîne généralement un crash du programme lorsque les pointeurs de fonction stdout_putf ou stdout_putp sont écrasés et qu'un message de débogage est affiché.
Entrée provoquant le crash :
./run_goodwatch.sh I04a
Pile d'appels lors du 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 (ou subindex) soit écrasé, provoquant un crash lors du chargement du prochain applet utilisant appindex (par exemple dans app_draw).Pile d'appels lors du 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 amène le firmware à générer et à envoyer une liste de nombres aléatoires. Cependant, le nombre de valeurs aléatoires à générer est contrôlé par la commande reçue. Si le nombre de valeurs à générer est trop grand, rints dépassera l'espace réservé à la pile, déclenchant une écriture OOB.Entrée provoquant le crash :
./run_goodwatch.sh I05
Pile d'appels lors du crash :
UnhandledException(code=WriteUnmapped, value=0x6e6a)
0x000000cbd4: USCI_A0_ISR+0x24c (inlined `send_randint`)
0x0000008e04: <unknown>
ook keypress :L'application OOK envoie un paquet OOK préconfiguré depuis button_array lorsque l'une des touches numériques (0-9) est enfoncée. Cependant, ook_keypress ne vérifie pas que la touche enfoncée est dans les limites du tableau button_array. Il y a 10 boutons numériques (0-9), mais button_array ne contient que 9 entrées.
button_array contient un tableau de pointeurs. Lorsque le bouton 9 est enfoncé dans l'application OOK, la fonction setrate du programme lit un pointeur hors des limites de button_array et le déréférence, provoquant le crash du programme.
Le pointeur ainsi lu est la première valeur de ook_settings (0x3012), qui n'existe pas en mémoire.
Entrée provoquant le crash :
./run_goodwatch.sh I06
Pile d'appels lors du crash :
UnhandledException(code=ReadUnmapped, value=0x3012)
0x000000b87a: ook_keypress+0x2c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Le firmware implémente la conversion d'entiers en décimal codé binaire (BCD) à l'aide d'une table de correspondance. Cependant, la table (bcdtable) ne contient que des valeurs pour convertir les entiers de 0 à 59. Pour les secondes et les minutes, cela convient puisque ces valeurs repassent à zéro à 60 lors du comptage. En revanche, la variable hour peut dépasser 60, provoquant un index hors limites.
Ce bug n'a été trouvé par le fuzzer que comme effet secondaire de la corruption causée par le bug de longueur de message nulle. Dans le crash trouvé par le fuzzer, les variables globales min et hour sont toutes deux corrompues lorsque uart_buffer est débordé.
Entrée provoquant le crash :
./run_goodwatch.sh I07
Pile d'appels lors du crash :
UnhandledException(code=ReadUnmapped, value=0x4b57)
0x000000a3e4: stopwatch_draw+0x9e
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
Faux positif causé par le fuzzer générant une grande valeur pour le périphérique RTCDOW.
Appuyer sur le bouton 9 dans l'application horloge tente d'afficher le jour actuel de la semaine sur l'écran LCD. Le jour de la semaine est lu directement depuis le registre RTCDOW du périphérique RTC. La fiche technique de ce registre spécifie que la valeur retournée est comprise entre 0 et 6. Cependant, pendant le fuzzing, la valeur de ce registre n'est pas contrainte. Comme la valeur est utilisée comme index dans le tableau dayofweek, si le fuzzer génère une valeur supérieure à 6 pour le registre RTCDOW, le programme lira un pointeur en dehors du tableau daysofweek, ce qui entraîne un crash (faux positif).
Ce crash peut se produire dans le cadre de clock_keypress et de hebrew_keypress.
Entrée provoquant le crash :
./run_goodwatch.sh I08a
Pile d'appels lors du crash :
UnhandledException(code=ReadUnmapped, value=0x5150)
0x0000009e6e: lcd_string+0x8
0x000000c1dc: clock_keypress+0x6c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Entrée provoquant le crash :
./run_goodwatch.sh I08b
Pile d'appels lors du crash :
UnhandledException(code=ReadPerm, value=0x1006)
0x0000009e6e: lcd_string+0x8
0x000000b2aa: hebrew_keypress+0x116
0x000000c48c: clock_keypress+0x31c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Entrée provoquant le crash :
./run_goodwatch.sh I09
Pile d'appels lors du 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>
Entrée provoquant le crash pour PEEK :
./run_goodwatch.sh I10a
Pile d'appels lors du crash :
UnhandledException(code=ReadUnmapped, value=0x5100)
0x000000cb00: USCI_A0_ISR+0x178
0x0000008e04: <unknown>
Entrée provoquant le crash pour POKE :
./run_goodwatch.sh I10b
Pile d'appels lors du crash :
UnhandledException(code=WritePerm, value=0x4b00)
0x000000cb32: USCI_A0_ISR+0x1aa
0x0000008e04: <unknown>
Get_Descriptor. Cela peut provoquer un accès hors limites. Par exemple :GetHidDescriptor :
./run_H4_PacketProtocol.sh I11a
Pile d'appels lors du 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
Pile d'appels lors du 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
Après avoir reçu un paquet Set_Report, le firmware affecte un tampon pour stocker le rapport dans pbOEP0Buffer et la longueur du rapport dans wBytesRemainingOnOEP0. Cependant, le firmware ne vérifie pas si le rapport tient dans le tampon affecté, ce qui provoque un débordement de tampon lorsque usbReceiveNextPacketOnOEP0 écrit ensuite dans ce tampon.
Dans l'entrée provoquant le crash ci-dessous, l'adresse du tableau de 8 octets (0x24a4: abUsbRequestIncomingData) est affectée à pbOEP0Buffer. Après le débordement du tableau, un pointeur de fonction (0x24b4: USB_RX_memcpy) est corrompu, ce qui provoque un crash lorsque ce pointeur de fonction est appelé ultérieurement.
./run_H4_PacketProtocol.sh I12
Pile d'appels lors du 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