
Emulationsbasierter Fuzzer für MSP430-Firmware, der Speicherkorruptionsfehler findet und analysiert, mit detaillierten Absturzberichten und reproduzierbaren Eingaben.
Von Icicle in MSP430-Binärdateien gefundene Abstürze.
| # | Ziel | Beschreibung |
|---|---|---|
| I03 | Goodwatch | Falscher Vergleich beim Schreiben auf dmesg_buffer |
| I04 | Goodwatch | Nachrichtenlänge Null |
| I05 | Goodwatch | RNG-Überlauf |
| I06 | Goodwatch | Zugriff außerhalb der Grenzen bei OOK keypress |
| I07 | Goodwatch | Zugriff außerhalb der Grenzen nach 60 Stunden in der Stoppuhr |
| I08 | Goodwatch | Zugriff außerhalb der Grenzen bei der Anzeige des Wochentags |
| I09 | Goodwatch | Hex-Viewer-Anwendung |
| I10 | Goodwatch | PEEK/POKE-Monitorbefehle |
| I11 | H4_PacketProtocol | Nicht geprüfter Interface-Index in Get Descriptor |
| I12 | H4_PacketProtocol | Pufferüberlauf in Set Report |
dmesg bufferputchar verursacht einen Ein-Byte-OOB-Schreibzugriff an Adresse 0x2c00.Beispiel-Callstack während des Absturzes:
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>
Nachrichten, die über die UART-Schnittstelle mit einem auf Null gesetzten Längenfeld gesendet werden, werden falsch verarbeitet. Im Zustand MSG wird nach dem Speichern des soeben empfangenen Bytes am aktuellen index im uart_buffer der index inkrementiert und geprüft, ob er nun gleich length ist. Da das Speichern und Inkrementieren von index jedoch vor dem Vergleich mit length erfolgt, wird die Bedingung index == length bei Nachrichten mit der Länge Null niemals wahr.
Schließlich wird index das uart_buffer-Array überschreiten, wodurch globale Variablen, die nach uart_buffer gespeichert sind, modifiziert werden können. Dies führt in der Regel zu einem Absturz des Programms, wenn entweder die Funktionszeiger stdout_putf oder stdout_putp überschrieben werden und eine Debug-Nachricht ausgegeben wird.
Absturzauslösende Eingabe:
./run_goodwatch.sh I04a
Callstack während des Absturzes:
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 (oder subindex) überschrieben wird, was beim nächsten Laden eines applet mithilfe von appindex einen Absturz verursacht (z. B. in app_draw).Callstack während des Absturzes:
UnhandledException(code=InvalidInstruction)
0x000000531c: <unknown>
0x0000009a96: app_init+0xe
0x000000c0a8: settime_draw+0x28
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
RANDINT veranlasst die Firmware, eine Liste von Zufallszahlen zu erzeugen und zu senden. Die Anzahl der zu erzeugenden Zufallswerte wird jedoch durch den empfangenen Befehl gesteuert. Wenn die Anzahl der zu erzeugenden Werte zu groß ist, überschreitet rints den für den Stack reservierten Speicherplatz und löst einen OOB-Schreibzugriff aus.Absturzauslösende Eingabe:
./run_goodwatch.sh I05
Callstack während des Absturzes:
UnhandledException(code=WriteUnmapped, value=0x6e6a)
0x000000cbd4: USCI_A0_ISR+0x24c (inlined `send_randint`)
0x0000008e04: <unknown>
ook keypress:Die OOK-Anwendung sendet ein vorkonfiguriertes OOK-Paket aus button_array, wenn eine der numerischen Tasten (0-9) gedrückt wird. Allerdings validiert ook_keypress nicht, ob sich die gedrückte Taste innerhalb der Grenzen des button_array-Arrays befindet. Es gibt 10 numerische Tasten (0-9) button_array enthält nur 9 Einträge.
button_array enthält ein Array von Zeigern. Wenn die Taste 9 in der OOK-Anwendung gedrückt wird, liest die Funktion setrate des Programms einen Zeiger außerhalb der Grenzen von button_array und dereferenziert ihn, was zum Absturz des Programms führt.
Der gelesene Zeiger ist der erste Wert aus ook_settings (0x3012), der im Speicher nicht existiert.
Absturzauslösende Eingabe:
./run_goodwatch.sh I06
Callstack während des Absturzes:
UnhandledException(code=ReadUnmapped, value=0x3012)
0x000000b87a: ook_keypress+0x2c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Die Firmware implementiert die Umwandlung von Ganzzahlen in binär codierte Dezimalzahlen (BCD) mithilfe einer Nachschlagetabelle. Die Nachschlagetabelle (bcdtable) enthält jedoch nur Werte zum Umwandeln von Ganzzahlen von 0 bis 59. Für Sekunden und Minuten ist das in Ordnung, da diese Werte beim Zählen bei 60 überlaufen. Die Variable hour kann jedoch 60 überschreiten, was einen Index außerhalb der Grenzen verursacht.
Dieser Fehler wurde vom Fuzzer nur als Nebeneffekt der Korruption gefunden, die durch den Fehler mit der Nachrichtenlänge Null verursacht wurde. Bei dem vom Fuzzer gefundenen Absturz werden sowohl die globalen Variablen min als auch hour beschädigt, wenn uart_buffer überläuft.
Absturzauslösende Eingabe:
./run_goodwatch.sh I07
Callstack während des Absturzes:
UnhandledException(code=ReadUnmapped, value=0x4b57)
0x000000a3e4: stopwatch_draw+0x9e
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
False-Positive-Fehler, der dadurch verursacht wird, dass der Fuzzer einen großen Wert für das RTCDOW-Peripheriegerät erzeugt.
Beim Drücken von Taste 9 in der Uhr-Anwendung wird versucht, den aktuellen Wochentag auf dem LCD darzustellen. Der Wochentag wird direkt aus dem RTCDOW-Register des RTC-Peripheriegeräts gelesen. Das Datenblatt für dieses Register gibt an, dass der zurückgegebene Wert zwischen 0 und 6 liegt. Während des Fuzzings ist der Wert dieses Registers jedoch uneingeschränkt. Da der Wert als Index in das dayofweek-Array verwendet wird, liest das Programm einen Zeiger außerhalb des daysofweek-Arrays, wenn der Fuzzer einen Wert größer als 6 für das RTCDOW-Register erzeugt, was zu einem (False-Positive-)Absturz führt.
Dieser Absturz kann sowohl im Rahmen von clock_keypress als auch von hebrew_keypress auftreten.
Absturzauslösende Eingabe:
./run_goodwatch.sh I08a
Callstack während des Absturzes:
UnhandledException(code=ReadUnmapped, value=0x5150)
0x0000009e6e: lcd_string+0x8
0x000000c1dc: clock_keypress+0x6c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Absturzauslösende Eingabe:
./run_goodwatch.sh I08b
Callstack während des Absturzes:
UnhandledException(code=ReadPerm, value=0x1006)
0x0000009e6e: lcd_string+0x8
0x000000b2aa: hebrew_keypress+0x116
0x000000c48c: clock_keypress+0x31c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Absturzauslösende Eingabe:
./run_goodwatch.sh I09
Callstack während des Absturzes:
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>
Absturzauslösende Eingabe für PEEK:
./run_goodwatch.sh I10a
Callstack während des Absturzes:
UnhandledException(code=ReadUnmapped, value=0x5100)
0x000000cb00: USCI_A0_ISR+0x178
0x0000008e04: <unknown>
Absturzauslösende Eingabe für POKE:
./run_goodwatch.sh I10b
Callstack während des Absturzes:
UnhandledException(code=WritePerm, value=0x4b00)
0x000000cb32: USCI_A0_ISR+0x1aa
0x0000008e04: <unknown>
Get_Descriptor-Handler nicht geprüft. Dies kann einen Zugriff außerhalb der Grenzen verursachen. Zum Beispiel:GetHidDescriptor:
./run_H4_PacketProtocol.sh I11a
Callstack während des Absturzes:
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
Callstack während des Absturzes:
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
Nach dem Empfang eines Set_Report-Pakets weist die Firmware einen Puffer zum Speichern des Reports in pbOEP0Buffer und die Länge des Reports in wBytesRemainingOnOEP0 zu. Die Firmware prüft jedoch nicht, ob der Report in den zugewiesenen Puffer passt, was zu einem Pufferüberlauf führt, wenn der Puffer später in usbReceiveNextPacketOnOEP0 beschrieben wird.
In der unten gezeigten absturzauslösenden Eingabe wird die Adresse eines 8-Byte-Arrays (0x24a4: abUsbRequestIncomingData) pbOEP0Buffer zugewiesen. Nach dem Überlaufen des Arrays wird ein Funktionszeiger (0x24b4: USB_RX_memcpy) beschädigt, was beim späteren Aufruf des Funktionszeigers einen Absturz verursacht.
./run_H4_PacketProtocol.sh I12
Callstack während des Absturzes:
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