
DOM-фаззер
Автор и сопровождающий: Ivan Fratric, [email protected]
Copyright 2017 Google Inc. All Rights Reserved.
Лицензировано в соответствии с Apache License, Version 2.0 (далее — «Лицензия»); вы не можете использовать этот файл иначе как в соответствии с Лицензией. Копию Лицензии можно получить по адресу:
http://www.apache.org/licenses/LICENSE-2.0
Если это не требуется применимым законодательством или не согласовано в письменной форме, программное обеспечение, распространяемое в соответствии с Лицензией, предоставляется на условиях «AS IS» («КАК ЕСТЬ»), БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ ИЛИ УСЛОВИЙ, явных или подразумеваемых. См. Лицензию для получения информации о разрешениях и ограничениях.
Чтобы увидеть информацию об использовании, выполните следующую команду:
python3 generator.py --help
Для генерации одного .html-примера выполните:
python generator.py --file <output file>
Для генерации одного .html-примера с использованием написанного вами шаблона выполните:
python generator.py --file <output file> --template <your custom template file>
Для генерации нескольких примеров одним вызовом выполните:
python generator.py --output_dir <output directory> --no_of_files <number of output files>
Сгенерированные примеры будут помещены в указанный каталог и названы fuzz-<number>.html, например fuzz-00001.html, fuzz-00002.html и т. д. Генерация нескольких примеров происходит быстрее, поскольку файлы входной грамматики нужно загрузить и разобрать только один раз.
generator.py содержит основной скрипт. Он использует grammar.py как библиотеку и содержит дополнительный вспомогательный код для фаззинга DOM.
grammar.py содержит движок генерации, который в основном независим от конкретного приложения и поэтому может использоваться в других (то есть не-DOM) генерационных фаззерах. Поскольку его можно использовать как библиотеку, его использование описано в отдельном разделе ниже.
Файлы .txt содержат определения грамматики. Есть 3 основных файла: html.txt, css.txt и js.txt, которые содержат грамматики HTML, CSS и JavaScript соответственно. Эти корневые файлы грамматики могут включать содержимое из других файлов.
Чтобы использовать движок генерации с пользовательской грамматикой, вы можете использовать следующий код Python:
from grammar import Grammar
my_grammar = Grammar()
my_grammar.parse_from_file('input_file.txt')
result_string = my_grammar.generate_symbol('symbol_name')
В следующих разделах описан синтаксис файлов грамматики.
Domato основан на движке, который, получив контекстно-свободную грамматику в простом формате, указанном ниже, генерирует примеры на основе этой грамматики.
Грамматика описывается как набор правил в следующем базовом формате:
<symbol> = смесь констант и <other_symbol>
Каждое правило грамматики содержит левую и правую части, разделённые знаком равенства. Левая часть содержит символ, а правая часть — сведения о том, как этот символ может быть развёрнут. При разворачивании символа все символы в правой части разворачиваются рекурсивно, а всё, что не является символом, просто копируется в выходные данные. Обратите внимание, что одно правило не может занимать несколько строк входного файла.
Рассмотрим следующий упрощённый пример части грамматики CSS:
<cssrule> = <selector> { <declaration> }
<selector> = a
<selector> = b
<declaration> = width:100%
Если мы укажем движку грамматики разобрать эту грамматику и сгенерировать 'cssrule', мы можем получить либо:
a { width:100% }
либо
b { width:100% }
Обратите внимание, что для символа 'selector' есть два правила. В таких случаях, когда генератору требуется сгенерировать 'selector', он выберет правило для использования случайным образом. Также можно указать вероятность правила с помощью атрибута 'p', например:
<selector p=0.9> = a
<selector p=0.1> = b
В этом случае строка 'a' будет выводиться чаще, чем 'b'.
Помимо вероятности, к символам можно применять и другие атрибуты. Они перечислены в отдельном разделе.
Рассмотрим ещё один пример для генерации HTML-примеров:
<html> = <lt>html<gt><head><body><lt>/html<gt>
<head> = <lt>head<gt>...<lt>/head<gt>
<body> = <lt>body<gt>...<lt>/body<gt>
Обратите внимание, что символы '<' и '>' имеют специальное значение в синтаксисе грамматики, поэтому здесь мы используем <lt> и <gt> вместо них. Эти символы встроены и не требуют определения пользователем. Список всех встроенных символов приведён в отдельном разделе.
Для генерации кода на языках программирования можно использовать похожий синтаксис, но есть несколько отличий. Каждая строка грамматики языка программирования будет соответствовать строке выходных данных. Из-за этого синтаксис грамматики будет более свободным, чтобы можно было выражать конструкции на различных языках программирования. Во-вторых, когда строка генерируется, помимо вывода самой строки могут создаваться одна или несколько переменных, и эти переменные могут повторно использоваться при генерации других строк. Опять же, давайте посмотрим на упрощённый пример:
!varformat fuzzvar%05d
!lineguard try { <line> } catch(e) {}
!begin lines
<new element> = document.getElementById("<string min=97 max=122>");
<element>.doSomething();
!end lines
Если мы укажем движку сгенерировать 5 строк, мы можем получить что-то вроде:
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) {}
Обратите внимание, что
<new element> вместо <element>. Это указывает генератору создать новую переменную типа 'element' вместо генерации символа 'element'.<string> — один из встроенных символов, поэтому его не нужно определять.Всё после первого символа '#' в строке считается комментарием, например:
#This is a comment
Синтаксис грамматики позволяет указать фаззеру, какие правила являются нерекурсивными и могут безопасно использоваться, даже если достигнут максимальный уровень рекурсии. Это делается с помощью атрибута ‘nonrecursive’. Пример приведён ниже.
!max_recursion 10
<test root=true> = <foobar>
<foobar> = foo<foobar>
<foobar nonrecursive> = bar