Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
gdbfuzz — Fuzzing de Sistemas Embarcados usando Breakpoints de Hardware | Kitploit
Ferramentas/GitHubGitHub/boschresearch/gdbfuzz
Segurança de Sistemas EmbarcadosAnálise de VulnerabilidadesDepuradoresFuzzingSegurança de HardwareAnálise de BináriosPapers e PesquisaAprendizado e EducaçãoAnálise de FirmwareArchived
GitHubboschresearch/gdbfuzz

gdbfuzz

Fuzzing de Sistemas Embarcados usando Breakpoints de Hardware

19420há 2 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Ver Repositório

GDBFuzz: Fuzzing orientado por depurador

Este é o código complementar para o artigo: 'Fuzzing Embedded Systems using Debugger Interfaces'. Uma pré-impressão do artigo pode ser encontrada aqui https://publications.cispa.saarland/3950/. O código permite que os usuários reproduzam e estendam os resultados relatados no artigo. Por favor, cite o artigo acima ao reportar, reproduzir ou estender os resultados.

Estrutura de pastas

root@kitploit:~
.
    ├── benchmark               # Scripts para construir o conjunto de teste de fuzzer do Google e executar experimentos
    ├── dependencies            # Contém um Makefile para instalar dependências para o GDBFuzz
    ├── evaluation              # Dados brutos dos experimentos, apresentados no artigo
    ├── example_firmware        # Aplicações de exemplo embarcadas, usadas para a avaliação
    ├── example_programs        # Contém um programa de exemplo compilado e configurações para testar o GDBFuzz
    ├── src                     # Contém a implementação do GDBFuzz
    ├── Dockerfile              # Para criar uma imagem Docker com todas as dependências do GDBFuzz instaladas
    ├── LICENSE                 # Licença
    ├── Makefile                # Makefile para criar a imagem Docker ou instalar o GDBFuzz localmente
    └── README.md               # Este arquivo README

Propósito do projeto

A ideia do GDBFuzz é aproveitar pontos de interrupção de hardware de microcontroladores como feedback para fuzzing guiado por cobertura. Para isso, o GDB é usado como uma interface genérica para permitir ampla aplicabilidade. Para análise binária do firmware, o Ghidra é usado. O código contém uma configuração de benchmark para avaliar o método. Além disso, arquivos de firmware de exemplo estão incluídos.

Primeiros passos

O GDBFuzz permite fuzzing guiado por cobertura para sistemas embarcados, mas - para fins de avaliação - também pode fuzzar aplicações de usuário arbitrárias. Para fuzzing em microcontroladores, recomendamos uma instalação local do GDBFuzz para poder enviar dados de fuzz para o dispositivo sob teste sem problemas.

Instalação local

O GDBFuzz foi testado no Ubuntu 20.04 LTS e no Raspberry Pi OS 32 bits. Pré-requisitos são java e python3. Primeiro, crie um novo ambiente virtual e instale todas as dependências.

root@kitploit:~
virtualenv .venv
source .venv/bin/activate
make
chmod a+x ./src/GDBFuzz/main.py

Executar localmente em um programa de exemplo

O GDBFuzz lê configurações de um arquivo de configuração com as seguintes chaves.

root@kitploit:~
[SUT]
# Caminho para o arquivo binário do SUT.
# Isso pode ser, por exemplo, um arquivo .elf ou um arquivo .bin.
binary_file_path = <caminho>

# Endereço do nó raiz do CFG.
# Pontos de interrupção são colocados em nós deste CFG.
# ex.: 'LLVMFuzzerTestOneInput' ou 'main'
entrypoint = <ponto_de_entrada>

# Número de entradas que devem ser executadas sem um ponto de interrupção ser atingido até
# que os pontos de interrupção sejam rotacionados.
until_rotate_breakpoints = <número>


# Número máximo de pontos de interrupção que podem ser colocados a qualquer momento.
max_breakpoints = <número>

# Lista de funções que devem ser ignoradas.
# ignore_functions é uma lista de nomes de funções separados por espaço, ex.: 'malloc free'.
ignore_functions = <lista separada por espaço>

# Um de {Hardware, QEMU, SUTRunsOnHost}
# Hardware: Um componente externo inicia um servidor gdb e o GDBFuzz pode se conectar a esse servidor gdb.
# QEMU: O GDBFuzz inicia o QEMU. O QEMU emula binary_file_path e inicia o gdbserver.
# SUTRunsOnHost: O GDBFuzz inicia o programa alvo dentro do GDB.
target_mode = <modo>

# Defina como False se você quiser iniciar o ghidra, analisar o SUT
# e iniciar o servidor bridge do ghidra manualmente.
start_ghidra = True


# Lista separada por espaços de endereços onde pontos de interrupção de software (para código
# de tratamento de erros) são definidos. A execução destes é considerada uma falha.
# Exemplo: software_breakpoint_addresses = 0x123 0x432
software_breakpoint_addresses = 


# Se todos os pontos de interrupção de software acionados são considerados como falha
consider_sw_breakpoint_as_error = False

[SUTConnection]
# A classe 'SUT_connection_class' no arquivo 'SUT_connection_path' implementa
# como as entradas são enviadas para o SUT.
# As entradas podem, por exemplo, ser enviadas via Wi-Fi, Serial, Bluetooth, ...
# Esta classe deve herdar de ./connections/SUTConnection.py.
# Veja ./connections/SUTConnection.py para mais informações.
SUT_connection_file = FIFOConnection.py

[GDB]
path_to_gdb = gdb-multiarch
#Escrito como endereço:porta
gdb_server_address = localhost:4242

[Fuzzer]
# Em bytes
maximum_input_length = 100000
# Em segundos
single_run_timeout = 20
# Em segundos
total_runtime = 3600

# Opcional
# Caminho para um diretório onde cada arquivo contém uma semente. Se você não quiser
# usar sementes, deixe o valor vazio.
seeds_directory = 

[BreakpointStrategy]
# As estratégias para escolher blocos básicos estão localizadas em
# 'src/GDBFuzz/breakpoint_strategies/'
# Para o artigo, usamos as seguintes estratégias
# 'RandomBasicBlockStrategy.py' - Escolhe aleatoriamente blocos básicos não alcançados
# 'RandomBasicBlockNoDomStrategy.py' - Como o anterior, mas não usa relações de dominância para derivar nós transitivamente alcançados.
# 'RandomBasicBlockNoCorpusStrategy.py' - Como o primeiro, mas impede o crescimento do corpus de entrada e, portanto, se comporta como fuzzing de caixa preta com medição de cobertura.
# 'BlackboxStrategy.py' - Não define nenhum ponto de interrupção
breakpoint_strategy_file = RandomBasicBlockStrategy.py

[Dependencies]
path_to_qemu = dependencies/qemu/build/x86_64-linux-user/qemu-x86_64
path_to_ghidra = dependencies/ghidra


[LogsAndVisualizations]
# Um de {DEBUG, INFO, WARNING, ERROR, CRITICAL}
loglevel = INFO

# Caminho para um diretório onde os arquivos de saída (ex.: gráficos, arquivos de log) são armazenados.
output_directory = ./output

# Se definido como True, um cliente MQTT envia elementos de UI (ex.: gráficos)
enable_UI = False

Um exemplo de arquivo de configuração está localizado em ./example_programs/ junto com um programa de exemplo que foi compilado usando nosso harness de fuzzing em benchmark/benchSUTs/GDBFuzz_wrapper/common/. Inicie o fuzzing por uma hora com o seguinte comando.

root@kitploit:~
chmod a+x ./example_programs/json-2017-02-12
./src/GDBFuzz/main.py --config ./example_programs/fuzz_json.cfg

Primeiro vemos a saída do Ghidra analisando o executável binário e, em seguida, mensagens quando os pontos de interrupção são realocados ou atingidos.

Saída do Fuzzing

Dependendo do output_directory especificado no arquivo de configuração, agora deve haver uma pasta trial-0 com a seguinte estrutura

root@kitploit:~
.
    ├── corpus            # Uma pasta que contém o corpus de entrada.
    ├── crashes           # Uma pasta que contém entradas que causam falha - se houver.
    ├── cfg               # O grafo de fluxo de controle como lista de adjacência.
    ├── fuzzer_stats      # Estatísticas da campanha de fuzzing.
    ├── plot_data         # Tabela mostrando em qual tempo relativo na campanha de fuzzing qual bloco básico foi alcançado.
    ├── reverse_cfg       # O grafo de fluxo de controle reverso.

Usando o Ghidra no modo GUI

Definindo start_ghidra = False no arquivo de configuração, o GDBFuzz se conecta a uma instância do Ghidra executando no modo GUI. Portanto, o plugin ghidra_bridge precisa ser iniciado manualmente a partir do gerenciador de scripts. Durante o fuzzing, os blocos de programa alcançados são destacados em verde.

GDBFuzz em programas de usuário Linux

Para fuzzing em aplicações de usuário Linux, o GDBFuzz aproveita o ponto de entrada padrão LLVMFuzzOneInput que é usado por quase todos os fuzzers como AFL, AFL++, libFuzzer,.... Em benchmark/benchSUTs/GDBFuzz_wrapper/common há um wrapper que pode ser usado para compilar qualquer harness de fuzzing compatível em um programa independente que obtém entrada via um pipe nomeado em /tmp/fromGDBFuzz. Isso permite simular um dispositivo embarcado que consome dados através de uma interface de entrada bem definida e, portanto, executar o GDBFuzz em qualquer aplicação. Para conveniência, criamos um script em benchmark/benchSUTs que compila todos os programas de nossa avaliação com nosso wrapper, conforme explicado posteriormente.

NOTA: O GDBFuzz não se destina a fuzzar aplicações de usuário Linux. Use AFL++ ou outros fuzzers para isso. O wrapper existe apenas para fins de avaliação para permitir a execução de benchmarks e comparações em escala!

Instalar e executar em um contêiner Docker

A eficácia geral de nossa abordagem é demonstrada em um benchmark de grande escala implantado como contêineres Docker.

root@kitploit:~
make dockerimage

Para executar o experimento acima no contêiner Docker (por uma hora, conforme especificado no arquivo de configuração), mapeie as pastas example_programs e output como volumes e inicie o GDBFuzz da seguinte forma.

root@kitploit:~
chmod a+x ./example_programs/json-2017-02-12
docker run -it --env CONFIG_FILE=/example_programs/fuzz_json_docker_qemu.cfg -v $(pwd)/example_programs:/example_programs -v $(pwd)/output:/output gdbfuzz:1.0

Uma pasta de saída deve aparecer no diretório de trabalho atual com a estrutura explicada acima.

Instruções detalhadas

Nossa avaliação é dividida em duas partes.

  1. GDBFuzz em sua configuração pretendida, diretamente no hardware.
  2. GDBFuzz em um ambiente emulado para permitir análise independente e comparações dos resultados.

O GDBFuzz pode funcionar com qualquer servidor GDB e, portanto, com a maioria das sondas de depuração para microcontroladores.

GDBFuzz vs. Blackbox (RQ1)

Em relação à RQ1 do artigo, executamos o GDBFuzz em diferentes microcontroladores com diferentes firmwares localizados em example_firmware. Para cada experimento, executamos o GDBFuzz com a estratégia RandomBasicBlock e com a estratégia RandomBasicBlockNoCorpus. A segunda se comporta como fuzzing sem feedback, mas ainda podemos medir a cobertura alcançada. Para responder à RQ1, comparamos a cobertura alcançada da estratégia RandomBasicBlock e RandomBasicBlockNoCorpus. Os arquivos de configuração respectivos estão nas subpastas correspondentes e agora explicamos como configurar o fuzzing nas quatro placas de desenvolvimento.

GDBFuzz na placa STM32 B-L4S5I-IOT01A

O GDBFuzz requer acesso a um Servidor GDB. Neste caso, a placa B-L4S5I-IOT01A e seu depurador integrado são usados. Este depurador integrado configura um servidor GDB através do programa 'st-util' e permite acesso a este servidor GDB via localhost:4242.

  • Instale o driver STLINK link
  • Conecte a placa MCU e o PC via USB (na placa MCU, conecte ao conector USB rotulado como 'USB STLINK')
root@kitploit:~
sudo apt-get install stlink-tools gdb-multiarch

Compile e grave um firmware para o STM32 B-L4S5I-IOT01A, por exemplo o projeto arduinojson.

Pré-requisito: Instale platformio (pio)

root@kitploit:~
cd ./example_firmware/stm32_disco_arduinojson/
pio run --target upload

Para sua informação: o platformio armazena um arquivo .elf do SUT aqui: ./example_firmware/stm32_disco_arduinojson/.pio/build/disco_l4s5i_iot01a/firmware.elf Este arquivo .elf também é usado posteriormente na configuração do usuário para o Ghidra.

Inicie um novo terminal e execute o seguinte para iniciar o Servidor GDB:

root@kitploit:~
st-util

Execute o GDBFuzz com uma configuração de usuário para arduinojson. Podemos enviar dados pela porta USB para o microcontrolador. O microcontrolador encaminha esses dados via serial para o SUT. No nosso caso, /dev/ttyACM0 é o dispositivo USB para a placa microcontroladora. Se seu sistema atribuiu outro dispositivo à placa microcontroladora, altere /dev/ttyACM0 no arquivo de configuração para o seu dispositivo.

root@kitploit:~
./src/GDBFuzz/main.py --config ./example_firmware/stm32_disco_arduinojson/fuzz_serial_json.cfg

Estatísticas e logs do fuzzer estão no diretório ./output/...

GDBFuzz na placa CY8CKIT-062-WiFi-BT

Instale pyocd:

root@kitploit:~
pip install --upgrade pip 'mbed-ls>=1.7.1' 'pyocd>=0.16'

Certifique-se de que 'KitProg v3' esteja no dispositivo e coloque a placa no modo 'Arm DAPLink' pressionando o botão apropriado. Inicie o servidor GDB:

root@kitploit:~
pyocd gdbserver --persist

Grave um firmware e inicie o fuzzing, por exemplo, com

root@kitploit:~
gdb-multiarch
    target remote :3333
    load ./example_firmware/CY8CKIT_json/mtb-example-psoc6-uart-transmit-receive.elf
    monitor reset
./src/GDBFuzz/main.py --config ./example_firmware/CY8CKIT_json/fuzz_serial_json.cfg

GDBFuzz no ESP32 e Segger J-Link

  • Instale o ESP32 SDK

Compile e grave um firmware para o ESP32, por exemplo o exemplo arduinojson com platformio.

root@kitploit:~
cd ./example_firmware/esp32_arduinojson/
pio run --target upload

Adicione a seguinte linha ao arquivo de configuração do openocd para o depurador J-Link: jlink.cfg

root@kitploit:~
adapter speed 10000

Inicie um novo terminal e execute o seguinte para iniciar o Servidor GDB:

root@kitploit:~
get_idf
openocd -f interface/jlink.cfg -f target/esp32.cfg -c "telnet_port 7777" -c "gdb_port 8888"

Execute o GDBFuzz com uma configuração de usuário para arduinojson. Podemos enviar dados pela porta USB para o microcontrolador. O microcontrolador encaminha esses dados via serial para o SUT. No nosso caso, /dev/ttyUSB0 é o dispositivo USB para a placa microcontroladora. Se seu sistema atribuiu outro dispositivo à placa microcontroladora, altere /dev/ttyUSB0 no arquivo de configuração para o seu dispositivo.

root@kitploit:~
./src/GDBFuzz/main.py --config ./example_firmware/esp32_arduinojson/fuzz_serial.cfg

Estatísticas e logs do fuzzer estão no diretório ./output/...

GDBFuzz no MSP430F5529LP

Instale o TI MSP430 GCC em https://www.ti.com/tool/MSP430-GCC-OPENSOURCE

Inicie o Servidor GDB

root@kitploit:~
./gdb_agent_console libmsp430.so

ou (mais estável). Compile o mspdebug de https://github.com/dlbeer/mspdebug/ e use:

root@kitploit:~
until mspdebug --fet-skip-close --force-reset tilib "opt gdb_loop True" gdb ; do sleep 1 ; done

O Ghidra falha ao analisar binários para o controlador TI MSP430 imediatamente. Para corrigir isso, importamos o arquivo na GUI do Ghidra, escolhemos MSP430X como arquitetura e pulamos a análise automática. Em seguida, abrimos a 'Tabela de Símbolos', classificamos por nome e excluímos todos os símbolos com nomes como $C$L*. Agora a análise automática pode ser executada. Após a análise, inicie o bridge do ghidra manualmente a partir da GUI do Ghidra e então inicie o GDBFuzz.

root@kitploit:~
./src/GDBFuzz/main.py --config ./example_firmware/msp430_arduinojson/fuzz_serial.cfg

Fuzzing USB

Para acessar dispositivos USB como usuário não root com pyusb, adicionamos regras apropriadas ao udev. Cole as seguintes linhas em /etc/udev/rules.d/50-myusb.rules:

root@kitploit:~
SUBSYSTEM=="usb", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678" GROUP="usbusers", MODE="666"

Recarregue o udev:

root@kitploit:~
sudo udevadm control --reload
sudo udevadm trigger

Comparar com o Fuzzware (RQ2)

Na RQ2 do artigo, comparamos o GDBFuzz com a abordagem baseada em emulação Fuzzware. Primeiro executamos o GDBFuzz e o Fuzzware conforme descrito anteriormente nos arquivos de firmware fornecidos. Para cada experimento do GDBFuzz, criamos um arquivo com blocos básicos válidos a partir dos arquivos do grafo de fluxo de controle da seguinte forma:

root@kitploit:~
cut -d " " -f1 ./cfg > valid_bbs.txt

Agora podemos reproduzir a cobertura em relação ao resultado do fuzzware: fuzzware genstats --valid-bb-file valid_bbs.txt

Encontrando bugs (RQ3)

Quando entradas que causam falha ou travamento são encontradas, elas são armazenadas na pasta crashes. Durante a avaliação, encontramos os três bugs a seguir:

  1. Um loop infinito na pilha de dispositivos USB do STM32, causado pela contagem de uma variável de índice uint8_t para uma variável uint32_t controlável pelo atacante dentro de um loop for.
  2. Um estouro de buffer no analisador JSON da Cypress, causado pela falta de verificações de comprimento em um buffer interno de tamanho fixo.
  3. Uma desreferência de ponteiro nulo no analisador JSON da Cypress, causada pela falta de verificações de validação.

GDBFuzz em um Raspberry Pi 4a (8Gb)

O GDBFuzz também pode ser executado em um host Raspberry Pi com pequenas modificações:

  1. O Ghidra deve ser modificado para funcionar em um sistema operacional de 32 bits

No arquivo ./dependencies/ghidra/support/launch.sh:125 A variável JAVA_HOME deve ser codificada, por exemplo, para JAVA_HOME="/usr/lib/jvm/default-java"

  1. STLink deve estar na versão >= 1.7 para funcionar corretamente -> Compilar a partir das fontes

GDBFuzz em outras placas

Para fuzzar software em outras placas, o GDBFuzz requer:

  1. Um microcontrolador com pontos de interrupção de hardware e uma sonda de depuração compatível com GDB
  2. O arquivo de firmware.
  3. Um GDBServer em execução e uma aplicação GDB adequada.
  4. Um ponto de entrada onde o fuzzing deve começar, por exemplo, uma função de análise ou um endereço
  5. Uma interface de entrada (veja src/GDBFuzz/connections) que aciona a execução do código no ponto de entrada, por exemplo, conexão serial

Todas essas propriedades precisam ser especificadas no arquivo de configuração.

Executar o benchmark completo (RQ4 - 8)

Para as RQs 4 a 8, executamos um benchmark de grande escala. Primeiro, construa a imagem Docker conforme descrito anteriormente e compile aplicações do Fuzzer Test Suite do Google com nosso harness de fuzzing em benchmark/benchSUTs/GDBFuzz_wrapper/common.

root@kitploit:~
cd ./benchmark/benchSUTs
chmod a+x setup_benchmark_SUTs.py
make dockerbenchmarkimage

Em seguida, adapte as configurações do benchmark em benchmark/scripts/benchmark.py e benchmark/scripts/benchmark_aflpp.py às suas necessidades (especialmente number_of_cores, trials e seconds_per_trial) e inicie o benchmark com:

root@kitploit:~
cd ./benchmark/scripts
./benchmark.py $(pwd)/../benchSUTs/SUTs/ SUTs.json
./benchmark_aflpp.py $(pwd)/../benchSUTs/SUTs/ SUTs.json

Uma pasta aparece em ./benchmark/scripts que contém arquivos de plotagem (cobertura ao longo do tempo), arquivos de estatísticas do fuzzer e arquivos de grafo de fluxo de controle para cada experimento, como em evaluation/fuzzer_test_suite_qemu_runs.

[Opcional] Instalar visualização e exemplo de visualização

O GDBFuzz possui um recurso opcional onde ele plota o grafo de fluxo de controle dos nós cobertos. Isso está desabilitado por padrão. Você pode habilitá-lo seguindo as instruções desta seção e definindo 'enable_UI' como 'True' na configuração do usuário.

No host:

Instale

root@kitploit:~
sudo apt-get install graphviz

Instale uma versão recente de node, por exemplo Opção 2 de aqui. Use a Opção 2 e não a opção 1. Isso deve instalar tanto node quanto npm. Para referência, nossos números de versão são (mas versões mais novas também devem funcionar):

root@kitploit:~
➜ node --version
v16.9.1
➜ npm --version
7.21.1

Instale as dependências da interface web:

root@kitploit:~
cd ./src/webui
npm install

Instale o broker MQTT mosquitto, por exemplo, veja aqui

Atualize a configuração do broker mosquitto: Substitua o arquivo /etc/mosquitto/conf.d/mosquitto.conf pelo seguinte conteúdo:

root@kitploit:~
listener 1883
allow_anonymous true

listener 9001
protocol websockets

Reinicie o broker mosquitto:

root@kitploit:~
sudo service mosquitto restart

Verifique se o broker mosquitto está em execução:

root@kitploit:~
sudo service mosquitto status

A saída deve incluir o texto 'Active: active (running)'

Inicie a interface web:

root@kitploit:~
cd ./src/webui
npm start

Seu navegador web deve abrir automaticamente em 'http://localhost:3000/'.

Inicie o GDBFuzz e use um arquivo de configuração de usuário onde enable_UI está definido como True. Você pode usar o contêiner Docker e o SUT arduinojson acima. Mas certifique-se de definir 'enable_UI' como 'True'.

Os nós cobertos em 'azul' estão cobertos. Nós brancos não estão cobertos. Mostramos apenas nós não cobertos se seu pai estiver coberto (desenhar o grafo de fluxo de controle completo leva muito tempo se o grafo for grande).

Licença

O GDBFuzz é licenciado sob a licença AGPL-3.0. Consulte o arquivo LICENSE para obter detalhes.

Para uma lista de outros componentes de código aberto incluídos no GDBFuzz, consulte o arquivo 3rd-party-licenses.txt.

Baixar ferramenta