
Fuzzer de DOM
Escrito e mantido por Ivan Fratric, [email protected]
Copyright 2017 Google Inc. Todos os direitos reservados.
Licenciado sob a Apache License, Versão 2.0 (a "Licença"); você não pode usar este arquivo exceto em conformidade com a Licença. Você pode obter uma cópia da Licença em
http://www.apache.org/licenses/LICENSE-2.0
A menos que exigido pela lei aplicável ou acordado por escrito, o software distribuído sob a Licença é distribuído numa base "COMO ESTÁ", SEM GARANTIAS OU CONDIÇÕES DE QUALQUER TIPO, expressas ou implícitas. Consulte a Licença para obter as permissões e limitações específicas que regem o uso deste software.
Para ver as informações de uso, execute o seguinte comando:
python3 generator.py --help
Para gerar uma única amostra .html, execute:
python generator.py --file <output file>
Para gerar uma única amostra .html usando um modelo que você escreveu:
python generator.py --file <output file> --template <your custom template file>
Para gerar várias amostras com uma única chamada, execute:
python generator.py --output_dir <output directory> --no_of_files <number of output files>
As amostras geradas serão colocadas no diretório especificado e serão nomeadas como fuzz-<number>.html, por exemplo, fuzz-00001.html, fuzz-00002.html etc. Gerar várias amostras é mais rápido porque os arquivos de gramática de entrada precisam ser carregados e analisados apenas uma vez.
O generator.py contém o script principal. Ele usa grammar.py como biblioteca e contém código auxiliar adicional para fuzzing de DOM.
O grammar.py contém o mecanismo de geração, que é em grande parte independente de aplicação e, portanto, pode ser usado em outros fuzzers baseados em geração (ou seja, não-DOM). Como pode ser usado como biblioteca, seu uso é descrito em uma seção separada abaixo.
Os arquivos .txt contêm definições de gramática. Há 3 arquivos principais, html.txt, css.txt e js.txt, que contêm as gramáticas de HTML, CSS e JavaScript, respectivamente. Esses arquivos de gramática raiz podem incluir conteúdo de outros arquivos.
Para usar o mecanismo de geração com uma gramática personalizada, você pode usar o seguinte código Python:
from grammar import Grammar
my_grammar = Grammar()
my_grammar.parse_from_file('input_file.txt')
result_string = my_grammar.generate_symbol('symbol_name')
As seções a seguir descrevem a sintaxe dos arquivos de gramática.
O Domato é baseado em um mecanismo que, dada uma gramática livre de contexto em um formato simples especificado abaixo, gera amostras a partir dessa gramática.
Uma gramática é descrita como um conjunto de regras no seguinte formato básico:
<symbol> = a mix of constants and <other_symbol>s
Cada regra de gramática contém um lado esquerdo e um lado direito separados pelo caractere de igual. O lado esquerdo contém um símbolo, enquanto o lado direito contém os detalhes de como esse símbolo pode ser expandido. Ao expandir um símbolo, todos os símbolos no lado direito são expandidos recursivamente, enquanto tudo o que não é um símbolo é simplesmente copiado para a saída. Observe que uma única regra não pode abranger várias linhas do arquivo de entrada.
Considere o seguinte exemplo simplificado de uma parte da gramática CSS:
<cssrule> = <selector> { <declaration> }
<selector> = a
<selector> = b
<declaration> = width:100%
Se instruirmos o mecanismo de gramática a analisar essa gramática e gerar 'cssrule', podemos obter:
a { width:100% }
ou
b { width:100% }
Observe que há duas regras para o símbolo 'selector'. Nesses casos, quando o gerador é solicitado a gerar um 'selector', ele seleciona a regra a ser usada aleatoriamente. Também é possível especificar a probabilidade da regra usando o atributo 'p', por exemplo:
<selector p=0.9> = a
<selector p=0.1> = b
Nesse caso, a string 'a' seria emitida com mais frequência do que 'b'.
Além da probabilidade, há outros atributos que podem ser aplicados aos símbolos. Eles estão listados em uma seção separada.
Considere outro exemplo para gerar amostras html:
<html> = <lt>html<gt><head><body><lt>/html<gt>
<head> = <lt>head<gt>...<lt>/head<gt>
<body> = <lt>body<gt>...<lt>/body<gt>
Observe que, como '<' e '>' têm um significado especial na sintaxe da gramática, aqui usamos <lt> e <gt> em seu lugar. Esses símbolos são internos e não precisam ser definidos pelo usuário. Uma lista de todos os símbolos internos é fornecida em uma seção separada.
Para gerar código de linguagem de programação, uma sintaxe semelhante pode ser usada, mas há algumas diferenças. Cada linha da gramática da linguagem de programação corresponderá a uma linha da saída. Por isso, a sintaxe da gramática será mais livre, permitindo expressar construções em várias linguagens de programação. Em segundo lugar, quando uma linha é gerada, além de emitir a linha, uma ou mais variáveis podem ser criadas e essas variáveis podem ser reutilizadas ao gerar outras linhas. Novamente, vejamos o exemplo simplificado:
!varformat fuzzvar%05d
!lineguard try { <line> } catch(e) {}
!begin lines
<new element> = document.getElementById("<string min=97 max=122>");
<element>.doSomething();
!end lines
Se instruirmos o mecanismo a gerar 5 linhas, podemos obter algo como:
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) {}
Observe que
<new element> em vez de <element>. Isso instrui o gerador a criar uma nova variável do tipo 'element' em vez de gerar o símbolo 'element'.<string> é um dos símbolos internos, portanto não é necessário defini-lo.Tudo após o primeiro caractere '#' na linha é considerado um comentário, por exemplo:
#This is a comment
A sintaxe da gramática tem uma maneira de informar ao fuzzer quais regras são não recursivas e podem ser usadas com segurança mesmo quando o nível máximo de recursão é atingido. Isso é feito com o atributo 'nonrecursive'. Um exemplo é dado abaixo.
!max_recursion 10
<test root=true> = <foobar>
<foobar> = foo<foobar>
<foobar nonrecursive> = bar
Primeiramente, uma declaração opcional '!max_recursion' define o nível máximo de profundidade de recursão (50 por padrão). Observe que a segunda regra de produção para 'foobar' é marcada como não recursiva. Se o nível máximo de recursão for atingido, o gerador forçará o uso da regra não recursiva para o símbolo 'foobar', evitando assim a recursão infinita.