
Fuzzer DOM
Scritto e mantenuto da Ivan Fratric, [email protected]
Copyright 2017 Google Inc. Tutti i diritti riservati.
Concesso in licenza secondo l'Apache License, Versione 2.0 (la "Licenza"); non è consentito usare questo file se non in conformità con la Licenza. È possibile ottenere una copia della Licenza al seguente indirizzo:
http://www.apache.org/licenses/LICENSE-2.0
Salvo quanto previsto dalla legge applicabile o concordato per iscritto, il software distribuito nell'ambito della Licenza è distribuito "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o implicite. Consultare la Licenza per il linguaggio specifico che disciplina i permessi e le limitazioni previsti dalla Licenza.
Per visualizzare le informazioni sull'utilizzo eseguire il seguente comando:
python3 generator.py --help
Per generare un singolo campione .html eseguire:
python generator.py --file <output file>
Per generare un singolo campione .html usando un template da te creato eseguire:
python generator.py --file <output file> --template <your custom template file>
Per generare più campioni con una singola chiamata eseguire:
python generator.py --output_dir <output directory> --no_of_files <number of output files>
I campioni generati verranno inseriti nella directory specificata e saranno denominati fuzz-<numero>.html, ad esempio fuzz-00001.html, fuzz-00002.html, ecc. La generazione di più campioni è più veloce perché i file di grammatica di input devono essere caricati e analizzati una sola volta.
generator.py contiene lo script principale. Utilizza grammar.py come libreria e contiene ulteriore codice di supporto per il fuzzing del DOM.
grammar.py contiene il motore di generazione che è in gran parte indipendente dall'applicazione e può quindi essere utilizzato in altri fuzzer basati sulla generazione (cioè non-DOM). Poiché può essere usato come libreria, il suo utilizzo è descritto in una sezione separata più avanti.
I file .txt contengono le definizioni delle grammatiche. Ci sono 3 file principali: html.txt, css.txt e js.txt, che contengono rispettivamente le grammatiche HTML, CSS e JavaScript. Questi file di grammatica radice possono includere contenuti da altri file.
Per utilizzare il motore di generazione con una grammatica personalizzata, si può usare il seguente codice Python:
from grammar import Grammar
my_grammar = Grammar()
my_grammar.parse_from_file('input_file.txt')
result_string = my_grammar.generate_symbol('symbol_name')
Le sezioni seguenti descrivono la sintassi dei file di grammatica.
Domato si basa su un motore che, data una grammatica context-free nel semplice formato specificato sotto, genera campioni da quella grammatica.
Una grammatica è descritta come un insieme di regole nel seguente formato di base:
<symbol> = a mix of constants and <other_symbol>s
Ogni regola grammaticale contiene un lato sinistro e un lato destro separati dal carattere uguale. Il lato sinistro contiene un simbolo, mentre il lato destro contiene i dettagli su come quel simbolo può essere espanso. Quando si espande un simbolo, tutti i simboli sul lato destro vengono espansi ricorsivamente, mentre tutto ciò che non è un simbolo viene semplicemente copiato nell'output. Si noti che una singola regola non può estendersi su più righe del file di input.
Consideriamo il seguente esempio semplificato di una parte della grammatica CSS:
<cssrule> = <selector> { <declaration> }
<selector> = a
<selector> = b
<declaration> = width:100%
Se istruiamo il motore grammaticale ad analizzare questa grammatica e a generare 'cssrule', potremmo ottenere:
a { width:100% }
oppure
b { width:100% }
Si noti che ci sono due regole per il simbolo 'selector'. In questi casi, quando al generatore viene chiesto di generare un 'selector', sceglierà la regola da usare in modo casuale. È anche possibile specificare la probabilità della regola usando l'attributo 'p', per esempio:
<selector p=0.9> = a
<selector p=0.1> = b
In questo caso, la stringa 'a' verrebbe emessa più spesso di 'b'.
Oltre alla probabilità, ci sono altri attributi che possono essere applicati ai simboli. Questi sono elencati in una sezione separata.
Consideriamo un altro esempio per generare campioni HTML:
<html> = <lt>html<gt><head><body><lt>/html<gt>
<head> = <lt>head<gt>...<lt>/head<gt>
<body> = <lt>body<gt>...<lt>/body<gt>
Si noti che, poiché '<' e '>' hanno un significato speciale nella sintassi delle grammatiche, qui usiamo <lt> e <gt> al loro posto. Questi simboli sono integrati e non devono essere definiti dall'utente. Un elenco di tutti i simboli integrati è fornito in una sezione separata.
Per generare codice di linguaggi di programmazione si può usare una sintassi simile, ma ci sono alcune differenze. Ogni riga della grammatica del linguaggio di programmazione corrisponderà a una riga dell'output. Per questo motivo, la sintassi della grammatica sarà più libera, per consentire di esprimere costrutti in vari linguaggi di programmazione. In secondo luogo, quando viene generata una riga, oltre a emettere la riga, possono essere create una o più variabili e queste variabili possono essere riutilizzate nella generazione di altre righe. Di nuovo, guardiamo l'esempio semplificato:
!varformat fuzzvar%05d
!lineguard try { <line> } catch(e) {}
!begin lines
<new element> = document.getElementById("<string min=97 max=122>");
<element>.doSomething();
!end lines
Se istruiamo il motore a generare 5 righe, potremmo ottenere qualcosa come:
try { var00001 = document.getElementById("hw"); } catch(e) {}
try { var00001.doSomething(); } catch(e) {}
try { var00002 = document.getElementById("feezcqbndf"); } catch(e) {}
try { var00002.doSomething(); } catch(e) {}
try { var00001.doSomething(); } catch(e) {}
Si noti che
<new element> invece di <element>. Questo istruisce il generatore a creare una nuova variabile di tipo 'element' invece di generare il simbolo 'element'.<string> è uno dei simboli integrati, quindi non è necessario definirlo.Tutto ciò che segue il primo carattere '#' nella riga è considerato un commento, per esempio:
#This is a comment
La sintassi delle grammatiche offre un modo per indicare al fuzzer quali regole sono non ricorsive e possono essere usate in sicurezza anche quando è stato raggiunto il livello massimo di ricorsione. Questo viene fatto con gli attributi 'nonrecursive'. Un esempio è riportato di seguito.
!max_recursion 10
<test root=true> = <foobar>
<foobar> = foo<foobar>
<foobar nonrecursive> = bar