
A linux system call fuzzer using TriforceAFL
Novo: Para aqueles que procuram experimentar o TriforceAFL e o TLSF, Richard Johnson criou um Dockerfile que instala ambos (e até compila um kernel Linux para você). Está disponível aqui https://hub.docker.com/r/moflow/afl-triforce/tags/.
Esta é uma coleção de arquivos usados para realizar fuzzing
de chamadas de sistema em kernels Linux x86_64 usando AFL e QEMU. Para usá-lo,
você precisará do TriforceAFL de https://github.com/nccgroup/TriforceAFL
e de uma imagem de kernel para fuzzing. Os scripts assumem que o TriforceAFL está
em $TAFL ou ../TriforceAFL/ (N.B. compilar testAfl requer
que ../TriforceAFL/config.h exista).
Para compilar:
make
Para executar, primeiro instale um kernel em ./kern/bzImage e
extraia /proc/kallsyms
para ./kern/kallsyms. Defina a variável de ambiente K=kern para apontar para
o seu kernel. Agora execute:
make inputs
./runFuzz -M M0
Observe que o script runFuzz espera um nome de mestre ou escravo, pois
sempre executa no modo mestre/escravo. Consulte o script runFuzz para
mais informações de uso.
Observe também que isso cria apenas um pequeno conjunto de exemplos de entradas. Para testar
um grande número de chamadas de sistema importantes, você provavelmente vai querer
gerar um exemplo de cada chamada de sistema, ou pelo menos um exemplo
para cada "formato" de chamada de sistema. Eles devem ser colocados em inputs/.
Veja gen2.py para um exemplo.
Para reproduzir casos de teste (como crashes) execute:
./runTest inputs/ex1
./runTest outputs/crashes/id*
Você também pode executar o driver fora do ambiente emulado
com a opção -t, com registro detalhado com -vv
e sem realmente realizar as chamadas de sistema com -x:
./driver -tvvx < inputs/ex1
strace ./driver -t < inputs/ex1
Às vezes é útil poder inicializar o kernel e executar testes interativamente. Para fazer isso, edite os arquivos rootTemplate como preferir (por exemplo, para adicionar mais ferramentas de teste ao sistema de arquivos raiz) e então execute:
./runCmd
Outros comandos além do shell podem ser invocados especificando-os
como argumentos de linha de comando para runCmd.
Nota: ao terminar com o shell, use ^A-c para obter o prompt do QEMU
e digite quit.
A depuração é mais fácil com um kernel compilado com símbolos de depuração habilitados.
Use runTest para iniciar o kernel e executar um teste através do
driver, ou use runCmd para executar manualmente um caso de teste a partir do shell.
Edite seu script de execução para incluir a opção -s ao iniciar afl-qemu-system-trace.
Isso habilitará o suporte a gdb na porta TCP 1234. Use getvmlinux para extrair
a imagem do kernel vmlinux do seu kernel bzImage e execute gdb depois
que o sistema inicializar:
cp kern/bzImage .
./getvmlinux
gdb ./vmlinux
target remote :1234
break somefunction
continue
Você pode anexar o depurador depois que runTest causar um crash
ou antes de acionar manualmente o bug no runCmd.
Observe que os fontes do Linux são compilados com otimização ativada
por padrão. Isso pode tornar a depuração confusa e difícil.
Você pode desativar a otimização arquivo por arquivo
editando o makefile do Linux para o subdiretório em que um arquivo está
e adicionando CFLAGS_name.o = -O0 ao Makefile. Por
exemplo, editar kernel/Makefile e adicionar CFLAGS_sys_ni.o = -O0
desativará a otimização ao compilar kernel/sys_ni.o.
O script de shell getSyms usa runCmd para executar cat /proc/kallsyms
e extraí-lo para um arquivo local chamado kallsyms. Isso é tipicamente
usado para preparar seu kernel para fuzzing:
K=yourKernDir ./getSyms para obter kallsymsmv kallsyms yourKernDir para instalá-loNota: Ao fazer fuzzing em um kernel Linux 2., você precisará habilitar
o temporizador da CPU. Quando o temporizador não está habilitado, a detecção
de pânico e registro não parece operar corretamente e pânicos resultam
em travamentos. Para habilitar o temporizador, chame startForkserver(1) em
driver.c em vez de startForkserver(0). Esse problema
não parece ocorrer em kernels Linux 3. e Linux 4.*.