{"id":13842930,"url":"https://github.com/AFLplusplus/Grammar-Mutator","last_synced_at":"2025-07-11T17:32:22.321Z","repository":{"id":45323984,"uuid":"261392188","full_name":"AFLplusplus/Grammar-Mutator","owner":"AFLplusplus","description":"A grammar-based custom mutator for AFL++","archived":false,"fork":false,"pushed_at":"2024-06-28T14:32:56.000Z","size":566,"stargazers_count":254,"open_issues_count":7,"forks_count":19,"subscribers_count":7,"default_branch":"stable","last_synced_at":"2025-07-10T16:43:42.175Z","etag":null,"topics":["afl","afl-fuzz","aflplusplus","fuzzing","grammar-fuzzer"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AFLplusplus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-05T07:45:57.000Z","updated_at":"2025-07-07T17:53:51.000Z","dependencies_parsed_at":"2024-01-20T03:03:51.939Z","dependency_job_id":"69ceed11-74bf-465a-9078-dac57ec83434","html_url":"https://github.com/AFLplusplus/Grammar-Mutator","commit_stats":{"total_commits":272,"total_committers":9,"mean_commits":30.22222222222222,"dds":"0.16176470588235292","last_synced_commit":"05d8f537f8d656f0754e7ad5dcc653c42cb4f8ff"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AFLplusplus/Grammar-Mutator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AFLplusplus%2FGrammar-Mutator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AFLplusplus%2FGrammar-Mutator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AFLplusplus%2FGrammar-Mutator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AFLplusplus%2FGrammar-Mutator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AFLplusplus","download_url":"https://codeload.github.com/AFLplusplus/Grammar-Mutator/tar.gz/refs/heads/stable","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AFLplusplus%2FGrammar-Mutator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264862504,"owners_count":23674986,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["afl","afl-fuzz","aflplusplus","fuzzing","grammar-fuzzer"],"created_at":"2024-08-04T17:01:51.331Z","updated_at":"2025-07-11T17:32:22.277Z","avatar_url":"https://github.com/AFLplusplus.png","language":"Python","funding_links":[],"categories":["Python","Python (1887)"],"sub_categories":[],"readme":"# Grammar Mutator - AFL++\n\n![Grammar Mutator CI](https://github.com/AFLplusplus/Grammar-Mutator/workflows/Grammar%20Mutator%20CI/badge.svg)\n\nA grammar-based custom mutator for AFL++ to handle highly-structured inputs.\n\n- Developer: [Shengtuo Hu (h1994st)](https://github.com/h1994st)\n- Mentors: [Marc Heuse](https://github.com/vanhauser-thc), [Andrea Fioraldi](https://github.com/andreafioraldi)\n\n## Overview\n\nWe developed a grammar mutator to enhance AFL++ such that AFL++ can handle highly-structured inputs, such as JSON, Ruby, etc.\nThe grammar mutator leverages the idea of [F1 fuzzer](https://github.com/vrthra/F1) and [Nautilus](https://github.com/nautilus-fuzz/nautilus) for test case generation and mutations.\nIn summary, this repository includes:\n\n- Tree-based mutation: rules mutation, random mutation, random recursive mutation, splicing mutation\n- Tree-based trimming: subtree trimming, recursive trimming\n- An ANTLR4 shim for parsing fuzzing test cases during the runtime\n- Documents about how to build the grammar mutator, specify custom grammars, and use the grammar mutator\n- Comprehensive test cases for unit testing\n- Sample grammar files and a script to convert nautilus's python grammar file\n\nFor more details about tree-based mutation, trimming, and grammar-based fuzzing, please refer to [Nautilus paper](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Nautilus.pdf).\n\nA fuzzing writeup on Apache which uses the AFL++ Grammmar Mutator can be found here:\n[https://securitylab.github.com/research/fuzzing-apache-1](https://securitylab.github.com/research/fuzzing-apache-1)\n\n## Getting Started\n\n### Prerequisites\n\nBefore getting started, the following tools/packages should be installed:\n\n```bash\nsudo apt install valgrind uuid-dev default-jre python3\nwget https://www.antlr.org/download/antlr-4.8-complete.jar\nsudo cp -f antlr-4.8-complete.jar /usr/local/lib\n```\nIf you do not leave the JAR file in the Grammar-Mutator directory or do not copy\nit to /usr/local/lib then you must specify the location via ANTLR_JAR_LOCATION=...\nin the make command.\n\nNote that the grammar mutator is based on the latest custom mutator APIs in AFL++, so please use the latest `dev` or `stable` branch of [AFL++](https://github.com/AFLplusplus/AFLplusplus/tree/dev).\n\n```bash\ngit clone https://github.com/AFLplusplus/AFLplusplus.git\ncd AFLplusplus\nmake distrib\nsudo make install\n```\n\n### Building the Grammar Mutator\n\nNext you need to build the grammar mutator.\nTo specify the grammar file, eg. Ruby, you can use `GRAMMAR_FILE` environment variable.\nThere are several grammar files in `grammars` directory, such as `json.json`, `ruby.json` and `http.json`.\nPlease refer to [customizing-grammars.md](doc/customizing-grammars.md) for more details about the input grammar file.\nNote that pull requests with new grammars are welcome! :-)\n\n```bash\nmake GRAMMAR_FILE=grammars/ruby.json\n```\n\nNote that the shared library and grammar generator are named after the grammar file that is specified so you can have multiple grammars generated.\nThe grammar name part is based on the filename with everything cut off after a underline, dash or dot, hency `ruby.json` will result in `ruby` and hence `grammar_generator-ruby` and `libgrammarmutator-ruby.so` will be created.\nYou can specify your own naming by setting `GRAMMAR_FILENAME=yourname` as make option.\n\nNow, you should be able to see two symbolic files `libgrammarmutator-ruby.so` and `grammar_generator-ruby` under the root directory.\nThese two files actually locate in the `src` directory.\n\nIf you would like to fork the project and fix bugs or contribute to the project, you can take a look at [building-grammar-mutator.md](doc/building-grammar-mutator.md) for full building instructions.\n\n### Instrumenting Fuzzing Targets\n\nYou can refer to [sample-fuzzing-targets.md](doc/sample-fuzzing-targets.md) to build the example fuzzing targets.\n\n### Seeds\n\nBefore fuzzing the real program, you need to prepare the input fuzzing seeds. You can either:\n\n- Generating seeds for a given grammar\n- Using existing seeds\n\n#### Using Existing Seeds\n\nYou can feed your own fuzzing seeds to the fuzzer, which does not need to match with your input grammar file.\nAssuming that the grammar mutator is built with `grammars/ruby.json`, which is a simplified Ruby grammar and does not cover all Ruby syntax.\nIn this case, the parsing error will definitely occur.\nFor any parsing errors, the grammar mutator will not terminate but save the error portion as a terminal node in the tree, such that we will not lose too much information on the original test case.\n\nTo e.g. use the test cases of the `mruby` project as input fuzzing seeds just pass the `-i mruby/test/t` to afl-fuzz\nwhen we run the fuzzer (if it has been checked out with `git clone https://github.com/mruby/mruby.git` in the current directory).\n\n#### Using Generated Seeds\n\n`grammar_generator` can be used to generate input fuzzing seeds and corresponding tree files, following the grammar file that you specified during the compilation of the grammar mutator (i.e., `GRAMMAR_FILE`).\nYou can control the number of generated seeds and the maximal size of the corresponding trees.\nUsually, the larger the tree size is, the more complex the corresponding input seed is.\n\n```bash\n# Usage\n# ./grammar_generator-$GRAMMAR \u003cmax_num\u003e \u003cmax_size\u003e \u003cseed_output_dir\u003e \u003ctree_output_dir\u003e [\u003crandom seed\u003e]\n#\n# \u003crandom seed\u003e is optional\n# e.g.:\n./grammar_generator-ruby 100 1000 ./seeds ./trees\n```\n\nAfterwards copy the `trees` folder with that exact name to the output directory that you will use with afl-fuzz (e.g. `-o out -S default`):\n```bash\nmkdir -p out/default\ncp -r trees out/default\n```\n\nNote that if you use multiple fuzzers (-M/-S sync mode) then you have to do this for all fuzzer instances, e.g. when the fuzzer instances are named fuzzer1 to fuzzer8:\n```bash\nfor i in 1 2 3 4 5 6 7 8; do\n  mkdir -p out/fuzzer$i\n  cp -r trees out/fuzzer$i/\ndone\n```\n\n### Fuzzing the Target with the Grammar Mutator!\n\nLet's start running the fuzzer.\nThe following example command is using Ruby grammar (from `grammars/ruby.json`) where `mruby` project has been cloned to the root `Grammar-Mutator` directory.\n\nThe default memory limit for child process is `75M` in `afl-fuzz`.\nThis may not be enough for some test cases, so it is recommended to increase it to `128M` by adding an option `-m 128`.\n\n```bash\nexport AFL_CUSTOM_MUTATOR_LIBRARY=./libgrammarmutator-ruby.so\nexport AFL_CUSTOM_MUTATOR_ONLY=1\nafl-fuzz -m 128 -i seeds -o out -- /path/to/target @@\n```\n\nYou may notice that the fuzzer will be stuck for a while at the beginning of fuzzing.\nOne reason for the stuck is the large `max_size` (i.e., 1000) we choose, which results in a large size of test cases that increases the loading time.\nAnother reason is the costly parsing operations in the grammar mutator.\nSince the input seeds are in string format, the grammar mutator needs to parse them into tree representations at first, which is costly.\nThe large `max_size` passed into `grammar_generator-$GRAMMAR` does help us generate deeply nested trees, but it further increases the parsing overhead.\n\n### Changing the Default Configurations\n\nExcept for the deterministic rules mutation, users can change the default number of the following three types of mutations, by setting related environment variables:\n\n- `RANDOM_MUTATION_STEPS`: the number of random mutations\n- `RANDOM_RECURSIVE_MUTATION_STEPS`: the number of random recursive mutations\n- `SPLICING_MUTATION_STEPS`: the number of splicing mutations\n\nBy default, the number of each of these three mutations is 1000. Increase them on your own as follows, if needed. :)\n\n```bash\nexport RANDOM_MUTATION_STEPS=10000\nexport RANDOM_RECURSIVE_MUTATION_STEPS=10000\nexport SPLICING_MUTATION_STEPS=10000\nexport AFL_CUSTOM_MUTATOR_LIBRARY=./libgrammarmutator-ruby.so\nexport AFL_CUSTOM_MUTATOR_ONLY=1\nafl-fuzz -m 128 -i seeds -o out -- /path/to/target @@\n```\n\n## Contact \u0026 Contributions\n\nWe welcome any questions and contributions! Feel free to open an issue or submit a pull request!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAFLplusplus%2FGrammar-Mutator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAFLplusplus%2FGrammar-Mutator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAFLplusplus%2FGrammar-Mutator/lists"}