
Ein grammatikbasierter Feedback-Fuzzer
Nautilus ist ein coverage-gesteuerter, grammatikbasierter Fuzzer. Sie können ihn nutzen, um Ihre Testabdeckung zu verbessern und mehr Fehler zu finden. Durch die Angabe der Grammatik semi-gültiger Eingaben ist Nautilus in der Lage, komplexe Mutationen durchzuführen und interessantere Testfälle aufzudecken. Viele der Ideen hinter diesem Fuzzer sind in einem Paper dokumentiert, das auf der NDSS 2019 veröffentlicht wurde.
Version 2.0 hat viele Verbesserungen an diesem frühen Prototypen vorgenommen und ist jetzt 100 % kompatibel mit AFL++. Neben allgemeinen Benutzerfreundlichkeitsverbesserungen enthält Version 2.0 viele tolle neue Funktionen:
Sie spezifizieren eine Grammatik mit Regeln wie EXPR -> EXPR + EXPR oder EXPR -> NUM und NUM -> 1. Aus diesen Regeln konstruiert der Fuzzer einen Baum. Diese interne Repräsentation erlaubt es, viel komplexere Mutationen anzuwenden als bei rohen Bytes. Dieser Baum wird dann in eine echte Eingabe für die Zielanwendung umgewandelt. In normalen kontextfreien Grammatiken ist dieser Prozess unkompliziert: Alle Blätter werden konkateniert. Der linke Baum im folgenden Beispiel würde zur Eingabe a=1+2 umgeformt und der rechte zu a=1+1+1+2. Um die Ausdruckskraft Ihrer Grammatiken zu erhöhen, können Sie mit Nautilus Python-Funktionen für den Unparsing-Prozess bereitstellen, um viel komplexere Spezifikationen zu ermöglichen.
# checkout the git
git clone '[email protected]:nautilus-fuzz/nautilus.git'
cd nautilus
/path/to/AFLplusplus/afl-clang-fast test.c -o test #afl-clang-fast as provided by AFL
# all arguments can also be set using the config.ron file
cargo run --release -- -g grammars/grammar_py_example.py -o /tmp/workdir -- ./test @@
# or if you want to use QEMU mode:
cargo run /path/to/AFLplusplus/afl-qemu-trace -- ./test_bin @@
Hier verwenden wir Python, um eine Grammatik für gültige XML-ähnliche Eingaben zu generieren. Beachten Sie die Verwendung einer Skriptregel, um sicherzustellen, dass die öffnenden und schließenden Tags übereinstimmen.
#ctx.rule(NONTERM: string, RHS: string|bytes) adds a rule NONTERM->RHS. We can use {NONTERM} in the RHS to request a recursion.
ctx.rule("START","<document>{XML_CONTENT}</document>")
ctx.rule("XML_CONTENT","{XML}{XML_CONTENT}")
ctx.rule("XML_CONTENT","")
#ctx.script(NONTERM:string, RHS: [string]], func) adds a rule NONTERM->func(*RHS).
# In contrast to normal `rule`, RHS is an array of nonterminals.
# It's up to the function to combine the values returned for the NONTERMINALS with any fixed content used.
ctx.script("XML",["TAG","ATTR","XML_CONTENT"], lambda tag,attr,body: b"<%s %s>%s</%s>"%(tag,attr,body,tag) )
ctx.rule("ATTR","foo=bar")
ctx.rule("TAG","some_tag")
ctx.rule("TAG","other_tag")
#sometimes we don't want to explore the set of possible inputs in more detail. For example, if we fuzz a script
#interpreter, we don't want to spend time on fuzzing all different variable names. In such cases we can use Regex
#terminals. Regex terminals are only mutated during generation, but not during normal mutation stages, saving a lot of time.
#The fuzzer still explores different values for the regex, but it won't be able to learn interesting values incrementally.
#Use this when incremantal exploration would most likely waste time.
ctx.regex("TAG","[a-z]+")
Um Ihre Grammatiken zu testen, können Sie den Generator verwenden:
$ cargo run --bin generator -- -g grammars/grammar_py_exmaple.py -t 100
<document><some_tag foo=bar><other_tag foo=bar><other_tag foo=bar><some_tag foo=bar></some_tag></other_tag><some_tag foo=bar><other_tag foo=bar></other_tag></some_tag><other_tag foo=bar></other_tag><some_tag foo=bar></some_tag></other_tag><other_tag foo=bar></other_tag><some_tag foo=bar></some_tag></some_tag></document>
Sie können Nautilus auch in Kombination mit AFL verwenden. Geben Sie einfach AFL -o auf das gleiche Arbeitsverzeichnis, und AFL wird sich mit Nautilus synchronisieren. Beachten Sie, dass dies eine Einbahnstraße ist. AFL importiert Nautilus-Eingaben, aber nicht umgekehrt.
#Terminal/Screen 1
./afl-fuzz -Safl -i /tmp/seeds -o /tmp/workdir/ ./test @@
#Terminal/Screen 2
cargo run --release -- -o /tmp/workdir -- ./test @@