
Fuzzer baseado em emulação para firmware MSP430 que encontra e analisa bugs de corrupção de memória com relatórios de crash detalhados e entradas reproduzíveis.
Falhas encontradas em binários MSP430 pelo Icicle.
| # | Alvo | Descrição |
|---|---|---|
| I03 | Goodwatch | Comparação incorreta ao escrever em dmesg_buffer |
| I04 | Goodwatch | Comprimento de mensagem zero |
| I05 | Goodwatch | Estouro de RNG |
| I06 | Goodwatch | Acesso fora dos limites em OOK keypress |
| I07 | Goodwatch | Acesso fora dos limites após 60 horas no cronômetro |
| I08 | Goodwatch | Acesso fora dos limites ao exibir o dia da semana |
| I09 | Goodwatch | Aplicativo Hex viewer |
| I10 | Goodwatch | Comandos de monitor PEEK/POKE |
| I11 | H4_PacketProtocol | Índice de interface não verificado em Get Descriptor |
| I12 | H4_PacketProtocol | Estouro de buffer em Set Report |
dmesg bufferputchar causa uma gravação OOB de um único byte em 0x2c00.Exemplo de pilha de chamadas durante a falha:
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>
Mensagens enviadas à interface UART com o campo de comprimento definido como zero são tratadas incorretamente. No estado MSG, após armazenar o byte que acabou de ser recebido no index atual do uart_buffer, ele incrementa index e verifica se agora é igual a length; porém, como o armazenamento e o incremento de index ocorrem antes da comparação com length, para mensagens de comprimento zero a condição index == length nunca será verdadeira.
Eventualmente, index excederá o array uart_buffer, permitindo que variáveis globais armazenadas após uart_buffer sejam modificadas. Isso normalmente resulta em uma falha do programa quando os ponteiros de função stdout_putf ou stdout_putp são sobrescritos e uma mensagem de depuração é impressa.
Entrada que causa a falha:
./run_goodwatch.sh I04a
Pilha de chamadas durante a falha:
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) for sobrescrito, causando uma falha na próxima vez que um applet for carregado usando appindex (por exemplo, em app_draw).Pilha de chamadas durante a falha:
UnhandledException(code=InvalidInstruction)
0x000000531c: <unknown>
0x0000009a96: app_init+0xe
0x000000c0a8: settime_draw+0x28
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
RANDINT faz o firmware gerar e enviar uma lista de números aleatórios. No entanto, o número de valores aleatórios a gerar é controlado pelo comando recebido. Se o número de valores a gerar for grande demais, rints excederá o espaço reservado para a pilha, acionando uma gravação OOB.Entrada que causa a falha:
./run_goodwatch.sh I05
Pilha de chamadas durante a falha:
UnhandledException(code=WriteUnmapped, value=0x6e6a)
0x000000cbd4: USCI_A0_ISR+0x24c (inlined `send_randint`)
0x0000008e04: <unknown>
ook keypress:O aplicativo OOK envia um pacote OOK pré-configurado de button_array quando uma das teclas numéricas (0-9) é pressionada. No entanto, ook_keypress não valida se a tecla pressionada está dentro dos limites do array button_array. Existem 10 botões numéricos (0-9) button_array contém apenas 9 entradas.
button_array contém um array de ponteiros; quando o botão 9 é pressionado no aplicativo OOK, a função setrate do programa lerá um ponteiro fora dos limites de button_array e o desreferencia, causando uma falha no programa.
O ponteiro lido é o primeiro valor de ook_settings (0x3012), que não existe na memória.
Entrada que causa a falha:
./run_goodwatch.sh I06
Pilha de chamadas durante a falha:
UnhandledException(code=ReadUnmapped, value=0x3012)
0x000000b87a: ook_keypress+0x2c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
O firmware implementa a operação de conversão de inteiro para decimal codificado em binário (BCD) usando uma tabela de consulta; no entanto, a tabela de consulta (bcdtable) contém apenas valores para converter inteiros de 0 a 59. Para converter segundos e minutos, isso é suficiente, pois esses valores são reiniciados ao chegar a 60 durante a contagem; porém, a variável hour pode exceder 60, causando um índice fora dos limites.
Esse bug só foi encontrado pelo fuzzer como efeito colateral da corrupção causada pelo bug de comprimento de mensagem zero. Na falha encontrada pelo fuzzer, as variáveis globais min e hour são corrompidas quando uart_buffer é estourado.
Entrada que causa a falha:
./run_goodwatch.sh I07
Pilha de chamadas durante a falha:
UnhandledException(code=ReadUnmapped, value=0x4b57)
0x000000a3e4: stopwatch_draw+0x9e
0x0000009b0a: app_draw+0x3e
0x000000ce78: watchdog_timer+0x6a
0x0000008e04: <unknown>
Falso positivo causado pelo fuzzer ao gerar um valor grande para o periférico RTCDOW.
Pressionar o botão 9 no aplicativo de relógio tenta desenhar o dia atual da semana no LCD. O dia da semana é lido diretamente do registrador RTCDOW do periférico RTC; a documentação deste registrador especifica que o valor retornado está entre 0 e 6, porém, durante o fuzzing, o valor deste registrador não tem restrições. Como o valor é usado como um índice no array dayofweek, se o fuzzer gerar um valor maior que 6 para o registrador RTCDOW, o programa lerá um ponteiro fora do array daysofweek, resultando em uma falha (falso positivo).
Essa falha pode ocorrer tanto em clock_keypress quanto em hebrew_keypress.
Entrada que causa a falha:
./run_goodwatch.sh I08a
Pilha de chamadas durante a falha:
UnhandledException(code=ReadUnmapped, value=0x5150)
0x0000009e6e: lcd_string+0x8
0x000000c1dc: clock_keypress+0x6c
0x000000cd7e: PORT2_ISR+0x5c
0x0000008e04: <unknown>
Entrada que causa a falha:
./run_goodwatch.sh I08b
Pilha de chamadas durante a falha:
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 causa a falha:
./run_goodwatch.sh I09
Pilha de chamadas durante a falha:
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 causa a falha para PEEK:
./run_goodwatch.sh I10a
Pilha de chamadas durante a falha:
UnhandledException(code=ReadUnmapped, value=0x5100)
0x000000cb00: USCI_A0_ISR+0x178
0x0000008e04: <unknown>
Entrada que causa a falha para POKE:
./run_goodwatch.sh I10b
Pilha de chamadas durante a falha:
UnhandledException(code=WritePerm, value=0x4b00)
0x000000cb32: USCI_A0_ISR+0x1aa
0x0000008e04: <unknown>
Get_Descriptor. Isso pode causar um acesso fora dos limites. Por exemplo:GetHidDescriptor:
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:
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, o firmware atribui um buffer para armazenar o relatório em pbOEP0Buffer e o comprimento do relatório em wBytesRemainingOnOEP0. No entanto, o firmware não verifica se o relatório cabe no buffer atribuído, causando um estouro de buffer quando o buffer é posteriormente gravado em usbReceiveNextPacketOnOEP0.Na entrada que causa a falha abaixo, o endereço de um array de 8 bytes (0x24a4: abUsbRequestIncomingData) é atribuído a pbOEP0Buffer; após estourar o array, um ponteiro de função (0x24b4: USB_RX_memcpy) é corrompido, causando uma falha quando o ponteiro de função é chamado posteriormente.
./run_H4_PacketProtocol.sh I12
Pilha de chamadas durante a falha:
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