
Fuzzer basado en emulación para firmware MSP430 que encuentra y analiza errores de corrupción de memoria con informes de fallos detallados y entradas reproducibles.
Fallos encontrados en binarios MSP430 por Icicle.
| # | Objetivo | Descripción |
|---|---|---|
| I03 | Goodwatch | Comparación incorrecta al escribir en dmesg_buffer |
| I04 | Goodwatch | Longitud de mensaje cero |
| I05 | Goodwatch | Desbordamiento del RNG |
| I06 | Goodwatch | Acceso fuera de límites en la pulsación de tecla OOK |
| I07 | Goodwatch | Acceso fuera de límites en el cronómetro |
| I08 | Goodwatch | Acceso fuera de límites al mostrar el día de la semana |
| I09 | Goodwatch | Aplicación de visor hexadecimal |
| I10 | Goodwatch | Comandos de monitor PEEK/POKE |
| I11 | H4_PacketProtocol | Índice de interfaz no verificado en Get Descriptor |
| I12 | H4_PacketProtocol | Desbordamiento de búfer en Set Report |
dmesg bufferputchar provoca una escritura fuera de límites de un solo byte en 0x2c00.Ejemplo de pila de llamadas durante el fallo:
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>
Los mensajes enviados a la interfaz UART con el campo de longitud establecido a cero se gestionan incorrectamente. En el estado MSG, después de almacenar el byte que se acaba de recibir en la index actual de uart_buffer, se incrementa index y se comprueba si ahora es igual a length; sin embargo, dado que el almacenamiento y el incremento de index ocurren antes de compararlo con length, para mensajes de longitud cero la condición index == length nunca será verdadera.
Con el tiempo, index superará el array uart_buffer, lo que permite modificar variables globales almacenadas después de uart_buffer. Esto normalmente provoca que el programa falle cuando se sobrescriben los punteros a función stdout_putf o stdout_putp y se imprime un mensaje de depuración.
Entrada que provoca el fallo:
./run_goodwatch.sh I04a
Pila de llamadas durante el fallo:
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) se sobrescriba, lo que provoca un fallo la próxima vez que se cargue un applet usando appindex (por ejemplo, en app_draw).Pila de llamadas durante el fallo:
UnhandledException(code=InvalidInstruction)
0x000000531c: <unknown>
0x0000009a96: app_init+0xe
0x000000c0a8: settime_draw+0x28
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
RANDINT hace que el firmware genere y envíe una lista de números aleatorios. Sin embargo, el número de valores aleatorios a generar está controlado por el comando recibido. Si el número de valores a generar es demasiado grande, rints excederá el espacio reservado para la pila, provocando una escritura fuera de límites.Entrada que provoca el fallo:
./run_goodwatch.sh I05
Pila de llamadas durante el fallo:
UnhandledException(code=WriteUnmapped, value=0x6e6a)
0x000000cbd4: USCI_A0_ISR+0x24c (inlined `send_randint`)
0x0000008e04: <unknown>
ook keypress:La aplicación OOK envía un paquete OOK preconfigurado desde button_array cuando se pulsa una de las teclas numéricas (0-9). Sin embargo, ook_keypress no valida que la tecla pulsada esté dentro de los límites del array button_array. Hay 10 botones numéricos (0-9) y button_array solo contiene 9 entradas.
button_array contiene un array de punteros; cuando se pulsa el botón 9 en la aplicación OOK, la función setrate del programa leerá un puntero fuera de los límites de button_array y lo desreferenciará, causando el fallo del programa.
El puntero que lee es el primer valor de ook_settings (0x3012), que no existe en memoria.
Entrada que provoca el fallo:
./run_goodwatch.sh I06
Pila de llamadas durante el fallo:
UnhandledException(code=ReadUnmapped, value=0x3012)
0x000000b87a: ook_keypress+0x2c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
El firmware implementa la conversión de entero a decimal codificado en binario (BCD) mediante una tabla de búsqueda; sin embargo, la tabla de búsqueda (bcdtable) solo contiene valores para convertir enteros de 0 a 59. Para convertir segundos y minutos esto es correcto, ya que estos valores se reinician al llegar a 60 durante el conteo; no obstante, la variable hour puede superar 60, lo que provoca un índice fuera de límites.
Este error solo fue encontrado por el fuzzer como efecto secundario de la corrupción causada por el error de longitud de mensaje cero. En el fallo encontrado por el fuzzer, tanto la variable global min como hour se corrompen cuando se desborda uart_buffer.
Entrada que provoca el fallo:
./run_goodwatch.sh I07
Pila de llamadas durante el fallo:
UnhandledException(code=ReadUnmapped, value=0x4b57)
0x000000a3e4: stopwatch_draw+0x9e
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
Falso positivo provocado por el fuzzer al generar un valor grande para el periférico RTCDOW.
Al pulsar el botón 9 en la aplicación de reloj se intenta dibujar el día actual de la semana en la LCD. El día de la semana se lee directamente del registro RTCDOW del periférico RTC; la hoja de datos de este registro especifica que el valor devuelto está entre 0 y 6. Sin embargo, durante el fuzzing el valor de este registro no está restringido. Dado que el valor se usa como índice en el array dayofweek, si el fuzzer genera un valor mayor que 6 para el registro RTCDOW, el programa leerá un puntero fuera del array daysofweek, lo que produce un fallo (falso positivo).
Este fallo puede ocurrir tanto en clock_keypress como en hebrew_keypress.
Entrada que provoca el fallo:
./run_goodwatch.sh I08a
Pila de llamadas durante el fallo:
UnhandledException(code=ReadUnmapped, value=0x5150)
0x0000009e6e: lcd_string+0x8
0x000000c1dc: clock_keypress+0x6c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Entrada que provoca el fallo:
./run_goodwatch.sh I08b
Pila de llamadas durante el fallo:
UnhandledException(code=ReadPerm, value=0x1006)
0x0000009e6e: lcd_string+0x8
0x000000b2aa: hebrew_keypress+0x116
0x000000c48c: clock_keypress+0x31c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Entrada que provoca el fallo:
./run_goodwatch.sh I09
Pila de llamadas durante el fallo:
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>
Entrada que provoca el fallo para PEEK:
./run_goodwatch.sh I10a
Pila de llamadas durante el fallo:
UnhandledException(code=ReadUnmapped, value=0x5100)
0x000000cb00: USCI_A0_ISR+0x178
0x0000008e04: <unknown>
Entrada que provoca el fallo para POKE:
./run_goodwatch.sh I10b
Pila de llamadas durante el fallo:
UnhandledException(code=WritePerm, value=0x4b00)
0x000000cb32: USCI_A0_ISR+0x1aa
0x0000008e04: <unknown>
Get_Descriptor. Esto puede causar un acceso fuera de límites. Por ejemplo:GetHidDescriptor:
./run_H4_PacketProtocol.sh I11a
Pila de llamadas durante el fallo:
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
Pila de llamadas durante el fallo:
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
Después de recibir un paquete Set_Report, el firmware asigna un búfer para almacenar el informe en pbOEP0Buffer, y la longitud del informe en wBytesRemainingOnOEP0. Sin embargo, el firmware no comprueba si el informe cabe en el búfer asignado, lo que provoca un desbordamiento de búfer cuando posteriormente se escribe en el búfer en usbReceiveNextPacketOnOEP0.
En la entrada que provoca el fallo a continuación, la dirección del array de 8 bytes (0x24a4: abUsbRequestIncomingData) se asigna a pbOEP0Buffer; después de desbordar el array, un puntero a función (0x24b4: USB_RX_memcpy) se corrompe, lo que causa un fallo cuando el puntero a función se llama posteriormente.
./run_H4_PacketProtocol.sh I12
Pila de llamadas durante el fallo:
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