
Un fuzzer de moteur JavaScript
Un fuzzer guidé par la couverture de code pour les interpréteurs de langages dynamiques basé sur un langage intermédiaire personnalisé ("FuzzIL") qui peut être muté et traduit en JavaScript.
Les étapes de base pour utiliser ce fuzzer sont :
swift build [-c release].swift run [-c release] FuzzilliCli --profile=<profile> [autres options cli] /chemin/vers/jsshell. Voir aussi swift run FuzzilliCli --help.La construction et l'exécution de Fuzzilli et des moteurs JavaScript pris en charge dans Docker et sur Google Compute Engine sont également supportées.
Consultez main.swift pour voir un exemple d'utilisation de la bibliothèque Fuzzilli et jouer avec les différentes options de configuration. Ensuite, jetez un œil à Fuzzer.swift pour la logique de fuzzing de haut niveau. De là, plongez dans toute partie qui vous semble intéressante.
Les correctifs, ajouts, autres contributions, etc. à ce projet sont très bienvenus ! Cependant, veuillez rapidement consulter les notes pour les contributeurs. Fuzzilli suit approximativement le guide de style de code de Google pour Swift.
Il serait grandement apprécié que vous envoyiez une courte note (incluant éventuellement un numéro CVE) à [email protected] ou ouvriez une pull request pour toute vulnérabilité découverte avec l'aide de ce projet afin qu'elle puisse être incluse dans la section démonstration de bogues. Autrement, vous pouvez bien sûr réclamer toute prime de bogue, crédits CVE, etc. pour les vulnérabilités :)
Lors du fuzzing pour des bogues de cœur d'interpréteur, par exemple dans les compilateurs JIT, la correction sémantique des programmes générés devient une préoccupation. Cela contraste avec la plupart des autres scénarios, par exemple le fuzzing des API d'exécution, où la correction sémantique peut facilement être contournée en enveloppant le code généré dans des constructions try-catch. Il existe différentes possibilités pour atteindre un taux acceptable d'échantillons sémantiquement corrects, dont l'une est une approche mutationnelle où tous les échantillons du corpus sont également sémantiquement valides. Dans ce cas, chaque mutation a seulement une faible chance de transformer un échantillon valide en un échantillon invalide.
Pour implémenter un fuzzer JavaScript basé sur les mutations, il faut définir des mutations du code JavaScript. Au lieu de muter l'AST ou d'autres éléments syntaxiques d'un programme, un langage intermédiaire personnalisé (IL) est défini sur lequel les mutations du flux de contrôle et de données d'un programme peuvent être effectuées plus directement. Cet IL est ensuite traduit en JavaScript pour exécution. Le langage intermédiaire ressemble approximativement à ceci :
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]
Qui peut par exemple être trivialement traduit en code JavaScript suivant :
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 au code JavaScript suivant en inlineant les expressions intermédiaires :
let v3 = 0;
for (let v4 = 0; v4 < 10; v4++) {
v3 = v3 + v4;
}
console.log("Result: " + v3);
FuzzIL a un certain nombre de propriétés :
Reassign.Un certain nombre de mutations peuvent ensuite être effectuées sur ces programmes :
Une discussion beaucoup plus approfondie sur le fonctionnement de Fuzzilli peut être trouvée ici.
Le fuzzer est implémenté en Swift, avec certaines parties (par exemple les mesures de couverture, les interactions socket, etc.) implémentées en C.
Une instance de fuzzer (implémentée dans Fuzzer.swift) est composée des composants centraux suivants :