
Um Fuzzer de Motor JavaScript
Um fuzzer guiado por cobertura para interpretadores de linguagens dinâmicas, baseado em uma linguagem intermediária personalizada ("FuzzIL") que pode ser mutada e traduzida para JavaScript.
Os passos básicos para usar este fuzzer são:
swift build [-c release].swift run [-c release] FuzzilliCli --profile=<profile> [other cli options] /path/to/jsshell. Veja também swift run FuzzilliCli --help.Construir e executar o Fuzzilli e os mecanismos JavaScript suportados dentro do Docker e no Google Compute Engine também é suportado.
Confira main.swift para ver um exemplo de uso da biblioteca Fuzzilli e brincar com as várias opções de configuração. Em seguida, dê uma olhada em Fuzzer.swift para a lógica de fuzzing de alto nível. A partir daí, mergulhe em qualquer parte que pareça interessante.
Patches, adições e outras contribuições a este projeto são muito bem-vindas! No entanto, verifique rapidamente as notas para contribuidores. O Fuzzilli segue aproximadamente o guia de estilo de código do Google para Swift.
Seria muito apreciado se você pudesse enviar uma breve nota (possivelmente incluindo um número CVE) para [email protected] ou abrir um pull request para qualquer vulnerabilidade encontrada com a ajuda deste projeto, para que possa ser incluída na seção mostruário de bugs. Fora isso, você pode, claro, reivindicar qualquer recompensa por bug, créditos CVE, etc. pelas vulnerabilidades :)
Ao fazer fuzzing para bugs no núcleo do interpretador, por exemplo em compiladores JIT, a correção semântica dos programas gerados torna-se uma preocupação. Isso contrasta com a maioria dos outros cenários, por exemplo, fuzzing de APIs de tempo de execução, onde a correção semântica pode ser facilmente contornada envolvendo o código gerado em construções try-catch. Existem diferentes possibilidades para atingir uma taxa aceitável de amostras semanticamente corretas, uma delas sendo uma abordagem mutacional na qual todas as amostras no corpus também são semanticamente válidas. Nesse caso, cada mutação tem apenas uma pequena chance de transformar uma amostra válida em uma inválida.
Para implementar um fuzzer JavaScript baseado em mutação, mutações no código JavaScript precisam ser definidas. Em vez de mutar a AST ou outros elementos sintáticos de um programa, uma linguagem intermediária (IL) personalizada é definida, na qual mutações no fluxo de controle e dados de um programa podem ser realizadas mais diretamente. Esta IL é posteriormente traduzida para JavaScript para execução. A linguagem intermediária parece aproximadamente como a seguir:
v0 <− LoadInteger '0'
v1 <− LoadInteger '10'
v2 <− LoadInteger '1'
v3 <− LoadInteger '0'
BeginFor v0, '<', v1, '+', v2 −> v4
v6 <− BinaryOperation v3, '+', v4
Reassign v3, v6
EndFor
v7 <− LoadString 'Result: '
v8 <− BinaryOperation v7, '+', v3
v9 <− LoadGlobal 'console'
v10 <− CallMethod v9, 'log', [v8]
Que pode, por exemplo, ser traduzido trivialmente para o seguinte código JavaScript:
const v0 = 0;
const v1 = 10;
const v2 = 1;
let v3 = 0;
for (let v4 = v0; v4 < v1; v4 = v4 + v2) {
const v6 = v3 + v4;
v3 = v6;
}
const v7 = "Result: ";
const v8 = v7 + v3;
const v9 = console;
const v10 = v9.log(v8);
Ou para o seguinte código JavaScript, embutindo expressões intermediárias:
let v3 = 0;
for (let v4 = 0; v4 < 10; v4++) {
v3 = v3 + v4;
}
console.log("Result: " + v3);
O FuzzIL tem várias propriedades:
Reassign.Uma série de mutações pode então ser realizada nesses programas:
Uma discussão muito mais aprofundada de como o Fuzzilli funciona pode ser encontrada aqui.
O fuzzer é implementado em Swift, com algumas partes (por exemplo, medições de cobertura, interações de socket, etc.) implementadas em C.
Uma instância do fuzzer (implementada em Fuzzer.swift) é composta pelos seguintes componentes centrais: