
Un fuzzer de motores JavaScript
Un fuzzer guiado por cobertura para intérpretes de lenguajes dinámicos basado en un lenguaje intermedio personalizado ("FuzzIL") que puede ser mutado y traducido a JavaScript.
Los pasos básicos para usar este fuzzer son:
swift build [-c release].swift run [-c release] FuzzilliCli --profile=<profile> [other cli options] /path/to/jsshell. Consulta también swift run FuzzilliCli --help.La compilación y ejecución de Fuzzilli y los motores JavaScript compatibles dentro de Docker y en Google Compute Engine también es compatible.
Revisa main.swift para ver un ejemplo de uso de la librería Fuzzilli y juega con las diversas opciones de configuración. Luego, echa un vistazo a Fuzzer.swift para la lógica de fuzzing de alto nivel. A partir de ahí, sumérgete en cualquier parte que parezca interesante.
¡Los parches, adiciones, otras contribuciones, etc. a este proyecto son muy bienvenidos! Sin embargo, revisa rápidamente las notas para contribuyentes. Fuzzilli sigue aproximadamente la guía de estilo de código de Google para swift.
Se agradecería mucho si pudieras enviar una nota breve (posiblemente incluyendo un número CVE) a [email protected] o abrir un pull request por cualquier vulnerabilidad encontrada con la ayuda de este proyecto para que pueda ser incluida en la sección bug showcase. Aparte de eso, por supuesto puedes reclamar cualquier recompensa por errores, créditos CVE, etc. por las vulnerabilidades :)
Al fuzzear para encontrar errores en el núcleo del intérprete, por ejemplo en compiladores JIT, la corrección semántica de los programas generados se convierte en una preocupación. Esto contrasta con la mayoría de otros escenarios, por ejemplo, fuzzear APIs de tiempo de ejecución, donde la corrección semántica se puede sortear fácilmente envolviendo el código generado en construcciones try-catch. Hay diferentes posibilidades para lograr una tasa aceptable de muestras semánticamente correctas, una de ellas es un enfoque mutacional en el que todas las muestras en el corpus también son semánticamente válidas. En ese caso, cada mutación solo tiene una pequeña probabilidad de convertir una muestra válida en una inválida.
Para implementar un fuzzer JavaScript basado en mutaciones, es necesario definir mutaciones al código JavaScript. En lugar de mutar el AST u otros elementos sintácticos de un programa, se define un lenguaje intermedio personalizado (IL) sobre el cual se pueden realizar mutaciones al flujo de control y datos de un programa de manera más directa. Este IL luego se traduce a JavaScript para su ejecución. El lenguaje intermedio tiene aproximadamente el siguiente aspecto:
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 puede, por ejemplo, traducirse trivialmente al siguiente 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);
O al siguiente código JavaScript mediante la inserción de expresiones intermedias:
let v3 = 0;
for (let v4 = 0; v4 < 10; v4++) {
v3 = v3 + v4;
}
console.log("Result: " + v3);
FuzzIL tiene varias propiedades:
Reassign.Se pueden realizar varias mutaciones en estos programas:
Se puede encontrar una discusión mucho más detallada sobre cómo funciona Fuzzilli aquí.
El fuzzer está implementado en Swift, con algunas partes (por ejemplo, mediciones de cobertura, interacciones de socket, etc.) implementadas en C.
Una instancia del fuzzer (implementada en Fuzzer.swift) está compuesta por los siguientes componentes centrales: