├── .envrc ├── .github └── workflows │ ├── hugo.yml │ ├── markdown.yml │ └── preview.yml ├── .gitignore ├── .gitmodules ├── .lycheeignore ├── .markdownlint-cli2.jsonc ├── .markdownlint.jsonc ├── CODEOWNERS ├── LICENSE ├── README.md ├── archetypes └── default.md ├── assets ├── _custom.scss └── _variables.scss ├── config.toml ├── content ├── _index.md └── docs │ ├── crypto │ ├── _index.md │ ├── constant_time_tool │ │ ├── Dudect.md │ │ ├── _index.md │ │ └── timecop.md │ ├── wycheproof │ │ ├── _index.md │ │ └── wycheproo_example.md │ └── zkdocs │ │ └── _index.md │ ├── dynamic-analysis │ └── _index.md │ ├── fuzzing │ ├── 10-ossfuzz.md │ ├── 3-python.md │ ├── 4-ruby.md │ ├── 5-snapshot.md │ ├── 5-snapshot │ │ ├── figure1.png │ │ ├── figure2.png │ │ ├── figure3.png │ │ ├── figure4.png │ │ ├── figure5.png │ │ ├── figure6.png │ │ └── figure7.png │ ├── 91-resources.md │ ├── _index.md │ ├── c-cpp │ │ ├── 10-libfuzzer │ │ │ └── index.md │ │ ├── 11-aflpp │ │ │ ├── aflpp-decision.drawio.svg │ │ │ ├── aflpp.png │ │ │ └── index.md │ │ ├── 12-libafl │ │ │ ├── index.md │ │ │ └── libafl.png │ │ ├── _index.md │ │ └── techniques │ │ │ ├── 01-coverage │ │ │ ├── cov1.png │ │ │ ├── cov2.png │ │ │ ├── cov3.png │ │ │ ├── coverage-flow.svg │ │ │ └── index.md │ │ │ ├── 02-obstacles │ │ │ └── index.md │ │ │ └── _index.md │ ├── intro.svg │ ├── rust │ │ ├── 10-cargo-fuzz │ │ │ └── index.md │ │ ├── _index.md │ │ └── techniques │ │ │ ├── 01-coverage │ │ │ ├── coverage-flow.svg │ │ │ └── index.md │ │ │ ├── 02-obstacles │ │ │ └── index.md │ │ │ ├── 03-writing-harnesses │ │ │ └── index.md │ │ │ └── _index.md │ └── techniques │ │ ├── 01-writing-harnesses.md │ │ ├── 02-dictionary.md │ │ ├── 03-asan.md │ │ ├── 04-env.md │ │ ├── 05-faq.md │ │ └── _index.md │ ├── static-analysis │ ├── _index.md │ ├── codeql │ │ ├── 00-installation.md │ │ ├── 10-advanced.md │ │ ├── 20-ci.md │ │ ├── 99-resources.md │ │ └── _index.md │ └── semgrep │ │ ├── 00-installation.md │ │ ├── 10-advanced.md │ │ ├── 20-ci.md │ │ ├── 30-org.md │ │ ├── 99-resources.md │ │ └── _index.md │ ├── template.md │ └── web │ ├── _index.md │ └── burp │ ├── _index.md │ ├── bugs-vs-features │ └── _index.md │ ├── burp-resources │ └── _index.md │ ├── stepbystep │ ├── 01-livetask │ │ └── _index.md │ ├── 02-workingmanually │ │ ├── 01-repeater │ │ │ ├── _index.md │ │ │ ├── content-type-converter.png │ │ │ ├── csrfoptions.png │ │ │ ├── generatecsrfpoc.png │ │ │ ├── minimizer-after.png │ │ │ ├── minimizer_before.png │ │ │ ├── repeater_options.png │ │ │ ├── repeater_request_minimizer.png │ │ │ ├── repeater_showchars.png │ │ │ ├── repeater_tab_options.png │ │ │ ├── test1337placeholder1.png │ │ │ └── test1337placeholder2.png │ │ ├── 02-intruder │ │ │ ├── _index.md │ │ │ ├── collabo-event-log.png │ │ │ ├── collabo-interaction-column.png │ │ │ ├── custom-wordlists.png │ │ │ ├── extension-generated.png │ │ │ ├── intruder-attack-type.png │ │ │ └── target-payload-markers.png │ │ ├── 03-collaborator │ │ │ ├── _index.md │ │ │ ├── burp-collaborator-ua.png │ │ │ ├── collaborator-settings.png │ │ │ └── collaborator-tab.png │ │ └── _index.md │ ├── 03-ensure-working-correctly │ │ └── _index.md │ └── _index.md │ └── tips │ ├── _index.md │ ├── allow-tags-in-proxy.png │ ├── auto-modified.png │ ├── autorize.png │ ├── bambda.png │ ├── browser-with-hud.png │ ├── burp-search.png │ ├── collaborator-everywhere.png │ ├── create-new-tab-group.png │ ├── distributed-damage.png │ ├── easy-auto-refresh.png │ ├── global-search.png │ ├── hackvertor-store.png │ ├── hackvertor-turbo-intruder.png │ ├── injection-pt-turbo-intruder.png │ ├── match-and-replace-rules.png │ ├── pause-tasks.png │ ├── remove-csp.png │ ├── repeater-add-tab.png │ ├── request-interference.png │ ├── send-in-parallel.png │ ├── session-handling-rule-scope.png │ ├── session-handling-rule.png │ ├── turbo-intruder.png │ └── upstream-proxy-rule.png ├── layouts ├── _default │ └── _markup │ │ └── render-link.html ├── partials │ └── docs │ │ ├── brand.html │ │ └── inject │ │ └── footer.html └── shortcodes │ ├── customFigure.html │ ├── fuzzing │ ├── intro-os.html │ └── oss-fuzz-faq.html │ ├── math.html │ ├── rawHtml.html │ ├── resourceFigure.html │ ├── resourceHref.html │ └── tooltipHighlight.html ├── materials └── fuzzing │ ├── .gitignore │ ├── aflpp │ ├── CMakeLists.txt │ ├── afl++ │ ├── argv-fuzz-inl.h │ ├── fuzz │ ├── harness.cc │ ├── main.cc │ ├── main_arg.c │ ├── main_arg_no_shared.c │ ├── main_arg_persist.c │ ├── main_asan.cc │ ├── main_file.c │ ├── main_file_persist.c │ ├── main_stdin.c │ ├── main_stdin_persist.c │ ├── main_stdin_persist_no_shared.c │ └── seeds │ │ └── minimal_seed │ ├── complex-example │ ├── FuzzedDataProvider.h │ ├── data_provider.cc │ ├── divide.cc │ ├── divide.json │ ├── gdc.cc │ └── interleved.cc │ ├── coverage-analysis │ └── execute-rt.cc │ ├── coverage.c │ ├── libafl │ ├── appsec_guide │ │ ├── CMakeLists.txt │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── harness.cc │ │ ├── main.cc │ │ └── src │ │ │ ├── bin │ │ │ ├── libafl_cc.rs │ │ │ └── libafl_cxx.rs │ │ │ └── lib.rs │ ├── appsec_guide_deduplicate │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── harness.cc │ │ ├── main.cc │ │ └── src │ │ │ ├── bin │ │ │ ├── libafl_cc.rs │ │ │ └── libafl_cxx.rs │ │ │ └── lib.rs │ └── appsec_guide_tokens │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── harness.cc │ │ ├── main.cc │ │ └── src │ │ ├── bin │ │ ├── libafl_cc.rs │ │ └── libafl_cxx.rs │ │ └── lib.rs │ ├── libfuzzer │ ├── CMakeLists.txt │ ├── harness.cc │ ├── interleaved │ │ ├── double.cc │ │ └── int.cc │ ├── main.cc │ └── main_asan.cc │ ├── libpng │ └── libpng-1.6.37.tar.xz │ ├── pc-trace │ ├── cb.cc │ └── trace-pc-guard-example.cc │ └── rust │ ├── afl │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── main.rs │ ├── cargo-fuzz │ ├── .gitignore │ ├── Cargo.toml │ ├── cov.sh │ ├── fuzz │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ └── fuzz_targets │ │ │ ├── fuzz_arbitrary.rs │ │ │ ├── fuzz_arbitrary_short.rs │ │ │ ├── fuzz_beyond_byte_arrays.rs │ │ │ ├── fuzz_check_buf.rs │ │ │ ├── fuzz_divide.rs │ │ │ ├── fuzz_impossible.rs │ │ │ ├── fuzz_interleaved.rs │ │ │ └── fuzz_interleaved_int.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs │ ├── ogg │ └── fuzz │ │ ├── Cargo.toml │ │ └── fuzz_targets │ │ └── fuzz_target_1.rs │ └── run.rs ├── mlc_config.json ├── shell.nix ├── static ├── TOB_Black.svg ├── code-scanning-protection.png ├── code-scanning-setup.png ├── favicon.png ├── favicon.svg ├── generate-codeql-query.png ├── logo.png ├── popper.min.js ├── svg │ └── copy-regular.svg ├── tippy-bundle.umd.min.js └── view-codeql-ast.png └── th-logo.jpg /.envrc: -------------------------------------------------------------------------------- 1 | use nix 2 | -------------------------------------------------------------------------------- /.github/workflows/hugo.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Hugo site to GitHub Pages 2 | name: Deploy Hugo site to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | # Default to bash 24 | defaults: 25 | run: 26 | shell: bash 27 | 28 | jobs: 29 | # Build job 30 | build: 31 | runs-on: ubuntu-latest 32 | env: 33 | HUGO_VERSION: 0.133.0 34 | steps: 35 | - name: Install Hugo CLI 36 | run: | 37 | wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ 38 | && sudo dpkg -i ${{ runner.temp }}/hugo.deb 39 | - name: Install Dart Sass Embedded 40 | run: sudo snap install dart-sass-embedded 41 | - name: Checkout 42 | uses: actions/checkout@v4 43 | with: 44 | submodules: recursive 45 | - name: Setup Pages 46 | id: pages 47 | uses: actions/configure-pages@v5 48 | - name: Install Node.js dependencies 49 | run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" 50 | - name: Build with Hugo 51 | env: 52 | # For maximum backward compatibility with Hugo modules 53 | HUGO_ENVIRONMENT: production 54 | HUGO_ENV: production 55 | run: | 56 | hugo \ 57 | --minify \ 58 | --baseURL "${{ steps.pages.outputs.base_url }}/" 59 | - name: Upload artifact 60 | uses: actions/upload-pages-artifact@v3 61 | with: 62 | path: ./public 63 | 64 | # Deployment job 65 | deploy: 66 | environment: 67 | name: github-pages 68 | url: ${{ steps.deployment.outputs.page_url }} 69 | runs-on: ubuntu-latest 70 | needs: build 71 | steps: 72 | - name: Deploy to GitHub Pages 73 | id: deployment 74 | uses: actions/deploy-pages@v4 75 | -------------------------------------------------------------------------------- /.github/workflows/markdown.yml: -------------------------------------------------------------------------------- 1 | name: Check Markdown files correctness 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | # Extract links from Markdown texts and check if they are alive 11 | markdown-link-check: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Restore lychee cache 16 | uses: actions/cache@v4 17 | with: 18 | path: .lycheecache 19 | key: cache-lychee-${{ github.sha }} 20 | restore-keys: cache-lychee- 21 | - uses: lycheeverse/lychee-action@f613c4a64e50d792e0b31ec34bbcbba12263c6a6 # for v2.3.0 22 | with: 23 | args: --base . -a 100..=103,200..=299,429 --verbose --no-progress --cache --max-cache-age 1d --scheme http --scheme https './**/*.md' './layout/shortcodes/fuzzing/*.html' 24 | fail: true 25 | # Lint Markdown files 26 | # Uses: a custom configuration file 27 | markdown-linter: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: DavidAnson/markdownlint-cli2-action@v19 32 | with: 33 | globs: "**/*.md" 34 | # Spellcheck Markdown files using `retext` and `remark` 35 | # Uses: a custom dictionary file 36 | spellcheck: 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v4 40 | - uses: tbroadley/spellchecker-cli-action@v1 41 | with: 42 | # No need to use a dictionary file with the disabled spell plugin 43 | # dictionaries: '.github/workflows/dictionary.txt' 44 | files: "'content/**/*.md'" 45 | quiet: true 46 | plugins: "indefinite-article repeated-words syntax-mentions syntax-urls" 47 | -------------------------------------------------------------------------------- /.github/workflows/preview.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/preview.yml 2 | name: Deploy PR previews 3 | 4 | on: 5 | pull_request: 6 | types: 7 | - opened 8 | - reopened 9 | - synchronize 10 | - closed 11 | 12 | concurrency: preview-${{ github.ref }} 13 | 14 | permissions: 15 | pull-requests: write 16 | 17 | # Default to bash 18 | defaults: 19 | run: 20 | shell: bash 21 | 22 | jobs: 23 | # Build job 24 | build-deploy: 25 | runs-on: ubuntu-latest 26 | env: 27 | HUGO_VERSION: 0.133.0 28 | steps: 29 | - name: Install Hugo CLI 30 | run: | 31 | wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ 32 | && sudo dpkg -i ${{ runner.temp }}/hugo.deb 33 | - name: Install Dart Sass Embedded 34 | run: sudo snap install dart-sass-embedded 35 | - name: Checkout 36 | uses: actions/checkout@v4 37 | with: 38 | submodules: recursive 39 | - name: Install Node.js dependencies 40 | run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" 41 | - name: Build with Hugo 42 | env: 43 | # For maximum backward compatibility with Hugo modules 44 | HUGO_ENVIRONMENT: production 45 | HUGO_ENV: production 46 | run: | 47 | hugo \ 48 | --minify \ 49 | --baseURL "https://trailofbits.github.io/testing-handbook-preview/pr-preview/pr-${{ github.event.number }}/" 50 | - name: Deploy preview 51 | uses: rossjrw/pr-preview-action@v1 52 | with: 53 | source-dir: ./public/ 54 | token: ${{ secrets.TESTING_HANDBOOK_PREVIEW_REPO }} 55 | deploy-repository: trailofbits/testing-handbook-preview 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | public/ 2 | exampleSite/public/ 3 | .DS_Store 4 | node_modules/* 5 | .idea/ 6 | 7 | .hugo_build.lock 8 | resources/ 9 | 10 | .direnv/ 11 | materials/fuzzing/aflpp/out 12 | 13 | target/ 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "themes/book"] 2 | path = themes/book 3 | url = https://github.com/alex-shpak/hugo-book.git 4 | -------------------------------------------------------------------------------- /.lycheeignore: -------------------------------------------------------------------------------- 1 | https://t.co/* 2 | https://dl.acm.org/doi/pdf/* 3 | https://www.gnu.org/* 4 | -------------------------------------------------------------------------------- /.markdownlint-cli2.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "ignores": ["content/docs/fuzzing/**", "themes/book/**", "node_modules/**"] 3 | } -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ahpaleus @elopez 2 | /content/docs/static-analysis/codeql @fegge @fcasal 3 | /content/docs/static-analysis/semgrep @ahpaleus -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Trail of Bits Testing Handbook 2 | 3 | ![Testing-Handbook-logo][logo] 4 | 5 | [logo]:th-logo.jpg 6 | 7 | The Trail of Bits Testing Handbook is a resource for developers and security professionals on configuring, optimizing, 8 | and automating many static and dynamic analysis tools we use at Trail of Bits. 9 | 10 | ## Preview Testing Handbook: [https://appsec.guide](https://appsec.guide) 🌐 11 | 12 | ## Why is this needed? ✨ 13 | 14 | - 📃 The documentation for configuring and optimizing existing tools is often not developer-friendly, as it is often meant 15 | for security professionals. This is especially the case when it comes to fuzzing utilities. This can lead to frustration 16 | and poor adoption of security tools that should be straightforward to configure. 17 | - ⚙️ Even if the tool is easy to configure locally, it can be difficult to configure them in CI/CD pipelines. 18 | Often, security tools are set up by following online documentation, but their configuration is rarely optimized. 19 | This can lead to a noisy tool that is more difficult to maintain than worth. 20 | - 🧠 We aim to make it as easy as possible to set up security tools effectively. In doing so, we also 21 | hope to demystify static and dynamic analysis techniques such as fuzzing and taint analysis. 22 | 23 | ## Chapters 24 | 25 | ### ✅ Released 26 | 27 | |Topic|Announcing Blog Post|Year| 28 | |---|---|---| 29 | |[Semgrep](https://appsec.guide/docs/static-analysis/semgrep/)| [Announcing the Trail of Bits Testing Handbook](https://blog.trailofbits.com/2023/07/26/announcing-the-trail-of-bits-testing-handbook/)|2023| 30 | |[CodeQL](https://appsec.guide/docs/static-analysis/codeql/)| [Say hello to the next chapter of the Testing Handbook!](https://blog.trailofbits.com/2023/12/11/say-hello-to-the-next-chapter-of-the-testing-handbook/)|2023| 31 | |[Fuzzing](https://appsec.guide/docs/fuzzing/)| [Master fuzzing with our new Testing Handbook chapter](https://blog.trailofbits.com/2024/02/09/master-fuzzing-with-our-new-testing-handbook-chapter/)|2024| 32 | |[Burp](https://appsec.guide/docs/web/burp/)| [Announcing the Burp Suite Professional chapter in the Testing Handbook](https://blog.trailofbits.com/2024/06/14/announcing-the-burp-suite-professional-chapter-in-the-testing-handbook/)|2024| 33 | | [Cryptographic testing - Wycheproof and Constant time analysis tooling](https://appsec.guide/docs/crypto/) | TBD | 2024 | 34 | 35 | ### 🎥 Webinars 36 | 37 | | Topic | Link | 38 | |---|---| 39 | | Introduction to Semgrep | https://www.youtube.com/watch?v=yKQlTbVlf0Q | 40 | | Introduction to CodeQL: Examples, Tools and CI Integration | https://www.youtube.com/watch?v=rQRlnUQPXDw | 41 | | Mastering Web Research with Burp Suite | https://www.youtube.com/watch?v=0PV5QEQTmPg | 42 | 43 | ### 🚧 Under construction 44 | 45 | - Formal verification and Tamarin 46 | - Rust 47 | 48 | ## How to contribute 49 | 50 | If you would like to contribute to the Testing Handbook, here are some guidelines to help you get started: 51 | 52 | 1. **Add a New Tool**: If you want to cover a new tool in the Testing Handbook, 53 | propose a topic in GitHub Issues. Afterward, you can work on a new pull request. 54 | 1. **Improve Existing Chapters**: If you have an idea to make a specific chapter better, 55 | you can add a GitHub issue. 56 | 1. **Pick Up Small Tasks**: If you don't have much time but still want to contribute, 57 | you can pick up any small task from the GitHub issues list. 58 | 1. **Report Issues**: If you find a small technical issue or a typo, 59 | create a new GitHub issue and/or fix it in the new pull request. 60 | 61 | ### Quick setup for convenient development 62 | 63 | 1. Install Hugo in your system 64 | 65 | ```shell 66 | brew install hugo 67 | ``` 68 | 69 | 2. Clone the repo 70 | 71 | ```shell 72 | git clone --recurse-submodules https://github.com/trailofbits/testing-handbook.git 73 | ``` 74 | 75 | 3. Create a new branch or select a branch you want to work on 76 | 77 | ```shell 78 | cd testing-handbook 79 | # then 80 | git checkout -b name-of-your-new-branch 81 | # or 82 | git checkout name-of-existing-branch 83 | ``` 84 | 85 | 4. Run the Hugo server with drafts turned on (`-D`) from the project's root directory. 86 | Your browser will be automatically refreshed with changes whenever you save a file. 87 | 88 | ```shell 89 | hugo server -D 90 | ``` 91 | 92 | 5. Add a new tool as "doc", and run the following from the project's root directory. 93 | 94 | ```shell 95 | hugo new docs/ 96 | ``` 97 | 98 | **Note**: This project uses the same hugo template as [zkdocs](https://www.zkdocs.com/). The template refers to each 99 | new page as a "doc," as opposed to a post. This is why you'd want to type `hugo new docs/` and not `post/my-new-post`. 100 | 101 | 6. Edit, add, and create pull requests to merge your changes into `main`. 102 | 103 | 7. ❗Keep in mind that when you merge your PR into `main`, the content goes live in . 104 | Our current policy forces at least one review before merging. 105 | 106 | 8. For updates to the home page, edit [content/_index.md](content/_index.md) 107 | 108 | ## Guidelines 109 | 110 | - The format should be consistent between each "doc." When adding a new doc (i.e., when adding a new tool), follow the 111 | template in [content/docs/template.md](content/docs/template.md). Send a PR for this file with suggested changes as needed. 112 | 113 | - Create a new branch with your changes, and create a PR to merge into `main` when you are done. 114 | 115 | - The GitHub workflow in this repository verifies the correctness of Markdown files through three checks: 116 | 1. **Markdown Link Check**: This step extracts links from Markdown files and verifies if they are valid and accessible. 117 | It uses the [lychee link checking action](https://github.com/lycheeverse/lychee-action). 118 | 2. **Markdown Linter**: This step ensures that Markdown files adhere to the desired style and formatting rules. 119 | It uses a custom configuration file (`.github/workflows/.markdownlint.jsonc`) and the 120 | [markdownlint-cli2-action](https://github.com/DavidAnson/markdownlint-cli2-action) action. 121 | Use the [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint) extension 122 | with Visual Studio Code for better user experience while working on the Testing Handbook. 123 | 3. **Spellcheck**: This step checks the spelling in Markdown files 124 | (built on top of [retext](https://github.com/retextjs/retext) and [remark](https://github.com/remarkjs/remark)). 125 | Uses the [tbroadley/spellchecker-cli-action](https://github.com/tbroadley/spellchecker-cli-action) action. 126 | 127 | - Familiarize yourself with the [Hugo Book theme](https://hugo-book-demo.netlify.app/) 128 | as it has a couple of nice features (buttons, etc.) 129 | - Reach out in [#testing-handbook](https://empirehacking.slack.com/archives/C06CSLSQAMB) Empire Hacking Slack if you have any questions. 130 | 131 | ## Editing 132 | 133 | ### Writing Guidelines 134 | 135 | - The term "Testing Handbook" should be capitalized any time it appears on the website (whether in a header/subheader or running text), 136 | since it is the title of a document. But if you'd like to avoid the capitalization because it looks strange, you can substitute 137 | "Testing Handbook" for "this handbook" (since it's clear enough what the title of the handbook is). 138 | 139 | ### Workflow: From Google Docs 140 | 141 | You can export the document from Google Docs as Markdown. Open the document in Google Docs. Click `File` > `Download`, and then select `Markdown (.md)`. 142 | 143 | ### Custom environments 144 | 145 | ```md 146 | {{< customFigure "Caption" >}} 147 | {{< /customFigure >}} 148 | 149 | {{< resourceFigure "cov1.png" >}} 150 | {{< /resourceFigure >}} 151 | 152 | {{< hint info >}} 153 | {{< /hint >}} 154 | ``` 155 | -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /assets/_custom.scss: -------------------------------------------------------------------------------- 1 | .book-brand { 2 | margin-top: 0; 3 | margin-bottom: $padding-16; 4 | 5 | #icon { 6 | height: 4.5em; 7 | width: 4.5em; 8 | margin-left: auto; 9 | display: block; 10 | margin-right: auto; 11 | margin-top: -0.7em; 12 | } 13 | 14 | #logo { 15 | height: 1.5em; 16 | width: 1.5em; 17 | margin-inline-end: $padding-8; 18 | } 19 | } 20 | 21 | .book-page footer { 22 | margin-top: 3em; 23 | border-top: 1px var(--gray-200) solid; 24 | } 25 | 26 | .footer-edit { 27 | :first-child { 28 | margin-left: auto; 29 | } 30 | 31 | a { 32 | margin-left: $padding-8; 33 | } 34 | 35 | a:not(:last-child) { 36 | margin-right: $padding-8; 37 | } 38 | } 39 | 40 | .markdown .highlight { 41 | position: relative; 42 | padding: 1rem 0; 43 | 44 | > pre { 45 | margin: inherit; 46 | } 47 | 48 | code:first-child::before { 49 | content: "Copy"; 50 | font-size: 0; 51 | background: no-repeat center url("svg/copy-regular.svg"); 52 | width: 1.4rem; 53 | height: 1.4rem; 54 | position: absolute; 55 | right: 1rem; 56 | top: 2rem; 57 | display: inline-block; 58 | opacity: 0.3; 59 | transition: opacity 0.1s ease-in; 60 | cursor: pointer; 61 | } 62 | } 63 | 64 | .markdown .highlight:hover code:first-child::before { 65 | opacity: 1; 66 | } 67 | 68 | figure { 69 | counter-increment: figureIndex; 70 | 71 | width: 100%; 72 | 73 | > div { 74 | display: flex; 75 | flex-direction: column; 76 | align-items: center; 77 | margin-block-start: 0; 78 | margin-block-end: 0; 79 | margin-inline-start: 0; 80 | margin-inline-end: 0; 81 | 82 | margin-top: 10px; 83 | 84 | min-width: 90%; 85 | 86 | > * { 87 | max-width: 95%; 88 | } 89 | } 90 | 91 | //border: 2px solid var(--gray-100); 92 | 93 | figcaption::before { 94 | content: "Figure " counter(figureIndex) ": "; 95 | } 96 | figcaption { 97 | text-align: center; 98 | max-width: 90%; 99 | margin-top: 5px; 100 | margin-bottom: 10px; 101 | font-style: italic; 102 | 103 | p:first-child { 104 | display: inline; 105 | } 106 | } 107 | 108 | figcaption.code { 109 | margin-top: 0px; // Remove margin when a figure is code block 110 | } 111 | } 112 | 113 | p { 114 | // TODO: not sure if this is without side effects 115 | code { 116 | white-space: nowrap; 117 | } 118 | } 119 | 120 | .skip-table-head thead { 121 | display: none; 122 | } 123 | 124 | .code-fence-wrap pre { 125 | text-wrap: wrap; 126 | } 127 | 128 | ul.no-bullet-point-list { 129 | list-style-type: none; 130 | 131 | li { 132 | margin-top: 10px; 133 | } 134 | } 135 | 136 | table.hide-empty-cells { 137 | td:empty { 138 | display: none; 139 | } 140 | } 141 | 142 | html { 143 | overflow: auto; 144 | scrollbar-color: var(--gray-500) transparent; 145 | scrollbar-width: auto; 146 | } 147 | 148 | // Vertical scrollbar 149 | ::-webkit-scrollbar { 150 | width: $padding-8; 151 | background: var(--gray-500); 152 | background: white; 153 | } 154 | 155 | // Horizontal scrollbar 156 | ::-webkit-scrollbar:horizontal { 157 | height: $padding-8; 158 | } 159 | 160 | ::-webkit-scrollbar-thumb { 161 | background: var(--gray-500); 162 | border-radius: $padding-8; 163 | } 164 | 165 | 166 | 167 | // Links 168 | // main colors are set in _variables.scss 169 | a:focus, a:focus-visible { 170 | opacity: .75; 171 | text-decoration: none; 172 | outline-style: auto; 173 | outline-color: var(--color-link-mono); 174 | } 175 | 176 | .markdown, .book-toc { 177 | a:hover { 178 | opacity: .75; 179 | } 180 | } 181 | 182 | .markdown a { 183 | &:hover { 184 | text-decoration: underline; 185 | text-decoration-color: var(--color-link-mono); 186 | } 187 | 188 | &:visited { 189 | &:hover { 190 | text-decoration-color: var(--color-visited-link-mono); 191 | } 192 | 193 | &:focus, &:focus-visible { 194 | outline-color: var(--color-visited-link-mono); 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /assets/_variables.scss: -------------------------------------------------------------------------------- 1 | // had to copy the whole mixin from _default.scss 2 | @mixin theme-light { 3 | --gray-100: #f8f9fa; 4 | --gray-200: #e9ecef; 5 | --gray-500: #adb5bd; 6 | 7 | // https://github.com/trailofbits/audit-reporting-tools/blob/88b75a31a7298e8079fb326c7992ff534868e497/make-report/make_report/colors.py#L86 8 | --color-link: #ad182b; 9 | --color-link-mono: #c93447; // monochromatic 10 | --color-visited-link: #683700; 11 | --color-visited-link-mono: #84531c; // monochromatic 12 | 13 | --body-background: white; 14 | --body-font-color: black; 15 | 16 | --icon-filter: none; 17 | 18 | --hint-color-info: #6bf; 19 | --hint-color-warning: #fd6; 20 | --hint-color-danger: #f66; 21 | } -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | baseURL = "http://example.org/" 2 | languageCode = "en-us" 3 | title = "Testing Handbook" 4 | theme = 'book' 5 | enableEmoji = true 6 | 7 | [params] 8 | BookLogo = 'TOB_Black.svg' 9 | BookIconLogo = 'logo.png' 10 | # Comment to make pages uneditable with a github link ("Edit this page" in the footer): 11 | BookRepo = "https://github.com/trailofbits/testing-handbook" 12 | BookEditBranch = "main" 13 | math = false 14 | 15 | [params.render_hooks.link] 16 | errorLevel = 'warning' # ignore (default), warning, or error (fails the build) 17 | highlightBroken = true # true or false (default) 18 | [markup] 19 | [markup.highlight] 20 | anchorLineNos = false 21 | codeFences = true 22 | guessSyntax = false 23 | hl_Lines = '' 24 | lineAnchors = '' 25 | lineNoStart = 1 26 | lineNos = false 27 | lineNumbersInTable = true 28 | noClasses = true 29 | style = 'friendly' 30 | tabWidth = 4 31 | [markup.goldmark.renderer] 32 | unsafe = false 33 | [markup.goldmark.parser.attribute] 34 | block = true 35 | [markup.goldmark] 36 | [markup.goldmark.extensions] 37 | [markup.goldmark.extensions.passthrough] 38 | enable = true 39 | [markup.goldmark.extensions.passthrough.delimiters] 40 | block = [['$$', '$$']] 41 | inline = [['\(', '\)']] 42 | -------------------------------------------------------------------------------- /content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | summary: "The automated testing handbook is a resource that guides developers and security professionals in configuring, optimizing, and automating many of the static and dynamic analysis tools we use at Trail of Bits." 4 | weight: 1 5 | --- 6 | 7 | # Trail of Bits Testing Handbook 8 | 9 | 10 | The Testing Handbook is a resource that guides developers and security 11 | professionals in configuring, optimizing, and automating many of the static and 12 | dynamic analysis tools we use at [Trail of Bits](https://www.trailofbits.com/). 13 | 14 | In our day-to-day work, we audit software projects ranging from cloud-native software 15 | to embedded devices. We often find issues that should be easy to spot early in 16 | development with the correct security tooling, but that make their way across 17 | the software lifecycle undetected. 18 | 19 | We hope to assist development teams across technology stacks in their quest to 20 | improve the security posture of their software by providing practical 21 | documentation they can apply when performing security analyses of their codebases. 22 | 23 | {{< columns >}} 24 | 25 | ## Straightforward 26 | 27 | We aim to make it as straightforward as possible to set up security tools 28 | effectively across all steps of the software development lifecycle. 29 | 30 | <---> 31 | 32 | ## Demystified 33 | 34 | In doing so, we also hope to demystify static and dynamic analysis techniques 35 | such as fuzzing and taint analysis. 36 | 37 | {{< /columns >}} 38 | 39 | ## Why is this needed? 40 | 41 | - The documentation for configuring and optimizing existing tools is often not 42 | developer friendly, as it is often targeted at security professionals. This 43 | is especially the case with fuzzing utilities. This lack of 44 | easy-to-follow documentation can lead to frustration and poor adoption of 45 | security tools that should be straightforward to configure. 46 | - Even if the tool is easy to configure locally, it can be difficult to 47 | configure it in a CI/CD pipeline. 48 | - Often, security tools are set up by following the online documentation, but 49 | their configuration is rarely optimized. This lack of tuning can lead to noisy 50 | tool results that are more frustrating than they are helpful. 51 | 52 | ## Tools 53 | 54 | We currently cover the following tools and techniques: 55 | 56 | {{< columns >}} 57 | 58 | ### Static analysis 59 | 60 | - [Semgrep]({{< relref "semgrep" >}}) 61 | - [CodeQL]({{< relref "codeql" >}}) 62 | 63 | <---> 64 | 65 | ### Dynamic analysis 66 | 67 | - [Fuzzing]({{< relref "fuzzing" >}}) 68 | - [Burp Suite Professional]({{< relref "/docs/web/burp/" >}}) 69 | 70 | {{< /columns >}} 71 | 72 | We are working on expanding the tools we cover here. We are also planning to 73 | cover several other security-related topics. Stay tuned for updates from our team! 74 | 75 | ### Upcoming (!) 76 | 77 | - Formal verification and Tamarin 78 | - Rust security 79 | - How to apply taint analysis in a directed fuzzing loop or/and for results verification 80 | - Taking effective notes for security engagements 81 | - mitmproxy 82 | - Leveraging grep in security audits 83 | 84 | ## Custom queries for static analysis tools 85 | 86 | One of our core objectives at Trail of Bits is to uncover and solve problems that are likely to recur. 87 | This is where our custom queries come into play. Built on the knowledge and expertise of our entire team, 88 | they provide proactive, effective security for your software projects. 89 | 90 | {{< details title="[Trail of Bits public Semgrep rules](https://github.com/trailofbits/semgrep-rules)" open=true >}} 91 | Navigate to the root folder of your project and use them right away: 92 | 93 | ```sh 94 | semgrep --config "p/trailofbits" 95 | ``` 96 | 97 | {{< /details >}} 98 | 99 | {{< details title="[Trail of Bits public CodeQL queries](https://github.com/trailofbits/codeql-queries)" open=true >}} 100 | To install our public CodeQL queries for C, C++ and Go, simply run `codeql pack download`: 101 | 102 | ```sh 103 | codeql pack download trailofbits/cpp-queries trailofbits/go-queries 104 | ``` 105 | 106 | To run our queries for C and C++ on an existing database, you can now run the following command: 107 | 108 | ```shell 109 | codeql database analyze codeql.db --format=sarif-latest --output=results.sarif -- trailofbits/cpp-queries 110 | ``` 111 | 112 | {{< /details >}} 113 | 114 | ## Custom fuzzers 115 | 116 | We make extensive use of fuzzing when auditing software for bugs. To that end, 117 | we often build our own fuzzers when we cannot find one for the task at hand. The 118 | following is a list of fuzzers we have built and endorse using: 119 | 120 | - [Mishegos](https://github.com/trailofbits/mishegos): a differential fuzzer for x86 decoders 121 | - [Ruzzy](https://github.com/trailofbits/ruzzy): a coverage-guided fuzzer for pure Ruby code and Ruby C extensions 122 | - [Medusa](https://github.com/crytic/medusa): a parallelized, coverage-guided, mutational Solidity smart contract fuzzer 123 | - [Echidna](https://github.com/crytic/echidna): Ethereum smart contract fuzzer 124 | - [Tayt](https://github.com/crytic/tayt): StarkNet smart contract fuzzer 125 | 126 | ## Feedback 127 | 128 | We want to actively maintain the highest possible quality and expand the content of the Testing Handbook. 129 | If you see a way to improve the Testing Handbook, please let us know! The best way to let us know is 130 | by raising an issue directly on the [Testing Handbook GitHub page](https://github.com/trailofbits/testing-handbook). 131 | 132 | -------------------------------------------------------------------------------- /content/docs/crypto/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 2 3 | bookFlatSection: true 4 | title: "Cryptographic testing" 5 | --- 6 | 7 | # Cryptographic testing 8 | 9 | This section presents testing tools to verify implementations of cryptographic algorithms. 10 | For each tool, we cover topics such as: 11 | 12 | - Explain the workings of these tools 13 | - Installation and basic use 14 | - Provide examples 15 | 16 | {{< section >}} 17 | -------------------------------------------------------------------------------- /content/docs/crypto/wycheproof/wycheproo_example.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Testing harness example" 3 | weight: 30 4 | # bookFlatSection: false 5 | # bookToc: true 6 | # bookHidden: false 7 | # bookCollapseSection: false 8 | # bookComments: false 9 | # bookSearchExclude: false 10 | --- 11 | 12 | # Wycheproof testing harness example in Python 13 | 14 | The following section will showcase how to write a simple testing harness to test a Python library implementing AES in GCM mode. 15 | We will use the [cryptography](https://pypi.org/project/cryptography/) package as an example of an AES-GCM implementation. 16 | For testing, we will use the [pytest](https://pypi.org/project/pytest/) package, one of the most popular testing frameworks in Python. 17 | 18 | ## Prerequisites 19 | 20 | Add the Wycheproof repository as a submodule to your existing repository. 21 | 22 | ```bash 23 | git submodule add https://github.com/C2SP/wycheproof.git 24 | ``` 25 | 26 | The first step of using Wycheproof is to parse the JSON file containing all the test vectors to make it usable for testing and then write a simple testing function. 27 | 28 | ## 1. Parse the JSON File 29 | 30 | First, check if Wycheproof offers test vectors for the specific cryptographic algorithm being tested by searching inside the `testvectors` or `testvectors_v1` folders. 31 | For the AES-GCM example, we will use the following file: 32 | 33 | - `testvectors_v1/aes_gcm_test.json` 34 | 35 | All test files share a common structure that can be used to write a testing harness to generalize between different constructions, which we discussed in the previous section. There are a total of 45 test groups in the `aes_gcm_test.json` file. The test groups are differentiated by key, IV, and tag sizes. If the underlying AES implementation only supports certain parameter sizes, they can be filtered out during the parsing stage. 36 | 37 | Here is an example of how to load and parse the test vectors: 38 | 39 | ```python {linenos=inline} 40 | def load_wycheproof_test_vectors(path: str): 41 | testVectors = [] 42 | try: 43 | with open(path, "r") as f: 44 | wycheproof_json = json.loads(f.read()) 45 | except FileNotFoundError: 46 | print(f"No Wycheproof file found at: {path}") 47 | return testVectors 48 | 49 | convert_attr = {"key", "aad", "iv", "msg", "ct", "tag"} 50 | for testGroup in wycheproof_json["testGroups"]: 51 | if testGroup["ivSize"] < 64 or testGroup["ivSize"] > 1024: 52 | continue 53 | for tv in testGroup["tests"]: 54 | for attr in convert_attr: 55 | if attr in tv: 56 | tv[attr] = bytes.fromhex(tv[attr]) 57 | testVectors.append(tv) 58 | return testVectors 59 | ``` 60 | 61 | This function reads the JSON file and converts the relevant attributes from hex strings to bytes. 62 | Since the specific AES-GCM implementation allows only for IV to be in a specific range, we filter the test groups based on the accepted IV size. 63 | Wycheproof provides us with a total of 283 test vectors for the specified parameters. 64 | 65 | ## 2. Write the Testing Harness 66 | 67 | After parsing the testing vectors, writing a testing harness is the next step. 68 | One can integrate the Wycheproof test vectors into the existing framework if a testing framework already exists. 69 | Notably, the testing framework should be flexible enough to expect that certain test vectors should fail, as some test vectors are specifically designed such that a correct implementation should raise an error and refuse to validate. We will demonstrate a simple example of writing a testing harness to check the encryption and decryption of the AES-GCM implementation. 70 | 71 | ### Testing Harness for Encryption 72 | 73 | The `parametrize` decorator of pytest allows us to create multiple tests that only differ in their parameterization. 74 | Here is an example testing harness for encryption: 75 | 76 | ```python {linenos=inline} 77 | @pytest.mark.parametrize("tv", tvs, ids=[str(tv['tcId']) for tv in tvs]) 78 | def test_encryption(tv): 79 | try: 80 | aesgcm = AESGCM(tv['key']) 81 | ct = aesgcm.encrypt(tv['iv'], tv['msg'], tv['aad']) 82 | except ValueError as e: 83 | assert tv['result'] != 'valid', tv['comment'] 84 | return 85 | if tv['result'] == 'valid': 86 | assert ct[:-16] == tv['ct'], f"Ciphertext mismatch: {tv['comment']}" 87 | assert ct[-16:] == tv['tag'], f"Tag mismatch: {tv['comment']}" 88 | elif tv['result'] == 'invalid' or tv['result'] == 'acceptable': 89 | assert ct[:-16] != tv['ct'] or ct[-16:] != tv['tag'] 90 | else: 91 | assert False 92 | ``` 93 | 94 | This function tests the encryption process by encrypting the provided input. 95 | If a `ValueError` occurs during encryption, the function ensures that the test vector is expected to fail. 96 | If no exceptions are raised, the function verifies that the encryption results match the expected outcomes. 97 | Specifically: 98 | 99 | 1. For test vectors expected to succeed, it checks that both the calculated tag and ciphertext are correct. 100 | 2. For test vectors expected to fail, it confirms that either the tag or the ciphertext is incorrect. 101 | 102 | You can run the tests using pytest with the following command: 103 | 104 | ```bash 105 | pytest /file/path/test.py 106 | ``` 107 | 108 | All 283 tests should pass. 109 | 110 | ### Testing Harness for Decryption 111 | 112 | Similarly, to test the decryption process, we can use pytest's parameterization feature to test all combinations of test vectors. 113 | The decryption test function handles exceptions specific to the AES implementation and verifies the expected outcomes based on the flags provided in the Wycheproof test vectors. 114 | If the AES implementation returns certain errors, the flag provided for each Wycheproof test vector can be used to verify the specific exceptions. 115 | 116 | ```python {linenos=inline} 117 | @pytest.mark.parametrize("tv", tvs, ids=[str(tv['tcId']) for tv in tvs]) 118 | def test_decryption(test_vector): 119 | try: 120 | aes_gcm = AESGCM(test_vector['key']) 121 | decrypted_msg = aes_gcm.decrypt(test_vector['iv'], test_vector['ct'] + test_vector['tag'], test_vector['aad']) 122 | except ValueError: 123 | assert test_vector['result'] != 'valid', test_vector['comment'] 124 | return 125 | except InvalidTag: 126 | assert test_vector['result'] != 'valid', test_vector['comment'] 127 | assert 'ModifiedTag' in test_vector['flags'], f"Expected 'ModifiedTag' flag: {test_vector['comment']}" 128 | return 129 | assert test_vector['result'] == 'valid', f"No invalid test case should pass: {test_vector['comment']}" 130 | assert decrypted_msg == test_vector['msg'], f"Decryption mismatch: {test_vector['comment']}" 131 | ``` 132 | 133 | If the cryptography library can not validate the tag an `InvalidTag` exception is raised. 134 | This function tests the decryption process by attempting to decrypt the provided ciphertext. 135 | The function covers several scenarios: 136 | 137 | 1. `ValueError`: If a `ValueError` occurs, the function checks if the test vector is supposed to fail. 138 | 2. `InvalidTag`: If an `InvalidTag` exception is raised, the function verifies that the test vector is expected to fail and checks for the presence of the `ModifiedTag` flag. 139 | 3. Successful Decryption: If no exceptions occur, the function confirms that the test vector is expected to succeed and that the decrypted message matches the expected plaintext. 140 | 141 | ## Summary 142 | 143 | In this article, we demonstrated how to write a testing harness for AES-GCM using the Wycheproof test vectors and the pytest framework. 144 | We covered: 145 | 146 | - Parsing the JSON test vectors. 147 | - Writing testing functions for both encryption and decryption. 148 | - Handling edge cases and errors within the testing framework. 149 | 150 | Following these steps ensures that your cryptographic implementation is robust and conforms to the expected standards. 151 | -------------------------------------------------------------------------------- /content/docs/crypto/zkdocs/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Zero-knowledge protocols" 3 | weight: 4 4 | summary: "ZKDocs provides comprehensive, detailed, and interactive documentation on zero-knowledge proof systems and related primitives." 5 | bookCollapseSection: true 6 | # math: true 7 | # bookFlatSection: false 8 | # bookToc: true 9 | # bookHidden: false 10 | # bookComments: false 11 | # bookSearchExclude: false 12 | --- 13 | # Zero-knowledge protocols 14 | 15 | ZKDocs provides comprehensive, detailed, and interactive documentation on zero-knowledge proof systems and related primitives. 16 | 17 | At [Trail of Bits](https://www.trailofbits.com/), we audit many implementations of non-standardized cryptographic protocols and often find the same issues. As we discovered more instances of these bugs, we wanted to find a way to prevent them in the future. Unfortunately, for these protocols, the burden is on the developers to figure out all of the low-level implementation details and security pitfalls. 18 | 19 | We hope that ZKDocs can fill in this gap and benefit the larger cryptography community. 20 | 21 | {{< hint info >}} 22 | **For in-depth resources and interactive guides on zero-knowledge proof systems, visit https://zkdocs.com.** 23 | {{< /hint >}} 24 | -------------------------------------------------------------------------------- /content/docs/dynamic-analysis/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 3 3 | bookFlatSection: true 4 | title: "Dynamic analysis" 5 | draft: true 6 | --- 7 | 8 | # Dynamic analysis 9 | 10 | Here we present several dynamic analysis tools. For each tool, we cover topics such as: 11 | 12 | - Installation and basic use 13 | - Advanced configuration 14 | - Usage in continuous integration pipelines 15 | 16 | {{< section >}} 17 | -------------------------------------------------------------------------------- /content/docs/fuzzing/5-snapshot/figure1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/5-snapshot/figure1.png -------------------------------------------------------------------------------- /content/docs/fuzzing/5-snapshot/figure2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/5-snapshot/figure2.png -------------------------------------------------------------------------------- /content/docs/fuzzing/5-snapshot/figure3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/5-snapshot/figure3.png -------------------------------------------------------------------------------- /content/docs/fuzzing/5-snapshot/figure4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/5-snapshot/figure4.png -------------------------------------------------------------------------------- /content/docs/fuzzing/5-snapshot/figure5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/5-snapshot/figure5.png -------------------------------------------------------------------------------- /content/docs/fuzzing/5-snapshot/figure6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/5-snapshot/figure6.png -------------------------------------------------------------------------------- /content/docs/fuzzing/5-snapshot/figure7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/5-snapshot/figure7.png -------------------------------------------------------------------------------- /content/docs/fuzzing/91-resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Additional resources" 3 | slug: resources 4 | weight: 7 5 | --- 6 | 7 | 8 | # Additional resources {#additional-resources} 9 | 10 | * **[Awesome fuzzing list 1.](https://github.com/cpuu/awesome-fuzzing)** GitHub-hosted list focused on scientific publications about fuzzing. 11 | * **[Awesome fuzzing list 2.](https://github.com/secfigo/Awesome-Fuzzing)** GitHub-hosted list about fuzzers and fuzzing related books. 12 | * **[Fuzzing handbook.](https://www.fuzzingbook.org/)** A fuzzing handbook written from an academic perspective. 13 | * **[CNCF-Fuzzing handbook.](https://github.com/cncf/tag-security/tree/main/community/resources/security-fuzzing-handbook)**. Handbook created by the CNCF. 14 | * **[Fuzzing101.](https://github.com/antonio-morales/Fuzzing101)** Tutorial and training for various fuzzing methods by GitHub Security Lab. 15 | -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/11-aflpp/aflpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/c-cpp/11-aflpp/aflpp.png -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/12-libafl/libafl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/c-cpp/12-libafl/libafl.png -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "C/C++" 3 | slug: c-cpp 4 | weight: 1 5 | bookCollapseSection: true 6 | --- 7 | 8 | # C/C++ {#c-c} 9 | 10 | In this section, we will discuss how to fuzz C/C++ projects, including how to set up a fuzzer in your project. While there are many options for fuzzing C/C++ projects, we will ground this tutorial in the practical use of libFuzzer and AFL++: two of the most prominent fuzzing tools in use today that can be applied to any C/C++ project. 11 | 12 | For a general introduction about fuzzing and fuzzing setup (e.g., the harness, fuzzer runtime, instrumentation, and SUT), refer to the [introduction]({{% relref "fuzzing#introduction-to-fuzzers" %}}). 13 | 14 | 15 | ## When should I use which fuzzer? {#when-should-i-use-which-fuzzer} 16 | 17 | ||| 18 | |--- |--- | 19 | |**libFuzzer**|Simple; well-tested; basic fuzzing features; limited multi-core fuzzing; libFuzzer is in maintenance-only mode| 20 | |**AFL++**|Well-tested; industry-standard; sufficient for most fuzzing needs; supported multi-core fuzzing; not suited for short fuzzing campaigns (e.g., CI fuzzing) due to initial calibration phase| 21 | |**LibAFL**|Potentially unstable; complex; can adapt to your fuzzing needs; supports cutting-edge fuzzing techniques; supports Android, Windows, and other more unusual fuzzing environments| 22 | {.skip-table-head} 23 | 24 | In a nutshell, libFuzzer is designed to integrate fuzz tests into a project's codebase, making it accessible for developers to write and maintain fuzz tests. AFL++ is more tailored for security experts, which often makes it the preferred choice for security consultants. If you have no fuzzing experience we recommend starting with libFuzzer, because switching over to the more capable AFL++ fuzzer is simple. 25 | 26 | -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/techniques/01-coverage/cov1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/c-cpp/techniques/01-coverage/cov1.png -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/techniques/01-coverage/cov2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/c-cpp/techniques/01-coverage/cov2.png -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/techniques/01-coverage/cov3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/fuzzing/c-cpp/techniques/01-coverage/cov3.png -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/techniques/02-obstacles/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "SUT patching: Overcoming obstacles" 3 | slug: obstacles 4 | weight: 2 5 | --- 6 | 7 | # SUT patching: Overcoming obstacles {#sut-patching-overcoming-obstacles} 8 | 9 | Codebases are often not fuzzing-friendly. This can happen if, for example, the code uses checksums or depends on a global state like a system-time seeded PRNG (i.e., by using [`rand`](https://man.archlinux.org/man/rand.3)) that causes the code to behave differently for the same input. Refer to [Practical harness rules]({{% relref "01-writing-harnesses#practical-harness-rules" %}}) to learn more about potential problems in your SUT. If you encounter checksums or a global state in your SUT, you may want to apply fuzzing-specific patches to change the behavior of the program during fuzzing, as shown in the following paragraphs. 10 | 11 | Typically, C/C++ fuzzers define the macro `FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION`. This is at least true for libFuzzer, AFL++, LibAFL, and Hongfuzz. If the macro is defined, then the program is being compiled for fuzzing. By using conditional compilation based on that macro, you can overcome obstacles in your code, such as hash checks that often hinder fuzzers at covering deeper code paths. The following figure shows an example. 12 | 13 | 14 | 15 | 16 | {{< customFigure "Example usage of `FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION`" >}} 17 | ```C++ 18 | if (checksum != expected_hash) { 19 | // Eliminate the need for guessing checksums by ignoring this error during fuzzing 20 | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 21 | return -1; 22 | #endif 23 | } 24 | 25 | // Continue program execution 26 | ``` 27 | {{< /customFigure >}} 28 | 29 | 30 | Note that this means that your SUT is behaving differently during fuzzing and production. Carelessly skipping checks can lead to false positives during fuzzing. For example, skipping the validation of a config file might lead to crashes in the SUT because the code expects config values to have a certain format. If the validation ensures that the config contains non-zero integers, then code called after the validation could misbehave when zero values are encountered. See the following example for an illustration. 31 | 32 | 33 | 34 | {{< customFigure "Problematic usage of `FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` that skips config validation. This may lead to false positives during fuzzing." >}} 35 | ```C++ 36 | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 37 | if (!validate_config(&config)) { 38 | // return error if config contains zero values 39 | return -1; 40 | } 41 | #endif 42 | 43 | // assume no negative values exist 44 | 45 | int32_t result = 100 / config.x; // Can crash if validation is skipped 46 | ``` 47 | {{< /customFigure >}} 48 | 49 | A real-world use of this variable occurs in the OpenSSL project, which [uses this variable](https://github.com/openssl/openssl/blob/afb19f07aecc84998eeea56c4d65f5e0499abb5a/crypto/cmp/cmp_vfy.c#L665-L678) to change how cryptographic algorithms work. 50 | -------------------------------------------------------------------------------- /content/docs/fuzzing/c-cpp/techniques/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Techniques" 3 | slug: techniques 4 | weight: 3 5 | 6 | # TODO readd this 7 | # ### Techniques {#techniques} 8 | #We now want to review standard techniques for #fuzzing C/C++ projects. These techniques are #essential to get the best out of your fuzzing #campaigns. 9 | --- 10 | -------------------------------------------------------------------------------- /content/docs/fuzzing/rust/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Rust" 3 | slug: rust 4 | weight: 2 5 | bookCollapseSection: true 6 | --- 7 | 8 | 9 | # Rust {#rust} 10 | 11 | Just like C/C++, Rust is a systems programming language. The tool stack for fuzzing is therefore related to the one described in the [C/C++ section]({{% relref "c-cpp" %}}), because fuzzers in Rust may be based on those introduced earlier. 12 | 13 | For a general introduction about fuzzing and setup (i.e., the harness, fuzzer runtime, instrumentation, and SUT), refer to the [introduction]({{% relref "fuzzing#introduction-to-fuzzers" %}}). 14 | 15 | 16 | -------------------------------------------------------------------------------- /content/docs/fuzzing/rust/techniques/01-coverage/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Coverage analysis" 3 | slug: coverage-analysis 4 | weight: 2 5 | --- 6 | 7 | 8 | # Coverage analysis {#coverage-analysis} 9 | 10 | Gaining confidence in your code coverage archived during fuzzing is essential for two reasons. Firstly, you want to assess which parts of your applications your fuzzing harnesses execute. 11 | 12 | For example, a magic value check, like the one shown in the following figure, may be hard for a fuzzer to overcome. Discovering such a check is important so that the values can be provided to the fuzzer through a [dictionary]({{% relref 02-dictionary %}}) or test cases in the seed corpus. 13 | 14 | {{< customFigure "Magic value check that may be difficult to overcome" >}} 15 | ```Rust 16 | if (buf == 0x7F454C46) { 17 | // start parsing buf 18 | } 19 | ``` 20 | {{< /customFigure >}} 21 | 22 | Secondly, when switching your fuzzer or updating your harness or SUT, you want to see whether coverage changes. If coverage decreases, then you may need to extend your harness because new features were introduced. If coverage increases, then you probably improved your harness or the SUT became easier to fuzz. 23 | 24 | Fuzzing coverage is a proxy for the capability and performance of the fuzzer. Even though it is widely accepted that coverage [is not ideal for measuring the performance](https://arxiv.org/abs/1808.09700) of a fuzzing engine, coverage can tell you whether your harness works in a given setup. 25 | 26 | The following flow chart shows an ideal coverage analysis workflow. The workflow uses the corpus generated after each fuzzing campaign to calculate the coverage, which is the preferred method. 27 | 28 | {{< resourceFigure "coverage-flow.svg" "alt" 300>}} 29 | Ideal fuzzing workflow: After each fuzzing campaign the code coverage is evaluated. Based on the results, the SUT or harness is updated and a new fuzzing campaign is started. 30 | {{< /resourceFigure >}} 31 | 32 | {{< hint info >}} 33 | PRO TIP: You should not use the statistics returned by your specific fuzzer to track fuzzing performance over a long time. For example, AFL++ outputs a value that indicates the code coverage. However, this value is non-comparable with other fuzzers because they may calculate this value differently. 34 | 35 | The most comparable data is generated by tools specifically made for measuring coverage. 36 | {{< /hint >}} 37 | 38 | The cargo-fuzz tool can output coverage for your corpus. Based on the acquired coverage data, we can use standard Rust tools to generate an HTML report. 39 | 40 | The cargo-fuzz tool requires the llvm-tools-preview component to be installed for the used nightly toolchain: 41 | 42 | 43 | ```shell 44 | rustup toolchain install nightly --component llvm-tools-preview 45 | ``` 46 | 47 | 48 | Now, use cargo-fuzz to output coverage data. The cargo-fuzz tool will recompile your project with coverage instrumentation and then run through all test cases in the corpus. 49 | 50 | 51 | ```shell 52 | cargo +nightly fuzz coverage fuzz_target_1 53 | ``` 54 | 55 | 56 | The cargo-fuzz tool will report that merged coverage has been written to a `.profdata` file. Next, we need the tools [cargo-binutils](https://github.com/rust-embedded/cargo-binutils) and [rustfilt](https://github.com/luser/rustfilt) installed. 57 | 58 | 59 | ```shell 60 | cargo install cargo-binutils 61 | cargo install rustfilt 62 | ``` 63 | 64 | Create the following script and make it executable. We create a script because the manual invocation of the coverage generation is quite complex. 65 | 66 | 67 | {{< customFigure "Script to generate HTML coverage. The path to the fuzzing binary is defined in the [cargo-fuzz source code](https://github.com/rust-fuzz/cargo-fuzz/blob/c4a4d33181b36bea49e20a9639e801ae88aa59c5/src/project.rs#L289-L295)." >}} 68 | ```sh 69 | cat <<'EOF' > ./generate_html 70 | #!/bin/sh 71 | if [ $# -lt 1 ]; then 72 | echo "Error: Name of fuzz target is required." 73 | echo "Usage: $0 fuzz_target [sources...]" 74 | exit 1 75 | fi 76 | FUZZ_TARGET="$1" 77 | shift 78 | SRC_FILTER="$@" 79 | TARGET=$(rustc -vV | sed -n 's|host: ||p') 80 | cargo +nightly cov -- show -Xdemangler=rustfilt \ 81 | "target/$TARGET/coverage/$TARGET/release/$FUZZ_TARGET" \ 82 | -instr-profile="fuzz/coverage/$FUZZ_TARGET/coverage.profdata" \ 83 | -show-line-counts-or-regions -show-instantiations \ 84 | -format=html -o fuzz_html/ $SRC_FILTER 85 | EOF 86 | chmod +x ./generate_html 87 | ``` 88 | {{< /customFigure >}} 89 | 90 | Finally, we can generate an HTML report and save it to `fuzz_html/`. 91 | 92 | 93 | ```shell 94 | ./generate_html fuzz_target_1 src/lib.rs 95 | ``` 96 | 97 | 98 | {{< hint info >}} 99 | PRO TIP: The following table lists the invoked cargo command in more detail: 100 | ||| 101 | |--- |--- | 102 | |`cargo +nightly cov --`|Invokes the llvm-cov tool from the Rust toolchain| 103 | |`show`|This subcommand can generate HTML reports| 104 | |`-Xdemangler=rustfilt`|Use the [rustfilt](https://github.com/luser/rustfilt) demangler for better function names| 105 | |`"target/$TARGET/coverage/$TARGET/release/$FUZZ_TARGET"`|Path to the instrumented Rust binary or object file| 106 | |`-instr-profile="fuzz/coverage/$FUZZ_TARGET/coverage.profdata"`|Path to the merged coverage data| 107 | |[`-show-line-counts-or-regions`](https://releases.llvm.org/5.0.1/docs/CommandGuide/llvm-cov.html#cmdoption-llvm-cov-show-show-line-counts-or-regions) [`-show-instantiations`](https://releases.llvm.org/5.0.1/docs/CommandGuide/llvm-cov.html#cmdoption-llvm-cov-show-show-instantiations)|Options for Rust to make the output easier to understand| 108 | |`-format=html -o fuzz_html/`|Sets the format to HTML and outputs the HTML files to a directory| 109 | |`src/lib.rs`|Optionally, you can add paths to source files to filter the output. In this case, we are interested only in the lib.rs file.| 110 | {.skip-table-head} 111 | {{< /hint >}} 112 | 113 | ## Real-world examples {#real-world-examples} 114 | 115 | 116 | ### Cargo crate: ogg {#cargo-crate-ogg} 117 | 118 | In a [previous section](#cargo-crate-ogg) we fuzzed the ogg crate. Now we want to evaluate the coverage of our fuzzing campaign to verify we achieved good coverage. 119 | 120 | First, we inspect the corpus and verify that we found test cases. 121 | 122 | 123 | ```shell 124 | ls fuzz/corpus/fuzz_target_1/ | wc -l 125 | ``` 126 | 127 | Then we generate merged coverage data from the corpus: 128 | ```shell 129 | cargo +nightly fuzz coverage fuzz_target_1 130 | ``` 131 | 132 | Finally, we generate an HTML report and use domain knowledge to assess the fuzzing performance by using the `generate_html` script introduced in the [Coverage analysis](#coverage-analysis) section. 133 | 134 | We may need to find more diverse seeds or fix bugs in our harness if the code coverage is unexpectedly low. However, no single number determines bad coverage; this depends significantly on how the crate is written and how difficult it is to reach certain code. 135 | 136 | 137 | -------------------------------------------------------------------------------- /content/docs/fuzzing/rust/techniques/02-obstacles/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "SUT patching: Overcoming obstacles" 3 | slug: obstacles 4 | weight: 2 5 | --- 6 | 7 | 8 | # SUT patching: Overcoming obstacles {#sut-patching-overcoming-obstacles} 9 | 10 | 11 | Codebases are often not fuzzing-friendly. This can happen if, for example, the code uses checksums or depends on a global state like a system-time seeded PRNG (i.e., from the [rand](https://docs.rs/rand/latest/rand/)) that causes the code to behave differently for the same input. Refer to [Practical harness rules]({{% relref "01-writing-harnesses#practical-harness-rules" %}}) to learn more about potential problems in your SUT. If you encounter checksums or a global state in your SUT, you may want to apply fuzzing-specific patches to change the behavior of the program during fuzzing, as shown in the following paragraphs. 12 | 13 | Rust fuzzers define a configuration option that is set during compilation of your Rust project. Similar to the [`cfg!(test)`](https://doc.rust-lang.org/reference/conditional-compilation.html#test) config option, the `cfg!(fuzzing)` option is enabled during fuzzing. You can use conditional compilation to overcome obstacles in your code, like hash checks that often hinder fuzzers at covering deeper code paths. The following figure shows an example. 14 | 15 | {{< customFigure "Example usage of `cfg!(fuzzing)`" >}} 16 | ```Rust 17 | if checksum != expected_hash { 18 | // Eliminate the need for guessing checksums by ignoring this error during fuzzing 19 | if !cfg!(fuzzing) { 20 | return Err(MyError::Hash) 21 | } 22 | } 23 | 24 | // Continue program execution 25 | ``` 26 | {{< /customFigure >}} 27 | 28 | 29 | 30 | Note that this means that your SUT is behaving differently during fuzzing and production. Carelessly skipping checks can lead to false positives during fuzzing. For example, skipping the validation of a config file might lead to crashes in the SUT because the code expects config values to have a certain format. If the validation ensures that the config contains non-zero integers, then code called after the validation could misbehave when zero values are encountered. See the following example for an illustration. 31 | 32 | 33 | {{< customFigure "Problematic usage of `cfg!(fuzzing)` that skips config validation. This may lead to false positives during fuzzing." >}} 34 | ```Rust 35 | if !cfg!(fuzzing) { 36 | config.validate()?; // return error if config contains zero values 37 | } 38 | 39 | // assume no negative values exist 40 | 41 | let result = 100 / config.x; // Can crash if validation is skipped 42 | ``` 43 | 44 | {{< /customFigure >}} 45 | 46 | For instance, the ogg crate uses a `cfg!(fuzzing)` check to [perform checksum checks only if the project is not being fuzzed](https://github.com/RustAudio/ogg/blob/5ee8316e6e907c24f6d7ec4b3a0ed6a6ce854cc1/src/reading.rs#L298-L300). Adding a `cfg!(fuzzing)` check can increase fuzzing coverage greatly, but requires source code modifications. -------------------------------------------------------------------------------- /content/docs/fuzzing/rust/techniques/03-writing-harnesses/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Writing harnesses" 3 | slug: writing-harnesses 4 | weight: 2 5 | --- 6 | 7 | 8 | 9 | 10 | # Writing harnesses {#writing-harnesses} 11 | 12 | In the following, we will go over Rust specific tips to optimize the results from your harnesses. For general advice, refer to [Writing harnesses](#writing-harnesses). 13 | 14 | ## Structure-Aware fuzzing with the arbitrary crate {#structure-aware-fuzzing-with-the-arbitrary-crate} 15 | 16 | 17 | The [arbitrary](https://github.com/rust-fuzz/arbitrary) crate simplifies writing fuzzing harnesses. By deriving a macro, Rust structs can be targeted for fuzzing. For example, the following code requires constructing a `Name` struct that owns a `String`. We derived the Arbitrary macro to facilitate the construction of such a `Name`. 18 | 19 | {{< customFigure "Rust code in the crate `your_project` that uses the arbitrary crate" >}} 20 | ```Rust 21 | use arbitrary::{Arbitrary}; 22 | 23 | #[derive(Debug, Arbitrary)] 24 | pub struct Name { 25 | data: String 26 | } 27 | 28 | impl Name { 29 | pub fn check_buf(&self) { 30 | let data = self.data.as_bytes(); 31 | if data.len() > 0 && data[0] == b'a' { 32 | if data.len() > 1 && data[1] == b'b' { 33 | if data.len() > 2 && data[2] == b'c' { 34 | process::abort(); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | ``` 41 | {{< /customFigure >}} 42 | 43 | With the arbitrary crate, we can easily write a fuzzing harness for this test, similar to the harness in [Write a Fuzz test]({{% relref "10-cargo-fuzz#write-a-fuzz-test" %}}). 44 | 45 | 46 | {{< customFigure "Fuzz test using the arbitrary crate" >}} 47 | ```Rust 48 | #![no_main] 49 | 50 | use libfuzzer_sys::fuzz_target; 51 | use arbitrary::{Arbitrary, Unstructured}; 52 | 53 | fn harness(data: &[u8]) { 54 | // Wrap it in an `Unstructured`. 55 | let mut unstructured = Unstructured::new(data); 56 | 57 | // Generate an `Name` and run our checks. 58 | if let Ok(name) = your_project::Name::arbitrary(&mut unstructured) { 59 | name.check_buf(); 60 | } 61 | } 62 | 63 | fuzz_target!(|data: &[u8]| { 64 | harness(data); 65 | }); 66 | ``` 67 | {{< /customFigure >}} 68 | 69 | The cargo-fuzz tool actually supports the arbitrary crate, so we can simplify this. 70 | 71 | {{< customFigure "Shortened fuzz test using the arbitrary crate" >}} 72 | ```Rust 73 | #![no_main] 74 | 75 | use libfuzzer_sys::fuzz_target; 76 | 77 | fn harness(data: &your_project::Name) { 78 | data.check_buf(); 79 | } 80 | 81 | fuzz_target!(|data: your_project::Name| { 82 | harness(&data); 83 | }); 84 | ``` 85 | {{< /customFigure >}} 86 | 87 | Both of the above examples require the arbitrary crate to be a dependency of your library crate. In the first example, you also need to add the dependency to the `Cargo.toml` in the `fuzz/` directory. The second example does not require this because the arbitrary dependency of the `libfuzzer_sys` dependency is used. Here is the dependency declaration you need: 88 | 89 | 90 | 91 | 92 | {{< customFigure "Dependency declaration for the arbitrary crate" >}} 93 | ```toml 94 | [dependencies] 95 | arbitrary = { version = "1", features = ["derive"] } 96 | ``` 97 | {{< /customFigure >}} 98 | 99 | As usual, the fuzz test can be started using the following command: 100 | 101 | 102 | ```shell 103 | cargo +nightly fuzz run fuzz_target_1 104 | ``` 105 | 106 | 107 | The arbitrary crate essentially offers a way to deserialize byte arrays to Rust structs. However, it is limited in that it does not offer the reverse function: serializing Rust structs to byte arrays. This becomes a problem when trying to prepare a corpus of seeds. It is not possible to purposefully construct byte-arrays that construct a specific Rust struct. 108 | 109 | Therefore, the arbitrary crate is useful only when starting from an empty corpus. This is not an issue when using cargo-fuzz because it uses libFuzzer internally, and libFuzzer supports starting from an empty corpus. However, other fuzzers like AFL++ require a seed input. 110 | 111 | 112 | -------------------------------------------------------------------------------- /content/docs/fuzzing/rust/techniques/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Techniques" 3 | slug: techniques 4 | weight: 3 5 | # TODO readd this 6 | # #### Techniques {#techniques} 7 | # We now want to review standard techniques for fuzzing Rust projects. These techniques are essential when trying to get the most out of your fuzzing campaigns. 8 | --- 9 | -------------------------------------------------------------------------------- /content/docs/fuzzing/techniques/02-dictionary.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Fuzzing dictionary" 3 | slug: dictionary 4 | weight: 2 5 | --- 6 | 7 | # Fuzzing dictionary {#dictionary-fuzzing} 8 | 9 | A dictionary can be used to guide the fuzzer. A dictionary is usually passed as a file to the fuzzer. The simplest input accepted by libFuzzer is a ASCII text file where each line consists of a quoted string. Strings can contain escaped byte sequences like "`\xF7\xF8"`. Optionally, a key-value pair like `hex_value="\xF7\xF8"` can be used for documentation purposes. Comments are supported by starting a line with `#`. See the following example: 10 | 11 | 12 | 13 | {{< customFigure "Example dictionary file. More examples can be found [here](https://github.com/AFLplusplus/AFLplusplus/tree/ef706ad668b36e65d24f352f5bcee22957f5f1cc/dictionaries)" >}} 14 | ```conf 15 | # Lines starting with '#' and empty lines are ignored. 16 | 17 | # Adds "blah" (w/o quotes) to the dictionary. 18 | kw1="blah" 19 | # Use \\ for backslash and \" for quotes. 20 | kw2="\"ac\\dc\"" 21 | # Use \xAB for hex values 22 | kw3="\xF7\xF8" 23 | # the name of the keyword followed by '=' may be omitted: 24 | "foo\x0Abar" 25 | ``` 26 | 27 | {{< /customFigure >}} 28 | 29 | 30 | Dictionaries are compatible between the libFuzzer, cargo-fuzz, and AFL++ fuzzers. They can be used according to the following table: 31 | 32 | 33 | ||| 34 | |--- |--- | 35 | |`libFuzzer`|`./fuzz -dict=./dictionary.dict ...`| 36 | |`AFL++`|`afl-fuzz -x ./dictionary.dict ...`| 37 | |`cargo-fuzz`|`cargo fuzz run fuzz_target -- -dict=./dictionary.dict`| 38 | {.skip-table-head} 39 | 40 | ## Generating a dictionary {#generating-a-dictionary} 41 | 42 | There are several ways to generate a dictionary. 43 | 44 | 45 | 46 | * LLMs (large language models): Tools like OpenAI's ChatGPT are helpful in generating a dictionary for your fuzzing task. However, be aware of LLM hallucinations. If the LLM proposes a feature not mentioned in this handbook, check first if it really exists. Try the following LLM prompt with the task `PNG parser`: 47 | ```text {.code-fence-wrap} 48 | A dictionary can be used to guide the fuzzer. A dictionary is passed as a file to the fuzzer usually. 49 | The simplest input accepted by libFuzzer is an ASCII text file where each line consists of a quoted string. Strings can contain escaped byte sequences like "\xF7\xF8". Optionally, a key-value pair can be used like hex_value="\xF7\xF8" for documentation purposes. Comments are supported by starting a line with #. Write me an example dictionary file for a : 50 | ``` 51 | * Header files: If you found C header file that contains relevant strings, then they can be extracted using the following command: 52 | ```shell 53 | grep -o '".*"' header.h > header.dict 54 | ``` 55 | * Man pages: If the project you are fuzzing has man pages, then you can use these to generate a dictionary. This is especially helpful when fuzzing a CLI. 56 | ```shell 57 | man curl | grep -oP '^\s*(--|-)\K\S+' | sed 's/[,.]$//' | sed 's/^/"&/; s/$/&"/' | sort -u > man.dict 58 | ``` 59 | * AFL++ [AUTODICTIONARIES](https://github.com/AFLplusplus/AFLplusplus/blob/108fb0b29ad1586e668ba23e23a0eb1a13c45c49/instrumentation/README.lto.md#autodictionary-feature): If you are using `afl-clang-lto`, then AFL++ will automatically generate a dictionary based on the binary that is being fuzzed. 60 | * If you are not using AFL++, then you might want to use the strings binary to generate dictionary: 61 | ```shell 62 | strings ./binary | sed 's/^/"&/; s/$/&"/' > strings.dict 63 | ``` -------------------------------------------------------------------------------- /content/docs/fuzzing/techniques/03-asan.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "AddressSanitizer" 3 | slug: asan 4 | weight: 3 5 | --- 6 | 7 | 8 | # AddressSanitizer {#addresssanitizer} 9 | 10 | 11 | AddressSanitizer (ASan) is a widely adopted tool in the realm of software testing, particularly during fuzzing. Fuzzing greatly benefits from the use of ASan because it helps detect memory errors that might otherwise go unnoticed, such as buffer overflows and use-after-free errors. 12 | 13 | While ASan is a standard practice in fuzzing due to its effectiveness in identifying such vulnerabilities, it does come with certain drawbacks. 14 | 15 | 16 | 17 | * One significant downside is that it can make the fuzzing process approximately 2–4 times slower. This reduction in speed is a tradeoff for the increased reliability and depth of testing. 18 | * ASan is not well supported on platforms other than Linux (i.e., Windows and macOS). 19 | * ASan maps a large amount of virtual memory from the operating system, typically requiring around 20TB. (This amount used to be 16TB, or 1/8th of the address space; [see AddressSanitizer: A Fast Address Sanity Checker](https://www.usenix.org/sites/default/files/conference/protected-files/serebryany_atc12_slides.pdf).) Because of this, you need to disable memory restrictions imposed by the fuzzer you use (e.g., `-rss_limit_mb 0` for libFuzzer and `-m none` for AFL++). 20 | 21 | 22 | Despite these limitations, the benefits of using ASan during fuzzing to enhance software security and reliability by improving memory error detection capabilities often outweigh the drawbacks, making it a valuable tool in the software development lifecycle. 23 | 24 | Note that it can also make sense to enable ASan for your unit tests. However, do not use ASan during production, because it can [make applications actually less secure](https://www.openwall.com/lists/oss-security/2016/02/17/9). ASan is primarily a detection tool. 25 | 26 | In general, ASan is enabled by using the flag `-fsanitize=address` during compilation and linking. However, integration can differ between fuzzers. Therefore, refer to the following sections: 27 | 28 | * C/C++ 29 | * [libFuzzer: AddressSanitizer]({{% relref "/docs/fuzzing/c-cpp/10-libfuzzer#addresssanitizer" %}}) 30 | * [AFL++: AddressSanitizer]({{% relref "/docs/fuzzing/c-cpp/11-aflpp#addresssanitizer" %}}) 31 | * Rust: 32 | * [cargo-fuzz: AddressSanitizer]({{% relref "/docs/fuzzing/rust/10-cargo-fuzz#addresssanitizer" %}}) 33 | 34 | ASan is documented on the [Google GitHub](https://github.com/google/sanitizers/wiki/AddressSanitizer). If you want to learn more about flags to configure ASan via the `ASAN_OPTIONS` environment variable, refer to [this page](https://github.com/google/sanitizers/wiki/SanitizerCommonFlags) for common sanitizer flags and [that page](https://github.com/google/sanitizers/wiki/AddressSanitizerFlags) for ASan flags specifically. An example configuration looks like this: 35 | 36 | 37 | ```shell 38 | ASAN_OPTIONS=verbosity=1:abort_on_error=1 39 | ``` 40 | 41 | The most commonly used flags are: 42 | 43 | * `verbosity=1`: Prints information before the actual program starts. Useful to check if a binary is sanitized by checking if output from ASan is printed. 44 | * `detect_leaks=0`: Controls whether the [leak sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer) is enabled. Leaks do not immediately lead to a crash in the fuzzer, but results about leaks are printed at the end of the fuzzing campaign. 45 | * `abort_on_error=1`: Calls [`abort`](https://man.archlinux.org/man/abort.3p) instead of [`_exit`](https://man.archlinux.org/man/_exit.2) after printing errors. This is useful for some fuzzers that require calling [`abort`](https://man.archlinux.org/man/abort.3p). 46 | 47 | The [FAQ on GitHub](https://github.com/google/sanitizers/wiki/AddressSanitizer#faq) summarizes the most common pitfalls when using ASan. 48 | 49 | If you are using Clang refer to its [documentation](https://clang.llvm.org/docs/AddressSanitizer.html). If using GCC, then additionally refer to this [documentation](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fsanitize_003daddress). -------------------------------------------------------------------------------- /content/docs/fuzzing/techniques/04-env.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Fuzzing environments" 3 | slug: environments 4 | weight: 4 5 | --- 6 | 7 | # Fuzzing environments {#fuzzing-environments} 8 | 9 | Like any software, the choice of fuzzer will depend on factors such as the operating system, architecture, software versions, and hardware. This section will review factors that influence the choice of the environment used for fuzzing. 10 | 11 | **Choice of hardware.** If your fuzzer supports running on multiple cores, choose hardware that has many cores available. [Renting](https://www.hetzner.com/sb?country=us) or purchasing a bare-metal server might be worthwhile if you plan to run campaigns regularly. If not, then [renting](https://www.digitalocean.com/pricing/droplets#cpu-optimized) VMs with many dedicated cores is probably the better choice. 12 | 13 | Keep in mind that achieving many executions per second of your SUT probably outweighs any smart tricks you can apply to your fuzzing setup! Execution speed is crucial. 14 | 15 | **Choice of environment.** Ideally, you will fuzz in the same environment that the users of your SUT use. However, to simplify fuzzing it, might be acceptable to fuzz your SUT on Linux even though it usually runs on Windows or macOS. For instance, forking a process on macOS is [slower than on Linux](https://github.com/AFLplusplus/AFLplusplus/blob/358cd1b062e58ce1d5c8efeef4789a5aca7ac5a9/GNUmakefile#L589) (although this may not be an issue, depending on your fuzzer). 16 | 17 | A general caveat of many operating systems (including Linux) is that executions per second may not scale linearly with the amount of cores you are using if the SUT interacts with the kernel (e.g., through system calls). If your SUT heavily communicates with the kernel, consider fuzzing on multiple VMs, each of which runs a separate kernel. A rough guideline is that if you fuzz on more than 24 cores, you may want to use multiple VMs. Note that this is relevant only for fuzzers that generally scale well with multiple cores like LibAFL. 18 | 19 | As an example, consider a game engine that supports all platforms. In this case, the easiest choice is to fuzz on Linux, because that is the best supported platform overall. However, doing so may miss bugs that affect only Windows. This is a tradeoff you have to make. Starting with the easiest environment and then iteratively fuzzing on other platforms is a good choice. 20 | 21 | **A word about Docker.** Docker offers a good way of encapsulating the user space. However, it does not encapsulate the kernel space. Fuzzers like AFL++ configure the system and kernel in a specific way, for example to avoid persisting core dumps to disk. This means that if you use the Docker host for more than fuzzing, or if you run multiple fuzzing campaigns in parallel using multiple Docker containers, you might run into issues: the kernel runtime configuration modified by AFL++ will impact the whole system, including other containers. 22 | 23 | The question of whether or not to use Docker also relates to the first point we made earlier in this section, which is the **choice of environment**. If your application typically runs in Docker, you may want to fuzz in a Docker container. 24 | 25 | We recommend fuzzing in Linux VMs if possible, because they offer better isolation than containers. Performance-wise, the difference between running in a [privileged](https://docs.docker.com/engine/reference/commandline/run/#privileged) Docker container and a VM is negligible, if native virtualization with the same host and guest architecture is used. However, note that the usage of default configured Docker comes with up to a 50% reduction in performance. Fuzzing in Docker can be slower if the container is not [privileged](https://docs.docker.com/engine/reference/commandline/run/#privileged) or disables [security features](https://mamememo.blogspot.com/2020/05/cpu-intensive-rubypython-code-runs.html). 26 | 27 | **Fuzzing in VMs.** If the fuzzing environment should use Linux, you will achieve more robust results by creating separate VMs for each fuzzing project or fuzzing campaign. You may want to experiment with the Trail of Bits' tool [cloudexec](https://github.com/crytic/cloudexec) to distribute tasks across several cloud VMs. 28 | 29 | Note that if you are using Docker Desktop on an Apple device, you are actually [launching a VM internally](https://www.docker.com/blog/the-magic-behind-the-scenes-of-docker-desktop/) that is isolated from your macOS system. -------------------------------------------------------------------------------- /content/docs/fuzzing/techniques/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Techniques" 3 | slug: techniques 4 | weight: 5 5 | permalink: docs/fuzzing/techniques/writing-harnesses 6 | bookCollapseSection: true 7 | # TODO readd this 8 | # ## Techniques {#techniques} 9 | # We now want to review general standard techniques to uplevel your fuzzing efficiency. 10 | --- 11 | -------------------------------------------------------------------------------- /content/docs/static-analysis/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 2 3 | bookFlatSection: true 4 | title: "Static analysis" 5 | --- 6 | 7 | # Static analysis 8 | 9 | This section presents several static analysis tools. For each tool, we cover topics such as: 10 | 11 | - Installation and basic use 12 | - Advanced configuration 13 | - Usage in continuous integration pipelines 14 | 15 | {{< section >}} 16 | -------------------------------------------------------------------------------- /content/docs/static-analysis/codeql/20-ci.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Continuous integration" 3 | slug: continuous-integration 4 | summary: "This section describes the process of integrating CodeQL into your continuous integration and continuous delivery (CI/CD) pipeline." 5 | weight: 20 6 | --- 7 | 8 | # Continuous Integration 9 | 10 | ## CI/CD integration 11 | 12 | In this chapter, we will walk you through the process of enabling code scanning 13 | with CodeQL for your GitHub repository. 14 | 15 | {{< hint info >}} 16 | Code scanning is available for public GitHub repositories. Code scanning is also 17 | available for private repositories owned by organizations with a GitHub Advanced 18 | Security license. For more details we refer to the official documentation on 19 | [GitHub Advanced Security](https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security). 20 | {{< /hint >}} 21 | 22 | ### Code scanning with CodeQL 23 | 24 | GitHub code scanning is a static-analysis framework powered by CodeQL. By 25 | enabling code scanning for your repository, you will automatically be notified 26 | about any issues detected by the framework. To enable code scanning for a GitHub 27 | repository, navigate to "Code security and analysis" on the GitHub repository 28 | settings page and enable "GitHub Advanced Security." This allows you to set up 29 | code scanning with CodeQL. 30 | 31 | {{< figure src="/code-scanning-setup.png" alt="Code scanning dialog in the GitHub settings page" >}} 32 | 33 | The code scanning dialog allows you to set up code scanning with either a 34 | default or custom configuration. The default configuration is a good starting 35 | point and will enable a set of query suites based on the language used in the 36 | repository. 37 | 38 | The default configuration is a simple way to get started with code scanning, 39 | but may not always work for more complex projects. In particular, if the project 40 | contains code in a compiled language like C or C++, the automatic setup may fail 41 | to detect the build system used by the project. 42 | 43 | If automatic setup fails, or if you would like to use custom queries as part of 44 | code scanning, we recommend using the advanced setup option. This will add to the repository a new 45 | code scanning workflow configuration that can be edited to 46 | add additional languages, custom build scripts, and new query packs. 47 | 48 | ```yaml 49 | name: "CodeQL" 50 | 51 | on: 52 | push: 53 | branches: [ "main" ] 54 | pull_request: 55 | branches: [ "main" ] 56 | schedule: 57 | - cron: '34 10 * * 6' 58 | 59 | jobs: 60 | analyze: 61 | name: Analyze 62 | 63 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 64 | timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} 65 | 66 | permissions: 67 | actions: read 68 | contents: read 69 | security-events: write 70 | 71 | strategy: 72 | fail-fast: false 73 | matrix: 74 | language: [ 'cpp' ] 75 | # If your project contains more than one language supported by CodeQL you simply 76 | # list all of the language identifiers here. The workflow will run once for each 77 | # included language. 78 | 79 | steps: 80 | - name: Checkout repository 81 | uses: actions/checkout@v3 82 | 83 | # Initializes the CodeQL tools for scanning. 84 | - name: Initialize CodeQL 85 | uses: github/codeql-action/init@v2 86 | with: 87 | languages: ${{ matrix.language }} 88 | # If you wish to specify custom queries, you can do so here or in a config file. 89 | # By default, queries listed here will override any specified in a config file. 90 | # Prefix the list here with "+" to use these queries and those in the config file. 91 | 92 | # queries: security-extended,security-and-quality 93 | 94 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). 95 | # If this step fails, then you should remove it and run the build manually (see below) 96 | - name: Autobuild 97 | uses: github/codeql-action/autobuild@v2 98 | 99 | # If the Autobuild fails above, remove it and uncomment the following three lines, 100 | # suitably modified to build the codebase. 101 | 102 | # - run: | 103 | # echo "Run, Build Application using script" 104 | # ./location_of_script_within_repo/buildscript.sh 105 | 106 | - name: Perform CodeQL Analysis 107 | uses: github/codeql-action/analyze@v2 108 | with: 109 | category: "/language:${{matrix.language}}" 110 | ``` 111 | 112 | For compiled languages, you may need to update the workflow configuration by 113 | replacing the autobuild job with a custom build command or script, as indicated 114 | above. 115 | 116 | ### Code scanning with custom queries 117 | 118 | To configure the query suites and query packs used by code scanning, you need to 119 | choose the advanced option and manually specify the query packs to run. This is 120 | done by editing the "Initialize CodeQL" section of the workflow configuration. 121 | It is possible to specify query suites and individual queries using `queries`, 122 | as well as published query packs using `packs`. 123 | 124 | ```yaml 125 | - uses: github/codeql-action/init@v2 126 | with: 127 | queries: security-extended,security-and-quality 128 | packs: trailofbits/cpp-queries 129 | ``` 130 | 131 | This example adds `security-extended` and `security-and-quality` query suites 132 | from GitHub, as well as the `trailofbits/cpp-queries` query pack. 133 | 134 | ### Code scanning with repository local queries 135 | 136 | It is also possible to include queries from the current repository as part of 137 | code scanning. For example, if the repository contains the CodeQL query 138 | `codeql/UnhandledError.ql`, this can be run as part of the code scanning 139 | workflow by adding the query to the workflow configuration under `queries` 140 | as follows: 141 | 142 | ```yaml 143 | - uses: github/codeql-action/init@v2 144 | with: 145 | queries: ./codeql/UnhandledError.ql 146 | packs: trailofbits/cpp-queries 147 | ``` 148 | 149 | The code scanning results will now include any issues identified by the 150 | local `UnhandledError.ql` query as well as any issues identified by the 151 | `trailofbits/cpp-queries` query pack. 152 | 153 | {{< hint info >}} 154 | Note the `.` at the start of the query path. This is needed to identify the 155 | query name as a repository relative path. 156 | {{< /hint >}} 157 | 158 | {{< hint info >}} 159 | Remember that all queries must be part of a query pack. For queries checked 160 | in to the current repository, this means that there must be a corresponding 161 | `qlpack.yml` file checked in to the root directory of the corresponding query 162 | pack. 163 | 164 | For more information on `qlpack.yml` files, see 165 | [Creating new query packs]({{< relref "10-advanced#creating-new-query-packs" >}}). 166 | {{< /hint >}} 167 | 168 | {{< hint info >}} 169 | If you have more than one or two repository local queries that you would like 170 | to run as part of CI/CD, it is probably better to install the query pack locally 171 | using `codeql pack install` and then specify the name of the query pack directly 172 | in the workflow configuration under `packs`. 173 | {{< /hint >}} 174 | 175 | ### Triaging code scanning results 176 | 177 | Code scanning results can be found under the "Security" tab in your repository. 178 | 179 | It is also possible to set up branch protection rules based on code scanning 180 | results on the repository settings page under "Code Security and Analysis." 181 | 182 | {{< figure src="/code-scanning-protection.png" alt="Code scanning dialog in the GitHub settings page" >}} 183 | -------------------------------------------------------------------------------- /content/docs/static-analysis/codeql/99-resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Additional resources" 3 | slug: resources 4 | summary: "Learn more about CodeQL using the external resources listed on this page." 5 | weight: 99 6 | --- 7 | 8 | # Additional Resources 9 | 10 | ## Publications 11 | 12 | ### Trail of Bits blog posts on CodeQL 13 | 14 | - [Look out! Divergent representations are everywhere!](https://blog.trailofbits.com/2022/11/10/divergent-representations-variable-overflows-c-compiler/) 15 | - [Finding unhandled errors using CodeQL](https://blog.trailofbits.com/2022/01/11/finding-unhandled-errors-using-codeql/) 16 | - [Detecting iterator invalidation with CodeQL](https://blog.trailofbits.com/2020/10/09/detecting-iterator-invalidation-with-codeql/) 17 | 18 | ### Learning resources for CodeQL 19 | 20 | - [CodeQL zero to hero part 1: The fundamentals of static analysis for vulnerability research](https://github.blog/2023-03-31-codeql-zero-to-hero-part-1-the-fundamentals-of-static-analysis-for-vulnerability-research/) 21 | - [QL language tutorials](https://codeql.github.com/docs/writing-codeql-queries/ql-tutorials/) 22 | - [GitHub Security Lab CodeQL CTFs](https://securitylab.github.com/ctf/) 23 | 24 | ### Writing custom CodeQL queries 25 | 26 | - [Practical introduction to CodeQL](https://jorgectf.github.io/blog/post/practical-codeql-introduction/) 27 | - [Security code reviewing with CodeQL](https://web.archive.org/web/20240529182656/https://remcovermeulen.com/posts/security-code-reviewing-with-codeql/) 28 | - [Sharing security expertise through CodeQL packs (Part I)](https://github.blog/2022-04-19-sharing-security-expertise-through-codeql-packs-part-i/) 29 | - :cinema: [Finding Security Vulnerabilities in C/C++ with CodeQL](https://www.youtube.com/watch?v=eAjecQrfv3o) 30 | - :cinema: [Finding Security Vulnerabilities in JavaScript with CodeQL](https://www.youtube.com/watch?v=pYzfGaLTqC0) 31 | - :cinema: [Finding Security Vulnerabilities in Java with CodeQL](https://www.youtube.com/watch?v=nvCd0Ee4FgE) 32 | 33 | ### Using CodeQL for vulnerability discovery 34 | 35 | - [Clang checkers and CodeQL queries for detecting untrusted pointer derefs and tainted loop conditions](https://www.zerodayinitiative.com/blog/2022/2/22/clang-checkers-and-codeql-queries-for-detecting-untrusted-pointer-derefs-and-tainted-loop-conditions) 36 | - [Vulnerability digging with CodeQL](https://mogwailabs.de/en/blog/2021/09/vulnerability-digging-with-codeql/) 37 | - [Make memcpy safe again: CodeQL](https://web.archive.org/web/20231203081719/https://www.cyberark.com/resources/threat-research-blog/make-memcpy-safe-again-codeql) 38 | 39 | ### CodeQL in CI/CD 40 | 41 | - [Blue-teaming for Exiv2: adding custom CodeQL queries to code scanning](https://github.blog/2021-11-16-adding-custom-codeql-queries-code-scanning/) 42 | - [Best practices on rolling out code scanning at enterprise scale](https://github.blog/2022-09-28-best-practices-on-rolling-out-code-scanning-at-enterprise-scale/) 43 | - [Fine tuning CodeQL scans using query filters](https://colinsalmcorner.com/fine-tuning-codeql-scans/) 44 | - [Ignore files in GitHub CodeQL analysis](https://josh-ops.com/posts/github-codeql-ignore-files/) 45 | -------------------------------------------------------------------------------- /content/docs/static-analysis/codeql/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "CodeQL" 3 | weight: 2 4 | summary: "CodeQL is a static analysis tool that transforms code into a relational database, and provides a custom declarative language to query this database." 5 | bookCollapseSection: true 6 | --- 7 | 8 | # CodeQL 9 | 10 | CodeQL is a powerful static analysis framework that allows developers and 11 | security researchers to query a codebase for specific code patterns. The 12 | CodeQL standard libraries are included with the installation and implement 13 | support for both inter- and intraprocedural control flow and data flow analysis. 14 | However, be aware that the learning curve for writing your own custom queries 15 | is steep, and documentation for the CodeQL standard libraries is still scant. 16 | 17 | {{< hint info >}}🎥 Watch the Trail of Bits Webinar on 18 | [Introduction to CodeQL: Examples, Tools and CI Integration](https://www.youtube.com/watch?v=rQRlnUQPXDw), 19 | where we show you how we used CodeQL to find real-world security issues, 20 | the tools needed for an effective CodeQL experience, and how to set up your CodeQL CI integration 21 | {{< /hint >}} 22 | 23 | {{< hint danger >}} 24 | 25 | If you are planning to run CodeQL on a closed-source repository, you may need 26 | a GitHub Enterprise or GitHub Advanced Security license. (For details, see the 27 | [CodeQL installation instructions](https://docs.github.com/en/code-security/codeql-cli/getting-started-with-the-codeql-cli/setting-up-the-codeql-cli#1-download-the-codeql-cli-zip-package) 28 | and the 29 | [CodeQL license](https://github.com/github/codeql-cli-binaries/blob/main/LICENSE.md).) 30 | 31 | {{< /hint >}} 32 | 33 | ## Benefits of using CodeQL 34 | 35 | - Supports interprocedural control flow and data flow queries across the entire 36 | codebase 37 | - Allows for fine-grained control over the abstract syntax tree, control flow 38 | graph, and data flow graph 39 | - Comes with a large set of libraries and predefined queries for each supported 40 | language 41 | - Prevents the introduction of known bugs and security vulnerabilities into the 42 | codebase 43 | - Easily added to CI/CD pipelines 44 | 45 | ## Ideal use case 46 | 47 | The following questions can help answer whether CodeQL is the right tool to 48 | identify variants of a given bug type: 49 | 50 | - Do you have access to the source code and any third-party dependencies, and 51 | (for compiled languages) can you build the project? 52 | - Are you analyzing an open-source codebase, or is the use of CodeQL covered by 53 | a GitHub Enterprise or GitHub Advanced Security license? 54 | - Does CodeQL [support the languages](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks) 55 | used in your project? 56 | - Does the bug class require either fine-grained control of the abstract syntax 57 | tree, or interprocedural control flow or data flow analysis to express? 58 | - Is analysis time not important? (Complex, interprocedural queries may 59 | take a long time to run.) 60 | 61 | If the answer to any of these questions is "no," we recommend that you start 62 | out by attempting to model the bug class using a tool like [Semgrep]({{% relref 63 | "semgrep" %}}) instead. 64 | -------------------------------------------------------------------------------- /content/docs/static-analysis/semgrep/99-resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Additional resources" 3 | slug: resources 4 | summary: "Learn more about Semgrep using the external resources listed on this page." 5 | weight: 99 6 | --- 7 | 8 | # Additional Resources 9 | 10 | ## Suggested rules 11 | 12 | - [Official Semgrep rules registry](https://semgrep.dev/explore) 13 | - [Trail of Bits public Semgrep rules](https://github.com/trailofbits/semgrep-rules) 14 | - [dgryski Go rules for Semgrep](https://github.com/dgryski/semgrep-go) 15 | - [0xdea/semgrep-rules](https://github.com/0xdea/semgrep-rules) 16 | - [elttam/semgrep-rules](https://github.com/elttam/semgrep-rules) 17 | - [kondukto-io/semgrep-rules](https://github.com/kondukto-io/semgrep-rules) 18 | - [federicodotta/semgrep-rules](https://github.com/federicodotta/semgrep-rules) 19 | - [mindedsecurity/semgrep-rules-android-security](https://github.com/mindedsecurity/semgrep-rules-android-security) 20 | 21 | ## Trail of Bits blog posts on Semgrep 22 | 23 | - [Discovering goroutine leaks with Semgrep](https://blog.trailofbits.com/2021/11/08/discovering-goroutine-leaks-with-semgrep/) 24 | - [Secure your machine learning with Semgrep](https://blog.trailofbits.com/2022/10/03/semgrep-maching-learning-static-analysis/) 25 | - [Secure your Apollo GraphQL server with Semgrep](https://blog.trailofbits.com/2023/08/29/secure-your-apollo-graphql-server-with-semgrep/) 26 | - [How to introduce Semgrep to your organization](https://blog.trailofbits.com/2024/01/12/how-to-introduce-semgrep-to-your-organization/) 27 | 28 | ## Publications 29 | 30 | ### Official Semgrep resources 31 | 32 | - [Rule updates | Semgrep](https://semgrep.dev/docs/release-notes/rule-updates/) 33 | - [Official Semgrep blog](https://semgrep.dev/blog/) 34 | 35 | ### Introduction to Semgrep 36 | 37 | - [A Practical Introduction to Semgrep](https://bernardoamc.com/semgrep-introduction/) 38 | - :cinema: [Semgrep: a lightweight static analysis tool for security consultant and hackers](https://www.youtube.com/watch?v=O5mh8j7-An8) 39 | - :cinema: [Detect complex code patterns using semantic grep](https://www.youtube.com/watch?v=IFRp2Y3cqOw) 40 | - :cinema: [Semgrep part 1 - Embrace Secure Defaults, Block Anti-patterns and more](https://www.youtube.com/watch?v=EIjoqwT53E4) 41 | - :cinema: [OCaml Workshop 2021 - Semgrep a fast lightweight polyglot static analysis tool to find bugs](https://www.youtube.com/watch?v=q7kuvyAOk78) 42 | - :cinema: [Detect Complex Code Patterns Using Semantic Grep - OWASP ATL Meeting](https://www.youtube.com/watch?v=khDPovU4YAU) 43 | 44 | ### Semgrep in the organization 45 | 46 | - [How Two Interns Are Helping Secure Millions of Lines of Code](https://slack.engineering/how-two-interns-are-helping-secure-millions-of-lines-of-code/) 47 | - :cinema: [Workshop: Scaling your AppSec Program with Semgrep](https://www.youtube.com/watch?v=DfU1SFfNrU0) 48 | - :cinema: [Scaling Your Security Program with Semgrep](https://www.youtube.com/watch?v=kb8oo7Wyk84) 49 | - :cinema: [How to Eradicate Vulnerability Classes with Secure Defaults + Lightweight Enforcement](https://www.youtube.com/watch?v=aFuvZw250_g) 50 | 51 | ### Creating custom Semgrep rules 52 | 53 | - [11 Semgrep Rules for Go Web Projects](https://web.archive.org/web/20231201073324/https://universalglue.dev/posts/semgrep-rules-for-go-web-projects/) 54 | - [Detecting Android Content Provider APIs with Semgrep Rules](https://shivasurya.me/security/android/android-security/2022/11/28/android-content-provider-semgrep-detection.html) 55 | - [Enforcing Code & Security Standards with Semgrep](https://owasp.org/www-chapter-newcastle-uk/presentations/2021-02-23-semgrep.pdf) 56 | - [Using Semgrep to find security issues and misconfiguration in AWS Cloud Development Kit projects](https://blog.aquia.io/blog/2022-02-18-semgrep-cdk/) 57 | - [Spring Actuator Security, Part 2: Finding Actuators using Static Code Analysis with Semgrep](https://blog.maass.xyz/spring-actuator-security-part-2-finding-actuators-using-static-code-analysis-with-semgrep) 58 | - [Semgrep ruleset for C/C++ vulnerability research](https://security.humanativaspa.it/semgrep-ruleset-for-c-c-vulnerability-research/) 59 | - [Customizing Semgrep Rules for Flask/Django and Other Popular Web Frameworks](https://blog.includesecurity.com/2021/07/customizing-semgrep-rules-for-flask-django/) 60 | - [Semgrep: scanning unusual extensions](https://blog.anantshri.info/semgrep-scanning-unusuals-extensions/) 61 | - [Semgrep - Matching JavaScript Imports](https://www.ayrx.me/semgrep-javascript-imports/) 62 | - [Linting naked returns with Semgrep](https://jemtucker.com/blog/linting-naked-returns-with-semgrep) 63 | - [Ensuring postMessage Origin Validation with Semgrep](https://bernardoamc.com/semgrep-post-message/) 64 | - :cinema: [Semgrep Weekly Wednesday Office Hours: Modifying Rules to Reduce False Positives](https://www.youtube.com/watch?v=VSL44ZZ7EvY) 65 | 66 | ### Semgrep in vulnerability discovery 67 | 68 | - [Automating binary vulnerability discovery with Ghidra and Semgrep](https://security.humanativaspa.it/automating-binary-vulnerability-discovery-with-ghidra-and-semgrep/) 69 | - :cinema: [Raining CVEs On WordPress Plugins With Semgrep | Nullcon Goa 2022](https://www.youtube.com/watch?v=RvKLn2ofMAo) 70 | - :cinema: [Automating Android App Vulnerability Discovery with Semgrep](https://www.youtube.com/watch?v=7ArHXmMITb0) 71 | 72 | ### Semgrep in CI/CD 73 | 74 | - :cinema: [Using Semgrep and Jenkins for Static Code Analysis](https://www.youtube.com/watch?v=X7_jiKsLkHs) 75 | - :cinema: [Adding in Semgrep SAST job and configuring custom rules](https://www.youtube.com/watch?v=Ip6knn_8NDw) 76 | -------------------------------------------------------------------------------- /content/docs/static-analysis/semgrep/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Semgrep" 3 | weight: 2 4 | summary: "Semgrep is a fast and open source static analysis tool for finding bugs, detecting vulnerabilities in third-party dependencies, and enforcing code standards." 5 | bookCollapseSection: true 6 | --- 7 | 8 | # Semgrep 9 | 10 | Semgrep is a highly efficient static analysis tool for finding low-complexity bugs and locating specific code patterns. 11 | Because of its ease of use, no need to build the code, multiple built-in rules, and convenient creation of custom rules, 12 | it is usually the first tool to run on an audited codebase. Furthermore, Semgrep's integration into the CI/CD pipeline 13 | makes it a good choice for ensuring code quality. 14 | 15 | {{< hint info >}}🎥 Watch the Trail of Bits Webinar on [Introduction to Semgrep](https://www.youtube.com/watch?v=yKQlTbVlf0Q), 16 | where we guide you on effectively bootstrapping Semgrep, the first section in this testing handbook{{< /hint >}} 17 | 18 | ## Benefits of using Semgrep 19 | 20 | - Prevents re-entry of known bugs and security vulnerabilities 21 | - Enables large-scale code refactoring, such as upgrading deprecated APIs 22 | - Easily added to the CI/CD pipelines 23 | - Custom Semgrep rules mimic the semantics of actual code 24 | - Allows for secure scanning without sharing code with third parties, suitable for closed-source repositories 25 | - Can be extended with new languages 26 | (see: [How Two Interns Are Helping Secure Millions of Lines of Code - Slack Engineering](https://slack.engineering/how-two-interns-are-helping-secure-millions-of-lines-of-code/)) 27 | or built upon for creating new tools (e.g., [NodeJsScan](https://github.com/ajinabraham/nodejsscan) or [GuardDog](https://github.com/DataDog/guarddog)) 28 | - Scanning with Semgrep usually takes minutes (not hours/days) 29 | - Semgrep is easy to use and accessible for both developers and security professionals, 30 | offering a seamless first-time experience for average users 31 | - Semgrep has an open-source engine and rules 32 | - Helps maintain high code quality standards and streamline the on-boarding of new developers 33 | 34 | ## Ideal use case 35 | 36 | The following questions can help you determine if Semgrep is the right tool for finding a particular type of bug: 37 | 38 | - Does Semgrep support the [languages](https://semgrep.dev/docs/supported-languages/#language-maturity) 39 | or [technologies](https://semgrep.dev/docs/contributing/contributing-to-semgrep-rules-repository/#technology) in your project? 40 | - Does the bug follow easy-to-identify patterns? 41 | - Can you identify the bug by looking at single files? 42 | - Can you spot the bug via intraprocedural (within a single file) analysis? 43 | - Is the bug systemic (multiple instances across the codebase)? 44 | - Do you want to detect the (lack of) use of secure defaults? 45 | 46 | The following questions can help you determine if you can write a custom Semgrep rule for your problem: 47 | 48 | - Can we detect a specific security vulnerability? 49 | - Can we enforce best practices/conventions or maintain code consistency? 50 | - Can we optimize the code by detecting code patterns that affect performance? 51 | - Can we validate a specific business requirement or constraint? 52 | - Can we identify deprecated/unused code? 53 | - Can we spot any misconfiguration in a configuration file? 54 | - Is this a recurring question as you review your code? 55 | - How is code documentation handled, and what are the requirements for documentation? 56 | - What are some common coding practices that are discouraged in your codebase? 57 | 58 | Support for the following cases is currently limited. Although development is ongoing, Semgrep may not be able to handle: 59 | 60 | - When multiple files are required for your analysis 61 | - Consider using the [Semgrep Pro Engine](https://semgrep.dev/docs/semgrep-code/semgrep-pro-engine-intro/) 62 | - When you need advanced flow analysis 63 | - Familiarize yourself with the [Semgrep dataflow analysis engine](https://semgrep.dev/docs/writing-rules/data-flow/data-flow-overview/) 64 | - Complex taint tracking 65 | - Check out the current state of 66 | [Semgrep taint tracking](https://semgrep.dev/docs/writing-rules/data-flow/taint-mode/) status 67 | - If you have a custom, in-house framework that is not open source 68 | -------------------------------------------------------------------------------- /content/docs/template.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Template" 3 | weight: 1 4 | draft: true 5 | # bookFlatSection: false 6 | # bookToc: true 7 | # bookHidden: false 8 | # bookCollapseSection: false 9 | # bookComments: false 10 | # bookSearchExclude: false 11 | --- 12 | 13 | # Awesome Tool Name Here 14 | 15 | Describe the tool at a high level. 16 | 17 | ## Ideal use case 18 | 19 | When is it ideal to use `` instead of a different tool? 20 | 21 | ## Initial setup 22 | 23 | Quick and easy setup steps here 24 | 25 | ## Running `` 26 | 27 | ## Optimizing `` 28 | 29 | Overall description of how to customize ``, with subsections as needed here. See [semgrep.md] as an example of 30 | what to enter in this section. 31 | 32 | ## CI/CD integration 33 | 34 | Describe how to setup and use `` in CI/CD 35 | 36 | ## Resources 37 | 38 | ### Recommended rules/queries/etc 39 | 40 | Any additional resources useful for developers, DevOps engineers, or security professionals for using this ``. 41 | -------------------------------------------------------------------------------- /content/docs/web/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 2 3 | bookFlatSection: true 4 | title: "Web application security" 5 | --- 6 | 7 | # Web application security 8 | 9 | This section presents web application security tools. For each tool, we cover topics such as: 10 | 11 | - Installation and basic use 12 | - Advanced configuration 13 | - Usage in continuous integration pipelines 14 | 15 | {{< section >}} 16 | -------------------------------------------------------------------------------- /content/docs/web/burp/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Burp Suite Professional" 3 | weight: 2 4 | summary: "Burp Suite Professional is an HTTP interception proxy with numerous security testing features." 5 | bookCollapseSection: true 6 | --- 7 | 8 | # Introduction to Burp Suite Professional 9 | 10 | ## 1. What is it? 11 | 12 | Burp Suite Professional is an HTTP interception proxy with numerous security testing features. It allows you to view and manipulate 13 | the HTTP requests and responses flowing between a client (usually a web application loaded in a browser) and a server. 14 | 15 | With the increased traffic of today's websites, Burp stands out for its ability to handle parallel requests. 16 | Its interactive tools allow you to formulate and test hypotheses about how the site will behave, even when there is a lot of 17 | traffic to sort through—a feat that is difficult for most browser development tools. In addition, Burp includes advanced search 18 | and filtering mechanisms that greatly increase user productivity when dealing with high traffic. 19 | Burp's UI also significantly outperforms browser development tools when it comes to editing requests. 20 | 21 | {{< hint info >}}🎥 Watch the Trail of Bits Webinar on 22 | [Mastering Web Research with Burp Suite](https://www.youtube.com/watch?v=0PV5QEQTmPg). 23 | In this session, we dive into advanced web research techniques using Burp Suite with James Kettle, including how to discover ideas and targets, 24 | optimize your setup, and utilize Burp tools in various scenarios. We also explore the future of Burp with the introduction of BChecks 25 | and compare dynamic and static analysis through real-world examples. 26 | {{< /hint >}} 27 | 28 | Burp contains four major features: 29 | 30 | 1. **Burp Proxy**. The **Proxy** tab lets you view, sort, and filter proxied requests and responses. 31 | 2. **Burp Scanner (both active and passive)**. The passive Burp Scanner analyzes requests and responses and informs users 32 | about potential issues. The active Burp Scanner generates requests to send to the server, testing it for potential 33 | vulnerabilities, and displays the results. 34 | 3. **Burp Repeater**. Burp Repeater allows you to edit and conveniently send requests. 35 | 4. **Burp Intruder**. Burp Intruder allows you to populate portions of requests (e.g., query strings, POST parameters, URL paths, 36 | headers) with sets of predefined fuzzing payloads and send them to a target server automatically. Burp Intruder then displays 37 | the server’s responses to help you identify bugs or vulnerabilities resulting from unexpected input. 38 | 39 | In short, Burp lets you capture HTTP traffic, interact with it conveniently, and conduct security testing by 40 | using Burp's embedded logic (predefined rules) or manual methods. 41 | 42 | ## 2. Where can Burp support you? 43 | 44 | Through extensive experience in white box security auditing at Trail of Bits, we've learned that identifying security 45 | vulnerabilities isn't always straightforward. Here are some of the challenges: 46 | 47 | * Some security vulnerabilities can originate from the large number of third-party libraries or their configurations. 48 | * Large products contain various components spread over complicated infrastructure, making the system’s real-world behavior hard 49 | to predict. 50 | * The presence of bugs varies depending on the configuration of the deployment environment (e.g., staging vs. production). 51 | 52 | Burp addresses these challenges by providing a practical suite of tools that help you do the following: 53 | 54 | * Identify server-side issues and unexpected behaviors. 55 | * Identify client-side vulnerabilities (with the assistance of Burp's DOM Invader Chromium extension). 56 | * Make sense of the data sent to the front end, uncovering its purpose and how it affects the application's behavior in instances 57 | where the code is obfuscated using libraries such as React or Webpack. 58 | * Understand what data the client is expected to provide, such as cookies or headers, and whether the timeframes for client-side 59 | data storage comply with local regulations. 60 | * Learn how a web application behaves under different scenarios, such as when traffic is coming from various geographical 61 | locations or when different user preferences are set or unset. 62 | * Use comprehensive built-in tools to efficiently fuzz multiple query parameters or header values simultaneously, without 63 | extensive scripting. For example, using the Intruder tool, you can fuzz various parts of a request, helping unearth issues 64 | that may manifest only when certain input combinations exist. 65 | 66 | Regardless of your application's complexities and challenges, Burp Suite offers a comprehensive toolkit that can 67 | significantly enhance your ability to uncover potential security vulnerabilities. 68 | 69 | ## 3. What this Testing Handbook will give you 70 | 71 | This handbook provides the answers: what you can precisely do to enhance the security of a product with minimal time and effort. 72 | We give you strategic ideas with links to the [official documentation](https://portswigger.net/burp/documentation). 73 | At this point in the Testing Handbook, we recommend that you do the following: 74 | 75 | * Reach out for free to [PortSwigger Web Security Academy](https://portswigger.net/web-security) to obtain 76 | knowledge of web vulnerabilities. 77 | * Go to the [PortSwigger website](https://portswigger.net/burp/pro) to request a trial or buy a license 78 | (we mostly work on the paid Burp Suite Professional version). 79 | -------------------------------------------------------------------------------- /content/docs/web/burp/burp-resources/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Additional resources" 3 | summary: "Learn more about Burp using the external resources listed on this page." 4 | weight: 99 5 | bookToc: false 6 | url: docs/web/burp/resources 7 | --- 8 | 9 | # Additional resources 10 | 11 | - 𝕏 https://twitter.com/MasteringBurp: Tips and tricks for Burp Suite Pro 12 | - 𝕏 https://twitter.com/Burp_Suite: The official Portswigger profile with tips and the latest and upcoming features 13 | - :cinema: [NSEC2023 - Burp Suite Pro tips and tricks, the sequel](https://www.youtube.com/watch?app=desktop&v=N7BN--CMOMI) 14 | - :cinema:[Burp Suite Essentials YouTube Playlist](https://www.youtube.com/watch?v=ouDe5sJ_uC8&list=PLoX0sUafNGbH9bmbIANk3D50FNUmuJIF3) 15 | - [The official BChecks developed by Portswigger and community](https://github.com/PortSwigger/BChecks) 16 | - [The official Bambdas collection developed by Portswigger and community](https://github.com/PortSwigger/bambdas) 17 | -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/01-livetask/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Live task" 3 | slug: livetask 4 | summary: "Live tasks process traffic from specific Burp Suite tools and perform defined actions." 5 | weight: 10 6 | url: docs/web/burp/guide/livetask 7 | --- 8 | 9 | ## First run with a live task 10 | 11 | {{< hint info >}} 12 | Ensure you have enabled extensions from the [Enabling extensions]({{% relref "docs/web/burp/stepbystep/#enabling-extensions" %}}) step. 13 | {{< /hint >}} 14 | 15 | [Live tasks](https://portswigger.net/burp/documentation/desktop/tutorials/using-live-tasks) process traffic from specific 16 | Burp Suite tools (e.g., Burp Proxy, Burp Repeater, Burp Intruder) and perform 17 | defined actions. In the live task strategy, we set up the live active Burp Scanner task to grab the proxied traffic 18 | when we visit the website and automatically send it to Burp Scanner. Follow these steps to set up Burp to automatically 19 | scan proxied requests: 20 | 21 | 1. Open **Dashboard** and click **New live task**. 22 | 2. Under **Tools scope**, select **Proxy**. 23 | 3. In **URL scope**, select **Suite scope**. 24 | 4. Check the **Ignore duplicate items based on URL and parameter names** box. This option ensures that Burp Suite avoids scanning 25 | the same request multiple times. More specifically, it prevents Burp Suite from repeatedly scanning requests that share the same 26 | URL and parameter names, regardless of their parameter values. 27 | 28 | Here's an example to illustrate: 29 | 30 | * Consider a scenario where your application has a profile page for a user, accessed via the URL 31 | `http://example.com/profile?id=1234`. When browsing the application, you might visit this URL multiple times with different 32 | `id` values (e.g., `?id=1234`, `?id=2345`, etc.). 33 | 34 | With **Ignore duplicate items based on URL and parameter names** checked, Burp Suite will scan this URL only once, 35 | regardless of the different `id` values you use. It treats all these requests (`http://example.com/profile?id=1234`, 36 | `http://example.com/profile?id=2345`, etc.) as duplicates based on their common URL `/profile` and the `id` parameter name. 37 | This helps prevent unnecessary redundancy in the scanning process, which in turn can save valuable time. 38 | 39 | 5. Go to **Scan configuration**, click on the **Select from library** button, and select **Audit coverage - maximum** to 40 | have the most comprehensive scan possible. For more information, see [Built-in configurations](https://portswigger.net/burp/documentation/scanner/scan-configurations/burp-scanner-built-in-configs). 41 | 6. Optionally, you can adjust the number of concurrent requests on the target at any time. 42 | For more information, see [Managing resource pools for scans](https://portswigger.net/burp/documentation/desktop/automated-scanning/managing-resource-pools). 43 | 44 | Then, open the embedded Burp browser and go through your website carefully; try to visit every nook and cranny of your website. 45 | You can see detailed information and specific requests in **Tasks** > **Live audit from Proxy (suite)**. 46 | 47 | Use the [**Logger**](https://portswigger.net/burp/documentation/desktop/tools/logger/getting-started) tab and observe how 48 | the scanning works under the hood and how your application reacts to potentially malicious requests. Be cautious where the 49 | application scans the sign-out API calls (e.g., `/logout`) to ensure your session will not be terminated and result in many of 50 | your requests ending in HTTP “401 Unauthorized” errors. Also, take care that the web application firewall (WAF) does not block you 51 | out or Burp does not send too many requests in a given time, which may result in the HTTP “429 Too Many Requests” response 52 | status code. To prevent issues with excessive traffic from Burp, see [automatic throttling](https://portswigger.net/burp/documentation/desktop/settings/project/tasks#:~:text=requests%20are%20sent.-,Automatic%20throttling,-%2D%20Specify%20the%20response). 53 | 54 | {{< hint danger >}} 55 | Remember that using an active Burp Scanner can have disruptive effects on the website, such as data loss. 56 | {{< /hint >}} 57 | 58 | Also, check whether Burp accurately processes the application’s requests. For example, some applications need 59 | the HMAC SHA-256 signature of the current request in a custom header—otherwise, the server responds with an error. 60 | Other web applications are scrupulous in handling CSRF tokens (e.g., via the `X-CSRF-Token` header)—otherwise, 61 | they respond with an error too. If the application’s requests are not handled correctly, you can miss the accuracy 62 | of testing. See more in the 63 | [Ensure your app handling works correctly section]({{% relref "docs/web/burp/stepbystep/03-ensure-working-correctly/" %}}). 64 | 65 | ## Where are the results? 66 | 67 | Mainly, you will find identified issues raised by the live scans in the **Dashboard** > **Tasks** activity. 68 | Review reported issues carefully and pay particular attention to high-severity and certain confidence issues. 69 | 70 | Also, it’s crucial to look at nonstandard responses when using different Burp tools—in particular, the following: 71 | 72 | 1. Check the **Logger** tab (consider extending the limit of the memory used—see [Working with Burp Logger entries](https://portswigger.net/burp/documentation/desktop/tools/logger/settings#:~:text=were%20actually%20captured.-,Capture%20limit,-You%20can%20specify)). 73 | 74 | a. Nonstandard error HTTP responses (e.g., 500, 502) that can indicate the need for further digging 75 | 76 | b. Potential error messages and stack traces 77 | 78 | c. Success status responses (e.g., “200 OK”) for requests that should not pass the authorization mechanism 79 | 80 | d. 302 and 301 status responses for any potential [open redirection](https://portswigger.net/kb/issues/00500100_open-redirection-reflected) 81 | issues 82 | 83 | 2. When you work from the white-box perspective, look at the application logs and try to identify any potential crashes, 84 | panics, or log injections (see [CRLF injection](https://book.hacktricks.xyz/pentesting-web/crlf-0d-0a) and [IP spoofing](https://portswigger.net/kb/issues/00400110_spoofable-client-ip-address)). 85 | -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/content-type-converter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/content-type-converter.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/csrfoptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/csrfoptions.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/generatecsrfpoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/generatecsrfpoc.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/minimizer-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/minimizer-after.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/minimizer_before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/minimizer_before.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_options.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_request_minimizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_request_minimizer.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_showchars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_showchars.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_tab_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/repeater_tab_options.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/test1337placeholder1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/test1337placeholder1.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/test1337placeholder2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/01-repeater/test1337placeholder2.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/collabo-event-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/collabo-event-log.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/collabo-interaction-column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/collabo-interaction-column.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/custom-wordlists.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/custom-wordlists.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/extension-generated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/extension-generated.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/intruder-attack-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/intruder-attack-type.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/target-payload-markers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/02-intruder/target-payload-markers.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/03-collaborator/burp-collaborator-ua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/03-collaborator/burp-collaborator-ua.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/03-collaborator/collaborator-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/03-collaborator/collaborator-settings.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/03-collaborator/collaborator-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/stepbystep/02-workingmanually/03-collaborator/collaborator-tab.png -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/02-workingmanually/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Working manually on specific HTTP requests" 3 | summary: "When you understand how your target application works—for instance, when you can identify crucial requests from a security standpoint—you can choose appropriate requests from the Proxy tab and try to exploit them manually." 4 | weight: 20 5 | url: docs/web/burp/guide/manual-work 6 | --- 7 | 8 | # Working manually on specific HTTP requests 9 | 10 | When you understand how your target application works—for instance, when you can identify crucial requests from a security 11 | standpoint—you can choose appropriate requests from the **Proxy** tab and try to exploit them manually. 12 | 13 | For example, requests that reflect user-provided values in the response and API calls that handle authentication 14 | are worth investigating in this manner. To support yourself with semi-automatic methods, use the following Burp tools. 15 | 16 | {{< section >}} 17 | -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/03-ensure-working-correctly/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Ensure your app handling works correctly" 3 | summary: "It’s essential to prepare Burp to handle your target application if you want the best results when using Burp’s automatic scanning capabilities. This way, you will not miss proper functionality testing because of application errors, which will allow you to find more bugs." 4 | weight: 30 5 | url: docs/web/burp/guide/app-handling 6 | --- 7 | 8 | # Ensure your app handling works correctly 9 | 10 | It’s essential to prepare Burp to handle your target application if you want the best results when using Burp’s automatic scanning 11 | capabilities. This way, you will not miss proper functionality testing because of application errors, 12 | which will allow you to find more bugs. 13 | 14 | Remember these aspects when using Burp’s automated tools (such as Burp Scanner): 15 | 16 | 1. **Session handling**. Ensure that Burp handles sessions properly, refreshes cookies if needed, 17 | and updates any necessary headers per request (e.g., some web applications require requests to be signed). 18 | Also, ensure that Burp does not silently invalidate sessions during active scanning by sending a request to sign out. 19 | To address these cases, you may need to configure session handling rules. For more information, refer to the following resources: 20 | 21 | - [Maintaining an authenticated session](https://portswigger.net/burp/documentation/desktop/testing-workflow/session-management/maintaining-authenticated-session) 22 | 23 | - [Session handling rule editor](https://portswigger.net/burp/documentation/desktop/settings/sessions/session-handling-rules) 24 | 25 | 2. **Anti-CSRF tokens**. Using Burp against a web application that uses [anti-CSRF tokens](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#token-based-mitigation) 26 | can cause problems because the application should not allow a request to be resent without updating the anti-CSRF token. 27 | Usually, you should be able to update anti-CSRF tokens with session handling rules; for more information, 28 | see [Using Burp's Session Handling Rules with anti-CSRF Tokens](https://portswigger.net/support/using-burp-suites-session-handling-rules-with-anti-csrf-tokens). 29 | 30 | 3. **Throttling**. Ensure that using Burp does not return an HTTP “429 Too Many Requests” status code or similar. 31 | Generally, Burp has a feature to [handle automatic throttling](https://portswigger.net/burp/documentation/desktop/settings/project/tasks#:~:text=Automatic%20throttling%20%2D%20Specify%20the%20response,429%20(Too%20many%20requests)) 32 | when tackling a specific status code. However, there may be other ways the application informs you about exceeded traffic. 33 | If possible, turn off throttling on the server side for the duration of the tests and adjust throttling accordingly. 34 | Still, if you need to bypass throttling, you can use the [IP Rotate](https://portswigger.net/bappstore/2eb2b1cb1cf34cc79cda36f0f9019874) 35 | extension. 36 | 37 | 4. **WAF**. Ensure that a WAF does not block your requests if one is in place. 38 | If it does, try to allowlist your IP address or bypass it using the [Bypass WAF](https://portswigger.net/bappstore/ae2611da3bbc4687953a1f4ba6a4e04c) 39 | extension. 40 | 41 | Sometimes there are edge cases where standard Burp features (like macros) or existing extensions do not solve the above problems. 42 | In those cases, you need to create a custom extension. You can find more information on developing custom extensions in 43 | [Creating Burp extensions](https://portswigger.net/burp/documentation/desktop/extensions/creating). 44 | 45 | Although the initial investment in setting up Burp Suite, including configuring standard features, handling macros, 46 | and creating custom extensions, may seem time-consuming, the payoff is often substantial. From our experience at Trail of Bits, 47 | the teams that put in the effort to fully customize and orchestrate Burp Suite to navigate complex applications tend to uncover 48 | significantly more security vulnerabilities. 49 | -------------------------------------------------------------------------------- /content/docs/web/burp/stepbystep/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Step-by-step guide: rapidly mastering Burp to test your app" 3 | slug: guide 4 | summary: "This section gives you a step-by-step guide to rapidly mastering Burp to test your app." 5 | weight: 10 6 | url: docs/web/burp/guide 7 | --- 8 | 9 | # Step-by-step guide: rapidly mastering Burp to test your app 10 | 11 | ## Installation and first steps 12 | 13 | For the first steps, refer to the official documentation on 14 | [installing and licensing Burp Suite Professional](https://portswigger.net/burp/documentation/desktop/getting-started/download-and-install) 15 | on your system. 16 | 17 | ## Preparing the proxy 18 | 19 | To launch Burp's embedded browser based on Chromium, select the **Proxy** > **Intercept** tab and click the **Open browser** button. 20 | Before proceeding, get familiar with [Proxy intercept](https://portswigger.net/burp/documentation/desktop/tools/proxy/intercept-messages). 21 | 22 | If you want to configure an external browser other than Chromium (e.g., Firefox or Safari), refer to the [official documentation](https://portswigger.net/burp/documentation/desktop/external-browser-config). 23 | 24 | ## First run of your target web application in Burp 25 | 26 | 1. Open your web application using the embedded Burp browser. Go through the largest number of functionalities you want to cover, 27 | such as logging in, signing up, and visiting possible features and panels. 28 | 2. [Add your targets to your scope](https://portswigger.net/burp/documentation/desktop/getting-started/setting-target-scope#:~:text=Step%204%3A%20Set%20the%20target%20scope). 29 | Narrowing down specific domains in the **Target** tab allows you to control what’s tested. 30 | 31 | a. Consider stopping Burp from sending out-of-scope items to the history. A pop-up will be shown with the text, 32 | “‘Do you want Burp Proxy to stop sending out-of-scope items to the history or other Burp tools?” Choose one of the following options: 33 | 34 | * Click **Yes** if you are sure you have chosen all possible domains. This will help you avoid sending potentially malicious requests 35 | to unforeseen hosts. This way, you can configure Burp Scanner to actively attack targets only from the configured scope. 36 | * Click **No** if it’s your first run and you are unsure about potential underlying requests to the specific domains. 37 | This will help you gain a more thorough overview of what’s going on in your application. 38 | 39 | b. For more information on configuring the scope, see [Scope](https://portswigger.net/burp/documentation/desktop/tools/target/scope). 40 | 41 | 3. Once you configure the scope, briefly look at Burp Proxy and what’s happening in the intercepted traffic. 42 | 43 | a. When you go through the application with Burp attached, many unwanted requests (e.g., to `fonts.googleapis.com`) 44 | can crop up in the **Intercept** tab. 45 | 46 | b. To turn off intercepting the uninteresting host, click on the intercepted request in the **Interception** tab, right-click, 47 | and then choose **Don’t intercept requests** > **To this host**. Burp will then automatically forward requests to the marked host. 48 | 49 | c. Keep in mind that if you selected **No** when asked in the previous step (“Do you want Burp Proxy to stop sending out-of-scope 50 | items to the history or other Burp tools?”), you could see a lot of out-of-scope (“unwanted”) items. 51 | 52 | {{< hint info >}} 53 | Important hot key: By default, **Ctrl+F** forwards the current HTTP request in the Burp Intercept feature. 54 | {{< /hint >}} 55 | 56 | ## Enabling extensions 57 | 58 | Extensions can be added to Burp to enhance its capabilities in finding bugs and automating 59 | various tasks. For in-depth information on installing the Burp extensions that we will cover in this section, 60 | refer to [Installing extensions](https://portswigger.net/burp/documentation/desktop/extensions/installing-extensions). 61 | 62 | Some extensions fall under the category of “turn on and forget.” They are mostly designed to automatically run on each 63 | Burp Scanner task without user interaction, with results appearing in the **Issue activity** pane of the **Dashboard** tab. 64 | We generally recommend the following extensions, which should apply to most web applications: 65 | 66 | 1. [**Active Scan++**](https://portswigger.net/bappstore/3123d5b5f25c4128894d97ea1acc4976) enhances the default active and 67 | passive scanning capabilities of Burp Suite. 68 | It adds checks for vulnerabilities that the default Burp Scanner might miss. 69 | 2. [**Backslash Powered Scanner**](https://portswigger.net/bappstore/9cff8c55432a45808432e26dbb2b41d8) extends the active 70 | scanning capability by trying to identify known and unknown classes 71 | of server-side injection vulnerabilities. 72 | 3. [**Software Vulnerability Scanner**](https://portswigger.net/bappstore/c9fb79369b56407792a7104e3c4352fb) integrates with 73 | Burp Suite to automatically identify known software vulnerabilities in web applications. 74 | 4. [**Freddy, Deserialization Bug Finder**](https://portswigger.net/bappstore/ae1cce0c6d6c47528b4af35faebc3ab3) helps detect 75 | and exploit serialization issues in libraries and APIs (e.g., .NET and Java). 76 | 5. [**J2EEScan**](https://portswigger.net/bappstore/7ec6d429fed04cdcb6243d8ba7358880) improves the test coverage during 77 | web application penetration tests on J2EE applications. 78 | 6. [**403 Bypasser**](https://portswigger.net/bappstore/444407b96d9c4de0adb7aed89e826122) attempts to bypass HTTP 403 Forbidden 79 | responses by changing request methods and altering headers. 80 | 81 | Some of the above extensions need 82 | [Jython or JRuby](https://portswigger.net/burp/documentation/desktop/extensions/installing-extensions#:~:text=Installing%20Jython%20or%20JRuby) 83 | configured in Burp. 84 | 85 | {{< hint warning >}} 86 | Because of the performance impact of enabling too many extensions, 87 | you should enable only extensions that you are actively using. 88 | We encourage you to periodically review your enabled extensions and unload any that you don't currently use. 89 | {{< /hint >}} 90 | -------------------------------------------------------------------------------- /content/docs/web/burp/tips/allow-tags-in-proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/allow-tags-in-proxy.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/auto-modified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/auto-modified.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/autorize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/autorize.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/bambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/bambda.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/browser-with-hud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/browser-with-hud.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/burp-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/burp-search.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/collaborator-everywhere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/collaborator-everywhere.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/create-new-tab-group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/create-new-tab-group.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/distributed-damage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/distributed-damage.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/easy-auto-refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/easy-auto-refresh.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/global-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/global-search.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/hackvertor-store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/hackvertor-store.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/hackvertor-turbo-intruder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/hackvertor-turbo-intruder.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/injection-pt-turbo-intruder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/injection-pt-turbo-intruder.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/match-and-replace-rules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/match-and-replace-rules.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/pause-tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/pause-tasks.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/remove-csp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/remove-csp.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/repeater-add-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/repeater-add-tab.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/request-interference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/request-interference.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/send-in-parallel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/send-in-parallel.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/session-handling-rule-scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/session-handling-rule-scope.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/session-handling-rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/session-handling-rule.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/turbo-intruder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/turbo-intruder.png -------------------------------------------------------------------------------- /content/docs/web/burp/tips/upstream-proxy-rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/content/docs/web/burp/tips/upstream-proxy-rule.png -------------------------------------------------------------------------------- /layouts/_default/_markup/render-link.html: -------------------------------------------------------------------------------- 1 | {{- if .Page.Site.Params.BookPortableLinks -}} 2 | {{- errorf "BookPortableLinks is unsupported" }} 3 | {{- else -}} 4 | {{- $isRemote := or (in .Destination ":") (strings.HasPrefix .Destination "//") }} 5 | {{- if $isRemote }} 6 | {{ .Text | safeHTML }} 7 | {{- else}} 8 | {{ .Text | safeHTML }} 9 | {{- end -}} 10 | {{- end -}} 11 | 12 | -------------------------------------------------------------------------------- /layouts/partials/docs/brand.html: -------------------------------------------------------------------------------- 1 |

2 | 4 | {{- with .Site.Params.BookLogo -}} 5 | Logo 6 | {{- end -}} 7 |
8 | {{- with .Site.Params.BookIconLogo -}} 9 | 10 | {{- end -}} 11 | {{ .Site.Title }} 12 |
13 |
14 |

-------------------------------------------------------------------------------- /layouts/partials/docs/inject/footer.html: -------------------------------------------------------------------------------- 1 | 35 | 36 |
37 | This content is licensed under a 39 | Creative Commons Attribution 4.0 International license. 43 |
44 | 45 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 118 | -------------------------------------------------------------------------------- /layouts/shortcodes/customFigure.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{ if eq (.Get 1) "html" }} 4 | {{ .Inner | safeHTML }} 5 | {{ else }} 6 | {{ .Inner | .Page.RenderString (dict "display" "inline") }} 7 | {{ end}} 8 | 9 | {{ if (.Get 0) }} 10 |
{{ (.Get 0) | .Page.RenderString (dict "display" "inline") }}
11 | {{ end }} 12 |
13 |
-------------------------------------------------------------------------------- /layouts/shortcodes/fuzzing/intro-os.html: -------------------------------------------------------------------------------- 1 | This section of the Testing Handbook is based on fuzzing binaries written in C/C++ on Ubuntu on x64_64. 2 | -------------------------------------------------------------------------------- /layouts/shortcodes/fuzzing/oss-fuzz-faq.html: -------------------------------------------------------------------------------- 1 |

What is the best approach if I have an OSS-Fuzz fuzzing harness ready, but my project is not eligible for continuous fuzzing by Google infrastructure?

2 |

When you already have harnesses, but your project is not eligible to be fuzzed continuously by Google infrastructure, it’s important to fuzz the project regularly and for extended periods. It’s best to configure fuzzing so it runs on an updated codebase automatically.

3 |

One way of doing this is using CIFuzz (with ClusterFuzzLite if your project is not enrolled in the OSS-Fuzz project) to perform short fuzzing as a post-commit (or pre-commit) CI job. Because CIFuzz tests code from every commit, you can easily see which commit introduced the problem. This method also simplifies adding regression testing, as you can automatically add problematic inputs to corpora.

4 |

Additionally, if your project supports code-coverage calculations, CIFuzz can run only harnesses that touch modified code and not all of them. Stay tuned for an upcoming update to the testing handbook with a robust Continuous Fuzzing chapter!

-------------------------------------------------------------------------------- /layouts/shortcodes/math.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /layouts/shortcodes/rawHtml.html: -------------------------------------------------------------------------------- 1 | {{ .Inner | safeHTML }} 2 | -------------------------------------------------------------------------------- /layouts/shortcodes/resourceFigure.html: -------------------------------------------------------------------------------- 1 | {{ $img := $.Page.Resources.GetMatch (.Get 0)}} 2 | 3 |
4 |
5 | {{ if (.Get 2) }} 6 | {{ if eq $img.MediaType.SubType "svg" }} 7 | {{ .Get 1 }} 8 | {{else }} 9 | {{ $resize := (printf "%dx webp" (.Get 2)) }} 10 | {{ $width := (printf "%dpx" (.Get 2)) }} 11 | {{ $resized := ($img.Resize $resize ) }} 12 | {{ .Get 1 }} 13 | {{ end }} 14 | {{else }} 15 | {{ .Get 1 }} 16 | {{ end }} 17 | {{ if .Inner }} 18 |
{{ .Inner | .Page.RenderString (dict "display" "inline") }}
19 | {{ end }} 20 |
21 |
22 | -------------------------------------------------------------------------------- /layouts/shortcodes/resourceHref.html: -------------------------------------------------------------------------------- 1 | {{ .Inner }} -------------------------------------------------------------------------------- /layouts/shortcodes/tooltipHighlight.html: -------------------------------------------------------------------------------- 1 | 2 | {{- $attrs := dict }} 3 | 4 | 5 | 6 | {{- range (seq 1 (sub (len .Params) 1) ) }} 7 | {{- $myArg := $.Get . }} 8 | 9 | {{- $attrs = merge $attrs (dict (printf "data-tooltips-%d" (sub . 1)) $myArg) }} 10 | {{- end }} 11 | 12 | 13 |
18 | {{ highlight (trim .InnerDeindent "\n\r") (.Get 0) "" }} 19 |
-------------------------------------------------------------------------------- /materials/fuzzing/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/materials/fuzzing/.gitignore -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(BuggyProgram) 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | add_executable(buggy_program main.cc) 5 | 6 | add_executable(fuzz main.cc harness.cc) 7 | target_compile_definitions(fuzz PRIVATE NO_MAIN=1) 8 | target_compile_options(fuzz PRIVATE -g -O2 -fsanitize=fuzzer) 9 | target_link_libraries(fuzz -fsanitize=fuzzer) 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/afl++: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | AFL_VERSION="${AFL_VERSION:-"stable"}" 3 | case "$1" in 4 | host) 5 | shift 6 | bash -c "$*" 7 | ;; 8 | docker) 9 | shift 10 | /usr/bin/env docker run -ti \ 11 | --privileged \ 12 | -v ./:/src \ 13 | --rm \ 14 | --name afl_fuzzing \ 15 | "aflplusplus/aflplusplus:$AFL_VERSION" \ 16 | bash -c "cd /src && bash -c \"$*\"" 17 | ;; 18 | *) 19 | echo "Usage: $0 {host|docker}" 20 | exit 1 21 | ;; 22 | esac 23 | -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/argv-fuzz-inl.h: -------------------------------------------------------------------------------- 1 | /* 2 | american fuzzy lop++ - sample argv fuzzing wrapper 3 | ------------------------------------------------ 4 | 5 | Originally written by Michal Zalewski 6 | 7 | Copyright 2015 Google Inc. All rights reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at: 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | This file shows a simple way to fuzz command-line parameters with stock 16 | afl-fuzz. To use, add: 17 | 18 | #include "/path/to/argv-fuzz-inl.h" 19 | 20 | ...to the file containing main(), ideally placing it after all the 21 | standard includes. Next, put AFL_INIT_ARGV(); near the very beginning of 22 | main(). 23 | 24 | This will cause the program to read NUL-delimited input from stdin and 25 | put it in argv[]. Two subsequent NULs terminate the array. Empty 26 | params are encoded as a lone 0x02. Lone 0x02 can't be generated, but 27 | that shouldn't matter in real life. 28 | 29 | If you would like to always preserve argv[0], use this instead: 30 | AFL_INIT_SET0("prog_name"); 31 | 32 | To enable persistent fuzzing, use the AFL_INIT_ARGV_PERSISTENT macro with 33 | buf as argument, or use AFL_INIT_SET0_PERSISTENT("prog_name", buf) 34 | to preserver argv[0]. buf is a pointer to a buffer containing 35 | the input data for the current test case being processed defined as: 36 | unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; 37 | */ 38 | 39 | #ifndef _HAVE_ARGV_FUZZ_INL 40 | #define _HAVE_ARGV_FUZZ_INL 41 | 42 | #include 43 | #include 44 | 45 | #define AFL_INIT_ARGV() \ 46 | do { \ 47 | \ 48 | argv = afl_init_argv(&argc); \ 49 | \ 50 | } while (0) 51 | 52 | #define AFL_INIT_SET0(_p) \ 53 | do { \ 54 | \ 55 | argv = afl_init_argv(&argc); \ 56 | argv[0] = (_p); \ 57 | if (!argc) argc = 1; \ 58 | \ 59 | } while (0) 60 | 61 | #define AFL_INIT_ARGV_PERSISTENT(persistent_buff) \ 62 | do { \ 63 | \ 64 | argv = afl_init_argv_persistent(&argc, persistent_buff); \ 65 | \ 66 | } while (0) 67 | 68 | #define AFL_INIT_SET0_PERSISTENT(_p, persistent_buff) \ 69 | do { \ 70 | \ 71 | argv = afl_init_argv_persistent(&argc, persistent_buff); \ 72 | argv[0] = (_p); \ 73 | if (!argc) argc = 1; \ 74 | \ 75 | } while (0) 76 | 77 | #define MAX_CMDLINE_LEN 1000000 78 | #define MAX_CMDLINE_PAR 50000 79 | 80 | static char **afl_init_argv(int *argc) { 81 | 82 | static char in_buf[MAX_CMDLINE_LEN]; 83 | static char *ret[MAX_CMDLINE_PAR]; 84 | 85 | char *ptr = in_buf; 86 | int rc = 0; 87 | 88 | ssize_t num = read(0, in_buf, MAX_CMDLINE_LEN - 2); 89 | if (num < 1) { return NULL; } 90 | in_buf[num] = '\0'; 91 | in_buf[num + 1] = '\0'; 92 | 93 | while (*ptr && rc < MAX_CMDLINE_PAR) { 94 | 95 | ret[rc] = ptr; 96 | if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; 97 | rc++; 98 | 99 | while (*ptr) 100 | ptr++; 101 | ptr++; 102 | 103 | } 104 | 105 | *argc = rc; 106 | 107 | return ret; 108 | 109 | } 110 | 111 | static char **afl_init_argv_persistent(int *argc, 112 | unsigned char *persistent_buff) { 113 | 114 | static char *ret[MAX_CMDLINE_PAR]; 115 | 116 | unsigned char *ptr = persistent_buff; 117 | int rc = 0; 118 | 119 | while (*ptr && rc < MAX_CMDLINE_PAR) { 120 | 121 | ret[rc] = (char *)ptr; 122 | if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; 123 | rc++; 124 | 125 | while (*ptr) 126 | ptr++; 127 | ptr++; 128 | 129 | } 130 | 131 | *argc = rc; 132 | 133 | return ret; 134 | 135 | } 136 | 137 | #undef MAX_CMDLINE_LEN 138 | #undef MAX_CMDLINE_PAR 139 | 140 | #endif /* !_HAVE_ARGV_FUZZ_INL */ 141 | 142 | -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/fuzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/materials/fuzzing/aflpp/fuzz -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void check_buf(char *buf, size_t buf_len); 5 | 6 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 7 | check_buf((char*) data, size); 8 | return 0; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void check_buf(char *buf, size_t buf_len) { 5 | if(buf_len > 0 && buf[0] == 'a') { 6 | if(buf_len > 1 && buf[1] == 'b') { 7 | if(buf_len > 2 && buf[2] == 'c') { 8 | abort(); 9 | } 10 | } 11 | } 12 | } 13 | 14 | #ifndef NO_MAIN 15 | int main() { 16 | char target[] = "123"; 17 | size_t len = strlen(target); 18 | check_buf(target, len); 19 | return 0; 20 | } 21 | #endif // NO_MAIN 22 | -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_arg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef __AFL_COMPILER 6 | #include "argv-fuzz-inl.h" 7 | #endif 8 | 9 | void check_buf(char *buf, size_t buf_len) { 10 | if(buf_len > 0 && buf[0] == 'a') { 11 | if(buf_len > 1 && buf[1] == 'b') { 12 | if(buf_len > 2 && buf[2] == 'c') { 13 | abort(); 14 | } 15 | } 16 | } 17 | } 18 | 19 | int main(int argc, char *argv[]) { 20 | #ifdef __AFL_COMPILER 21 | AFL_INIT_ARGV(); 22 | #endif 23 | 24 | if (argc < 2) { 25 | fprintf(stderr, "Usage: %s \n", argv[0]); 26 | return 1; 27 | } 28 | 29 | char *input_buf = argv[1]; 30 | size_t len = strlen(input_buf); 31 | 32 | check_buf(input_buf, len); 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_arg_no_shared.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef __AFL_COMPILER 6 | #include "argv-fuzz-inl.h" 7 | //__AFL_FUZZ_INIT(); 8 | #endif 9 | 10 | void check_buf(char *buf, size_t buf_len) { 11 | if(buf_len > 0 && buf[0] == 'a') { 12 | if(buf_len > 1 && buf[1] == 'b') { 13 | if(buf_len > 2 && buf[2] == 'c') { 14 | abort(); 15 | } 16 | } 17 | } 18 | } 19 | 20 | //extern __attribute__((visibility("default"))) int __afl_connected; 21 | 22 | int main(int argc, char *argv[]) { 23 | #ifdef __AFL_COMPILER 24 | 25 | //__AFL_INIT(); // is this required? when is it? deferred fork server? apparently yes 26 | 27 | #endif 28 | //(fprintf(stderr, "__afl_connected: %d\n",__afl_connected); 29 | 30 | 31 | int its = 0; 32 | while (__AFL_LOOP(1000)) { 33 | its++; 34 | 35 | if (its > 800) { 36 | fprintf(stdout, "iters: %d\n", its); 37 | } 38 | 39 | AFL_INIT_ARGV(); 40 | 41 | if (argv == NULL) { 42 | continue; 43 | } 44 | 45 | if (argc < 2) { 46 | //fprintf(stderr, "Usage: %s \n", argv[0]); 47 | //return 1; 48 | continue; 49 | } 50 | 51 | char *input_buf = argv[1]; 52 | size_t len = strlen(input_buf); 53 | check_buf(input_buf, len); 54 | 55 | 56 | } 57 | 58 | 59 | 60 | 61 | 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_arg_persist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef __AFL_COMPILER 6 | #include "argv-fuzz-inl.h" 7 | 8 | __AFL_FUZZ_INIT(); 9 | 10 | #endif 11 | 12 | void check_buf(char *buf, size_t buf_len) { 13 | if(buf_len > 0 && buf[0] == 'a') { 14 | if(buf_len > 1 && buf[1] == 'b') { 15 | if(buf_len > 2 && buf[2] == 'c') { 16 | abort(); 17 | } 18 | } 19 | } 20 | } 21 | 22 | int main(int argc, char *argv[]) { 23 | #ifdef __AFL_COMPILER 24 | unsigned char *buf; 25 | __AFL_INIT(); 26 | buf = __AFL_FUZZ_TESTCASE_BUF; 27 | AFL_INIT_ARGV_PERSISTENT(buf); 28 | #endif 29 | 30 | #ifdef __AFL_COMPILER 31 | while (__AFL_LOOP(1000)) { 32 | #endif 33 | 34 | if (argc < 2) { 35 | fprintf(stderr, "Usage: %s \n", argv[0]); 36 | return 1; 37 | } 38 | 39 | char *input_buf = argv[1]; 40 | size_t len = strlen(input_buf); 41 | 42 | check_buf(input_buf, len); 43 | 44 | #ifdef __AFL_COMPILER 45 | } 46 | #endif 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_asan.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void check_buf(char *buf, size_t buf_len) { 6 | char *last; 7 | 8 | if(buf_len > 0 && buf[0] == 'a') { 9 | if(buf_len > 1 && buf[1] == 'b') { 10 | if(buf_len > 2 && buf[2] == 'c') { 11 | last = (char*)malloc(1 * sizeof(char)); 12 | last[0] = 'c'; 13 | last[1] = '\0'; 14 | printf("%s", last); 15 | free(last); 16 | } 17 | } 18 | } 19 | } 20 | 21 | #ifndef NO_MAIN 22 | int main() { 23 | char target[] = "123"; 24 | size_t len = strlen(target); 25 | check_buf(target, len); 26 | return 0; 27 | } 28 | #endif // NO_MAIN 29 | -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_BUF_SIZE 100 6 | 7 | void check_buf(char *buf, size_t buf_len) { 8 | if(buf_len > 0 && buf[0] == 'a') { 9 | if(buf_len > 1 && buf[1] == 'b') { 10 | if(buf_len > 2 && buf[2] == 'c') { 11 | abort(); 12 | } 13 | } 14 | } 15 | } 16 | int main(int argc, char *argv[]) { 17 | char input_buf[MAX_BUF_SIZE]; 18 | 19 | if (argc < 2) { 20 | fprintf(stderr, "Usage: %s \n", argv[0]); 21 | return 1; 22 | } 23 | 24 | FILE *file = fopen(argv[1], "r"); 25 | if (file == NULL) { 26 | return 1; 27 | } 28 | 29 | if (fgets(input_buf, MAX_BUF_SIZE, file) == NULL) { 30 | if (!feof(file)) { // Check for reading error and not end of file 31 | fclose(file); 32 | return 1; 33 | } 34 | } 35 | 36 | fclose(file); 37 | 38 | size_t len = strlen(input_buf); 39 | check_buf(input_buf, len); 40 | return 0; 41 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_file_persist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | __AFL_FUZZ_INIT(); 6 | 7 | #define MAX_BUF_SIZE 100 8 | 9 | void check_buf(char *buf, size_t buf_len) { 10 | if(buf_len > 0 && buf[0] == 'a') { 11 | if(buf_len > 1 && buf[1] == 'b') { 12 | if(buf_len > 2 && buf[2] == 'c') { 13 | abort(); 14 | } 15 | } 16 | } 17 | } 18 | 19 | int main(int argc, char *argv[]) { 20 | #ifdef __AFL_COMPILER 21 | unsigned char *input_buf; 22 | __AFL_INIT(); 23 | input_buf = __AFL_FUZZ_TESTCASE_BUF; 24 | #else 25 | char input_buf[MAX_BUF_SIZE]; 26 | 27 | if (argc < 2) { 28 | fprintf(stderr, "Usage: %s \n", argv[0]); 29 | return 1; 30 | } 31 | 32 | FILE *file = fopen(argv[1], "r"); 33 | if (file == NULL) { 34 | return 1; 35 | } 36 | 37 | if (fgets(input_buf, MAX_BUF_SIZE, file) == NULL) { 38 | if (!feof(file)) { // Check for reading error and not end of file 39 | fclose(file); 40 | return 1; 41 | } 42 | } 43 | 44 | fclose(file); 45 | #endif 46 | 47 | while (__AFL_LOOP(1000)) { 48 | size_t len = strlen(input_buf); 49 | check_buf(input_buf, len); 50 | } 51 | return 0; 52 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_stdin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_BUF_SIZE 100 6 | 7 | void check_buf(char *buf, size_t buf_len) { 8 | if(buf_len > 0 && buf[0] == 'a') { 9 | if(buf_len > 1 && buf[1] == 'b') { 10 | if(buf_len > 2 && buf[2] == 'c') { 11 | abort(); 12 | } 13 | } 14 | } 15 | } 16 | 17 | int main() { 18 | char input_buf[MAX_BUF_SIZE]; 19 | 20 | if (fgets(input_buf, MAX_BUF_SIZE, stdin) == NULL) { 21 | return 1; 22 | } 23 | 24 | size_t len = strlen(input_buf); 25 | check_buf(input_buf, len); 26 | return 0; 27 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_stdin_persist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | __AFL_FUZZ_INIT(); 6 | 7 | #define MAX_BUF_SIZE 100 8 | 9 | void check_buf(char *buf, size_t buf_len) { 10 | if(buf_len > 0 && buf[0] == 'a') { 11 | if(buf_len > 1 && buf[1] == 'b') { 12 | if(buf_len > 2 && buf[2] == 'c') { 13 | abort(); 14 | } 15 | } 16 | } 17 | } 18 | 19 | int main() { 20 | #ifdef __AFL_COMPILER 21 | unsigned char *input_buf; 22 | __AFL_INIT(); 23 | input_buf = __AFL_FUZZ_TESTCASE_BUF; 24 | #else 25 | char input_buf[MAX_BUF_SIZE]; 26 | 27 | if (fgets(input_buf, MAX_BUF_SIZE, stdin) == NULL) { 28 | return 1; 29 | } 30 | #endif 31 | 32 | while (__AFL_LOOP(1000)) { 33 | size_t len = strlen(input_buf); 34 | check_buf(input_buf, len); 35 | } 36 | return 0; 37 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/main_stdin_persist_no_shared.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //__AFL_FUZZ_INIT(); 6 | 7 | #define MAX_BUF_SIZE 100 8 | 9 | void check_buf(char *buf, size_t buf_len) { 10 | if(buf_len > 0 && buf[0] == 'a') { 11 | if(buf_len > 1 && buf[1] == 'b') { 12 | if(buf_len > 2 && buf[2] == 'c') { 13 | abort(); 14 | } 15 | } 16 | } 17 | } 18 | 19 | int main() { 20 | char input_buf[MAX_BUF_SIZE]; 21 | 22 | __AFL_INIT(); 23 | while (__AFL_LOOP(1000)) { 24 | memset(input_buf, 0, MAX_BUF_SIZE); 25 | 26 | //if (fgets(input_buf, MAX_BUF_SIZE, stdin) == NULL) { return 1; } 27 | 28 | size_t len = read(0, input_buf, 100); 29 | 30 | //size_t len = strlen(input_buf); 31 | check_buf(input_buf, len); 32 | } 33 | return 0; 34 | } -------------------------------------------------------------------------------- /materials/fuzzing/aflpp/seeds/minimal_seed: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /materials/fuzzing/complex-example/data_provider.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "./FuzzedDataProvider.h" 4 | 5 | char* concat(const char* inputStr, size_t inputStrLen, 6 | const char* anotherStr, size_t anotherStrLen, 7 | size_t allocation_size) { 8 | 9 | if (allocation_size <= 1 || allocation_size > 1 << 16) { 10 | return NULL; 11 | } 12 | 13 | char* result = (char*)malloc(allocation_size); 14 | 15 | if (result == NULL) { 16 | return NULL; 17 | } 18 | 19 | memcpy(result, inputStr, inputStrLen); 20 | memcpy(result + inputStrLen, anotherStr, anotherStrLen); 21 | 22 | return result; 23 | } 24 | 25 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 26 | FuzzedDataProvider fuzzed_data(data, size); 27 | 28 | size_t allocation_size = fuzzed_data.ConsumeIntegral(); 29 | 30 | std::vector str1 = 31 | fuzzed_data.ConsumeBytesWithTerminator(32, 0xFF); 32 | 33 | std::vector str2 = 34 | fuzzed_data.ConsumeBytesWithTerminator(32, 0xFF); 35 | 36 | char* concatenated = concat(&str1[0], str1.size(), &str2[0], str2.size(), allocation_size); 37 | if (concatenated != NULL) { 38 | free(concatenated); 39 | } 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /materials/fuzzing/complex-example/divide.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | double divide(uint32_t numerator, uint32_t denominator) { 5 | // Bug: No check if denominator is zero 6 | return numerator / denominator; 7 | } 8 | 9 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 10 | // Ensure exactly 2 4-byte numbers (numerator and denominator) are read 11 | if(size != 2 * sizeof(uint32_t)){ 12 | return 0; 13 | } 14 | 15 | // Split input into numerator and denominator 16 | int numerator = *(uint32_t*)(data); 17 | int denominator = *(uint32_t*)(data + sizeof(uint32_t)); 18 | 19 | divide(numerator, denominator); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /materials/fuzzing/complex-example/divide.json: -------------------------------------------------------------------------------- 1 | { 2 | "numerator": 21, 3 | "denominator": 0 4 | } -------------------------------------------------------------------------------- /materials/fuzzing/complex-example/gdc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int gcd(uint64_t a, uint64_t b) { 5 | if (b == 0) 6 | return a; 7 | return gcd(b, a % b); 8 | } 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 11 | if (size < sizeof(uint64_t) * 2) { 12 | return 0; 13 | } 14 | 15 | int a = *(uint64_t*)data; 16 | int b = *(uint64_t*)(data + sizeof(uint64_t)); 17 | 18 | gcd(a, b); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /materials/fuzzing/complex-example/interleved.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | double add(double a, double b); 6 | double subtract(double a, double b); 7 | double multiply(double a, double b); 8 | double divide(double a, double b); 9 | 10 | double add(double a, double b) { 11 | return a + b; 12 | } 13 | 14 | double subtract(double a, double b) { 15 | return a - b; 16 | } 17 | 18 | double multiply(double a, double b) { 19 | return a * b; 20 | } 21 | 22 | double divide(double a, double b) { 23 | if (b != 0.0) { // Avoid division by zero 24 | return a / b; 25 | } 26 | 27 | return 0.0; 28 | } 29 | 30 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 31 | if (size < 1 + 2 * sizeof(double)) { 32 | return 0; 33 | } 34 | 35 | uint8_t mode = data[0]; 36 | double numbers[2]; 37 | memcpy(numbers, data + 1, 2 * sizeof(double)); 38 | 39 | // We select functions based on the first byte of the fuzzing data 40 | switch (mode % 4) { 41 | case 0: 42 | add(numbers[0], numbers[1]); 43 | break; 44 | case 1: 45 | subtract(numbers[0], numbers[1]); 46 | break; 47 | case 2: 48 | multiply(numbers[0], numbers[1]); 49 | break; 50 | case 3: 51 | divide(numbers[0], numbers[1]); 52 | break; 53 | } 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /materials/fuzzing/coverage-analysis/execute-rt.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); 8 | 9 | void load_file_and_test(const char *filename) { 10 | FILE *file = fopen(filename, "rb"); 11 | if (file == NULL) { 12 | printf("Failed to open file: %s\n", filename); 13 | return; 14 | } 15 | 16 | fseek(file, 0, SEEK_END); 17 | long filesize = ftell(file); 18 | rewind(file); 19 | 20 | uint8_t *buffer = (uint8_t*) malloc(filesize); 21 | if (buffer == NULL) { 22 | printf("Failed to allocate memory for file: %s\n", filename); 23 | fclose(file); 24 | return; 25 | } 26 | 27 | long read_size = (long) fread(buffer, 1, filesize, file); 28 | if (read_size != filesize) { 29 | printf("Failed to read file: %s\n", filename); 30 | free(buffer); 31 | fclose(file); 32 | return; 33 | } 34 | 35 | LLVMFuzzerTestOneInput(buffer, filesize); 36 | 37 | free(buffer); 38 | fclose(file); 39 | } 40 | 41 | int main(int argc, char **argv) { 42 | if (argc != 2) { 43 | printf("Usage: %s \n", argv[0]); 44 | return 1; 45 | } 46 | 47 | DIR *dir = opendir(argv[1]); 48 | if (dir == NULL) { 49 | printf("Failed to open directory: %s\n", argv[1]); 50 | return 1; 51 | } 52 | 53 | struct dirent *entry; 54 | while ((entry = readdir(dir)) != NULL) { 55 | if (entry->d_type == DT_REG) { 56 | char filepath[1024]; 57 | snprintf(filepath, sizeof(filepath), "%s/%s", argv[1], entry->d_name); 58 | load_file_and_test(filepath); 59 | } 60 | } 61 | 62 | closedir(dir); 63 | return 0; 64 | } -------------------------------------------------------------------------------- /materials/fuzzing/coverage.c: -------------------------------------------------------------------------------- 1 | int foo(int param) 2 | { 3 | if (param) 4 | { 5 | return 1; 6 | } 7 | else 8 | { 9 | return 0; 10 | } 11 | } 12 | 13 | int main(int argc, char* argv[]) 14 | { 15 | foo(0); 16 | 17 | return 0; 18 | } -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(BuggyProgram) 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | add_executable(buggy_program main.cc) 5 | 6 | add_executable(fuzz main.cc harness.cc) 7 | target_compile_definitions(fuzz PRIVATE NO_MAIN=1) 8 | target_compile_options(fuzz PRIVATE -g -O2) -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "appsec_guide" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["staticlib"] 8 | 9 | [dependencies] 10 | clap = { version = "4", features = ["derive"] } 11 | libafl = { version = "0.13", features = ["casr"] } 12 | libafl_bolts = "0.13" 13 | libafl_cc = "0.13" 14 | libafl_targets = { version = "0.13", features = ["libfuzzer", "sancov_pcguard_hitcounts"] } 15 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | void check_buf(char *buf, size_t buf_len); 6 | 7 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 8 | check_buf((char*) data, size); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void check_buf(char *buf, size_t buf_len) { 5 | if(buf_len > 0 && buf[0] == 'a') { 6 | if(buf_len > 1 && buf[1] == 'b') { 7 | if(buf_len > 2 && buf[2] == 'c') { 8 | abort(); 9 | } 10 | } 11 | } 12 | } 13 | 14 | #ifndef NO_MAIN 15 | int main() { 16 | char target[] = "123"; 17 | size_t len = strlen(target); 18 | check_buf(target, len); 19 | return 0; 20 | } 21 | #endif // NO_MAIN 22 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide/src/bin/libafl_cc.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use libafl_cc::{ClangWrapper, CompilerWrapper, Configuration, ToolWrapper}; 4 | 5 | pub fn main() { 6 | let args: Vec = env::args().collect(); 7 | if args.len() > 1 { 8 | let mut dir = env::current_exe().unwrap(); 9 | let wrapper_name = dir.file_name().unwrap().to_str().unwrap(); 10 | 11 | let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() { 12 | "cc" => false, 13 | "++" | "pp" | "xx" => true, 14 | _ => panic!("Could not figure out if c or c++ wrapper was called. Expected {dir:?} to end with c or cxx"), 15 | }; 16 | 17 | dir.pop(); 18 | 19 | let mut cc = ClangWrapper::new(); 20 | if let Some(code) = cc 21 | .cpp(is_cpp) 22 | // silence the compiler wrapper output, needed for some configure scripts. 23 | .silence(true) 24 | .parse_args(&args) 25 | .expect("Failed to parse the command line") 26 | .link_staticlib(&dir, "appsec_guide") 27 | .add_args(&Configuration::GenerateCoverageMap.to_flags().unwrap()) 28 | .add_args(&Configuration::AddressSanitizer.to_flags().unwrap()) 29 | .run() 30 | .expect("Failed to run the wrapped compiler") 31 | { 32 | std::process::exit(code); 33 | } 34 | } else { 35 | panic!("LibAFL CC: No Arguments given"); 36 | } 37 | } -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide/src/bin/libafl_cxx.rs: -------------------------------------------------------------------------------- 1 | pub mod libafl_cc; 2 | 3 | fn main() { 4 | libafl_cc::main(); 5 | } -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_deduplicate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "appsec_guide" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["staticlib"] 8 | 9 | [dependencies] 10 | clap = { version = "4", features = ["derive"] } 11 | libafl = { version = "0.13", features = ["casr"] } 12 | libafl_bolts = "0.13" 13 | libafl_cc = "0.13" 14 | libafl_targets = { version = "0.13", features = ["libfuzzer", "sancov_pcguard_hitcounts"] } 15 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_deduplicate/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | void check_buf(char *buf, size_t buf_len); 6 | 7 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 8 | check_buf((char*) data, size); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_deduplicate/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void check_buf(char *buf, size_t buf_len) { 5 | if(buf_len > 0 && buf[0] == 'a') { 6 | if(buf_len > 1 && buf[1] == 'b') { 7 | if(buf_len > 2 && buf[2] == 'c') { 8 | abort(); 9 | } 10 | } 11 | } 12 | } 13 | 14 | #ifndef NO_MAIN 15 | int main() { 16 | char target[] = "123"; 17 | size_t len = strlen(target); 18 | check_buf(target, len); 19 | return 0; 20 | } 21 | #endif // NO_MAIN 22 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_deduplicate/src/bin/libafl_cc.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use libafl_cc::{ClangWrapper, CompilerWrapper, Configuration, ToolWrapper, LLVMPasses}; 4 | 5 | pub fn main() { 6 | let args: Vec = env::args().collect(); 7 | if args.len() > 1 { 8 | let mut dir = env::current_exe().unwrap(); 9 | let wrapper_name = dir.file_name().unwrap().to_str().unwrap(); 10 | 11 | let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() { 12 | "cc" => false, 13 | "++" | "pp" | "xx" => true, 14 | _ => panic!("Could not figure out if c or c++ wrapper was called. Expected {dir:?} to end with c or cxx"), 15 | }; 16 | 17 | dir.pop(); 18 | 19 | let mut cc = ClangWrapper::new(); 20 | if let Some(code) = cc 21 | .cpp(is_cpp) 22 | // silence the compiler wrapper output, needed for some configure scripts. 23 | .silence(true) 24 | .parse_args(&args) 25 | .expect("Failed to parse the command line") 26 | .link_staticlib(&dir, "appsec_guide") 27 | .add_args(&Configuration::GenerateCoverageMap.to_flags().unwrap()) 28 | .add_args(&Configuration::AddressSanitizer.to_flags().unwrap()) 29 | .run() 30 | .expect("Failed to run the wrapped compiler") 31 | { 32 | std::process::exit(code); 33 | } 34 | } else { 35 | panic!("LibAFL CC: No Arguments given"); 36 | } 37 | } -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_deduplicate/src/bin/libafl_cxx.rs: -------------------------------------------------------------------------------- 1 | pub mod libafl_cc; 2 | 3 | fn main() { 4 | libafl_cc::main(); 5 | } -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_tokens/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "appsec_guide" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["staticlib"] 8 | 9 | [dependencies] 10 | clap = { version = "4", features = ["derive"] } 11 | libafl = { version = "0.13", features = ["casr"] } 12 | libafl_bolts = "0.13" 13 | libafl_cc = "0.13" 14 | libafl_targets = { version = "0.13", features = ["libfuzzer", "sancov_pcguard_hitcounts"] } 15 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_tokens/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | void check_buf(char *buf, size_t buf_len); 6 | 7 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 8 | check_buf((char*) data, size); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_tokens/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void check_buf(char *buf, size_t buf_len) { 5 | if (buf_len >= 4) { 6 | if (memcmp(buf, "buf", 4) == 0) { 7 | abort(); 8 | } 9 | } 10 | 11 | if(buf_len > 0 && buf[0] == 'a') { 12 | if(buf_len > 1 && buf[1] == 'b') { 13 | if(buf_len > 2 && buf[2] == 'c') { 14 | abort(); 15 | } 16 | } 17 | } 18 | } 19 | 20 | #ifndef NO_MAIN 21 | int main() { 22 | char target[] = "123"; 23 | size_t len = strlen(target); 24 | check_buf(target, len); 25 | return 0; 26 | } 27 | #endif // NO_MAIN 28 | -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_tokens/src/bin/libafl_cc.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use libafl_cc::{ClangWrapper, CompilerWrapper, Configuration, ToolWrapper, LLVMPasses}; 4 | 5 | pub fn main() { 6 | let args: Vec = env::args().collect(); 7 | if args.len() > 1 { 8 | let mut dir = env::current_exe().unwrap(); 9 | let wrapper_name = dir.file_name().unwrap().to_str().unwrap(); 10 | 11 | let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() { 12 | "cc" => false, 13 | "++" | "pp" | "xx" => true, 14 | _ => panic!("Could not figure out if c or c++ wrapper was called. Expected {dir:?} to end with c or cxx"), 15 | }; 16 | 17 | dir.pop(); 18 | 19 | let mut cc = ClangWrapper::new(); 20 | if let Some(code) = cc 21 | .cpp(is_cpp) 22 | // silence the compiler wrapper output, needed for some configure scripts. 23 | .silence(true) 24 | .parse_args(&args) 25 | .expect("Failed to parse the command line") 26 | .link_staticlib(&dir, "appsec_guide") 27 | .add_args(&Configuration::GenerateCoverageMap.to_flags().unwrap()) 28 | .add_args(&Configuration::AddressSanitizer.to_flags().unwrap()) 29 | .add_pass(LLVMPasses::AutoTokens) 30 | .run() 31 | .expect("Failed to run the wrapped compiler") 32 | { 33 | std::process::exit(code); 34 | } 35 | } else { 36 | panic!("LibAFL CC: No Arguments given"); 37 | } 38 | } -------------------------------------------------------------------------------- /materials/fuzzing/libafl/appsec_guide_tokens/src/bin/libafl_cxx.rs: -------------------------------------------------------------------------------- 1 | pub mod libafl_cc; 2 | 3 | fn main() { 4 | libafl_cc::main(); 5 | } -------------------------------------------------------------------------------- /materials/fuzzing/libfuzzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(BuggyProgram) 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | add_executable(buggy_program main.cc) 5 | 6 | add_executable(fuzz main.cc harness.cc) 7 | target_compile_definitions(fuzz PRIVATE NO_MAIN=1) 8 | target_compile_options(fuzz PRIVATE -g -O2 -fsanitize=fuzzer) 9 | target_link_libraries(fuzz -fsanitize=fuzzer) 10 | 11 | add_executable(fuzz_exec main.cc harness.cc ${CMAKE_CURRENT_SOURCE_DIR}/../coverage-analysis/execute-rt.cc) 12 | target_compile_definitions(fuzz_exec PRIVATE NO_MAIN) 13 | target_compile_options(fuzz_exec PRIVATE -O2 -fprofile-instr-generate -fcoverage-mapping) 14 | target_link_libraries(fuzz_exec -fprofile-instr-generate) 15 | 16 | 17 | add_executable(fuzz_exec_gcov main.cc harness.cc ${CMAKE_CURRENT_SOURCE_DIR}/../coverage-analysis/execute-rt.cc) 18 | target_compile_definitions(fuzz_exec_gcov PRIVATE NO_MAIN) 19 | target_compile_options(fuzz_exec_gcov PRIVATE -O2 -ftest-coverage -fprofile-arcs) 20 | target_link_libraries(fuzz_exec_gcov -ftest-coverage -fprofile-arcs) 21 | 22 | 23 | -------------------------------------------------------------------------------- /materials/fuzzing/libfuzzer/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void check_buf(char *buf, size_t buf_len); 5 | 6 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 7 | check_buf((char*) data, size); 8 | return 0; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /materials/fuzzing/libfuzzer/interleaved/double.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | double add(double a, double b); 8 | double subtract(double a, double b); 9 | double multiply(double a, double b); 10 | double divide(double a, double b); 11 | 12 | double add(double a, double b) { 13 | return a + b; 14 | } 15 | 16 | double subtract(double a, double b) { 17 | return a - b; 18 | } 19 | 20 | double multiply(double a, double b) { 21 | return a * b; 22 | } 23 | 24 | double divide(double a, double b) { 25 | if (b != 0.0) { // Avoid division by zero 26 | return a / b; 27 | } 28 | 29 | return 0.0; 30 | } 31 | 32 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 33 | if (size < 1 + 2 * sizeof(double)) { 34 | return 0; 35 | } 36 | 37 | uint8_t mode = data[0]; 38 | double numbers[2]; 39 | double r = 0; 40 | memcpy(numbers, data + 1, 2 * sizeof(double)); 41 | 42 | // We select functions based on the first byte of the fuzzing data 43 | switch (mode % 4) { 44 | case 0: 45 | r = add(numbers[0], numbers[1]); 46 | break; 47 | case 1: 48 | r = subtract(numbers[0], numbers[1]); 49 | break; 50 | case 2: 51 | r = multiply(numbers[0], numbers[1]); 52 | break; 53 | case 3: 54 | r = divide(numbers[0], numbers[1]); 55 | break; 56 | } 57 | 58 | printf("%f", r); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /materials/fuzzing/libfuzzer/interleaved/int.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int32_t add(int32_t a, int32_t b); 8 | int32_t subtract(int32_t a, int32_t b); 9 | int32_t multiply(int32_t a, int32_t b); 10 | int32_t divide(int32_t a, int32_t b); 11 | 12 | int32_t add(int32_t a, int32_t b) { 13 | return a + b; 14 | } 15 | 16 | int32_t subtract(int32_t a, int32_t b) { 17 | return a - b; 18 | } 19 | 20 | int32_t multiply(int32_t a, int32_t b) { 21 | return a * b; 22 | } 23 | 24 | int32_t divide(int32_t a, int32_t b) { 25 | // Avoid division by zero and int overflow 26 | if (b != 0 && !(a == INT_MIN && b == -1)) { 27 | return a / b; 28 | } 29 | return 0; 30 | } 31 | 32 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 33 | if (size < 1 + 2 * sizeof(int32_t)) { 34 | return 0; 35 | } 36 | 37 | uint8_t mode = data[0]; 38 | int32_t numbers[2]; 39 | int32_t r = 0; 40 | memcpy(numbers, data + 1, 2 * sizeof(int32_t)); 41 | 42 | // We select functions based on the first byte of the fuzzing data 43 | switch (mode % 4) { 44 | case 0: 45 | r = add(numbers[0], numbers[1]); 46 | break; 47 | case 1: 48 | r = subtract(numbers[0], numbers[1]); 49 | break; 50 | case 2: 51 | r = multiply(numbers[0], numbers[1]); 52 | break; 53 | case 3: 54 | r = divide(numbers[0], numbers[1]); 55 | break; 56 | } 57 | 58 | printf("%d", r); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /materials/fuzzing/libfuzzer/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void check_buf(char *buf, size_t buf_len) { 5 | if(buf_len > 0 && buf[0] == 'a') { 6 | if(buf_len > 1 && buf[1] == 'b') { 7 | if(buf_len > 2 && buf[2] == 'c') { 8 | abort(); 9 | } 10 | } 11 | } 12 | } 13 | 14 | #ifndef NO_MAIN 15 | int main() { 16 | char target[] = "123"; 17 | size_t len = strlen(target); 18 | check_buf(target, len); 19 | return 0; 20 | } 21 | #endif // NO_MAIN 22 | -------------------------------------------------------------------------------- /materials/fuzzing/libfuzzer/main_asan.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void check_buf(char *buf, size_t buf_len) { 6 | char *last; 7 | 8 | if(buf_len > 0 && buf[0] == 'a') { 9 | if(buf_len > 1 && buf[1] == 'b') { 10 | if(buf_len > 2 && buf[2] == 'c') { 11 | last = (char*)malloc(1 * sizeof(char)); 12 | last[0] = 'c'; 13 | last[1] = '\0'; 14 | printf("%s", last); 15 | free(last); 16 | } 17 | } 18 | } 19 | } 20 | 21 | #ifndef NO_MAIN 22 | int main() { 23 | char target[] = "123"; 24 | size_t len = strlen(target); 25 | check_buf(target, len); 26 | return 0; 27 | } 28 | #endif // NO_MAIN 29 | -------------------------------------------------------------------------------- /materials/fuzzing/libpng/libpng-1.6.37.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/materials/fuzzing/libpng/libpng-1.6.37.tar.xz -------------------------------------------------------------------------------- /materials/fuzzing/pc-trace/cb.cc: -------------------------------------------------------------------------------- 1 | // trace-pc-guard-cb.cc 2 | #include 3 | #include 4 | #include 5 | 6 | // This callback is inserted by the compiler as a module constructor 7 | // into every DSO. 'start' and 'stop' correspond to the 8 | // beginning and end of the section with the guards for the entire 9 | // binary (executable or DSO). The callback will be called at least 10 | // once per DSO and may be called multiple times with the same parameters. 11 | extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, 12 | uint32_t *stop) { 13 | static uint64_t N; // Counter for the guards. 14 | if (start == stop || *start) return; // Initialize only once. 15 | printf("INIT: %p %p\n", start, stop); 16 | for (uint32_t *x = start; x < stop; x++) 17 | *x = ++N; // Guards should start from 1. 18 | } 19 | 20 | // This callback is inserted by the compiler on every edge in the 21 | // control flow (some optimizations apply). 22 | // Typically, the compiler will emit the code like this: 23 | // if(*guard) 24 | // __sanitizer_cov_trace_pc_guard(guard); 25 | // But for large functions it will emit a simple call: 26 | // __sanitizer_cov_trace_pc_guard(guard); 27 | extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { 28 | if (!*guard) return; // Duplicate the guard check. 29 | // If you set *guard to 0 this code will not be called again for this edge. 30 | // Now you can get the PC and do whatever you want: 31 | // store it somewhere or symbolize it and print right away. 32 | // The values of `*guard` are as you set them in 33 | // __sanitizer_cov_trace_pc_guard_init and so you can make them consecutive 34 | // and use them to dereference an array or a bit vector. 35 | void *PC = __builtin_return_address(0); 36 | char PcDescr[1024]; 37 | // This function is a part of the sanitizer run-time. 38 | // To use it, link with AddressSanitizer or other sanitizer. 39 | //__sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr)); 40 | printf("guard: %p %x PC %s\n", guard, *guard, PcDescr); 41 | } -------------------------------------------------------------------------------- /materials/fuzzing/pc-trace/trace-pc-guard-example.cc: -------------------------------------------------------------------------------- 1 | void foo() { } 2 | int main(int argc, char **argv) { 3 | if (argc > 1) foo(); 4 | } -------------------------------------------------------------------------------- /materials/fuzzing/rust/afl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "project" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | 11 | arbitrary = { version = "1", features = ["derive"] } 12 | 13 | afl = "*" 14 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/afl/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn divide(numerator: i32, denominator: i32) -> i32 { 2 | // Rust automatically checks for division by zero at runtime, 3 | // so we don't need an explicit check. 4 | numerator / denominator 5 | } 6 | 7 | // -- 8 | 9 | use std::process; 10 | 11 | pub fn check_buf(buf: &[u8]) { 12 | if buf.len() > 0 && buf[0] == b'a' { 13 | if buf.len() > 1 && buf[1] == b'b' { 14 | if buf.len() > 2 && buf[2] == b'c' { 15 | process::abort(); 16 | } 17 | } 18 | } 19 | } 20 | 21 | // -- 22 | 23 | use arbitrary::{Arbitrary}; 24 | 25 | #[derive(Debug, Arbitrary)] 26 | pub struct Name { 27 | data: String 28 | } 29 | 30 | impl Name { 31 | pub fn check_buf(&self) { 32 | let data = self.data.as_bytes(); 33 | if data.len() > 0 && data[0] == b'a' { 34 | if data.len() > 1 && data[1] == b'b' { 35 | if data.len() > 2 && data[2] == b'c' { 36 | process::abort(); 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/afl/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | fn main_unused() { 3 | let buffer: &[u8] = b"123"; 4 | project::check_buf(buffer); 5 | } 6 | 7 | // -- 8 | 9 | #[macro_use] 10 | extern crate afl; 11 | 12 | fn harness(data: &[u8]) { 13 | //project::check_buf(data); 14 | use std::process; 15 | if let Ok(string) = String::from_utf8(data.to_vec()) { 16 | if string.len() > 100 { 17 | if string.len() > 200 { 18 | if string.len() > 300 { 19 | if string.len() > 400 { 20 | if string.len() > 500 { 21 | process::abort(); 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | 31 | fn main() { 32 | fuzz!(|data: &[u8]| { 33 | harness(data); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "project" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | 11 | arbitrary = { version = "1", features = ["derive"] } -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/cov.sh: -------------------------------------------------------------------------------- 1 | export CARGO_LLVM_COV_TARGET_DIR=/root/handbook/rust/cargo-fuzz/fuzz/target 2 | export LLVM_PROFILE_FILE="$CARGO_LLVM_COV_TARGET_DIR/fuzz-%p-%8m.profraw" 3 | 4 | cd fuzz/ 5 | cargo +nightly fuzz run fuzz_divide 6 | cargo +nightly fuzz run fuzz_divide -- -runs=0 corpus/fuzz_divide 7 | cargo llvm-cov report --profile release --target x86_64-unknown-linux-gnu 8 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "project-fuzz" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | libfuzzer-sys = "0.4" 12 | arbitrary = { version = "1", features = ["derive"] } 13 | bytemuck = "1.14.0" 14 | 15 | [dependencies.project] 16 | path = ".." 17 | 18 | # Prevent this from interfering with workspaces 19 | [workspace] 20 | members = ["."] 21 | 22 | [profile.release] 23 | debug = 1 24 | 25 | [[bin]] 26 | name = "fuzz_divide" 27 | path = "fuzz_targets/fuzz_divide.rs" 28 | test = false 29 | doc = false 30 | 31 | [[bin]] 32 | name = "fuzz_check_buf" 33 | path = "fuzz_targets/fuzz_check_buf.rs" 34 | test = false 35 | doc = false 36 | 37 | [[bin]] 38 | name = "fuzz_target_1" 39 | path = "fuzz_targets/fuzz_check_buf.rs" 40 | test = false 41 | doc = false 42 | 43 | [[bin]] 44 | name = "fuzz_impossible" 45 | path = "fuzz_targets/fuzz_impossible.rs" 46 | test = false 47 | doc = false 48 | 49 | 50 | [[bin]] 51 | name = "fuzz_arbitrary" 52 | path = "fuzz_targets/fuzz_arbitrary.rs" 53 | test = false 54 | doc = false 55 | [[bin]] 56 | name = "fuzz_arbitrary_short" 57 | path = "fuzz_targets/fuzz_arbitrary_short.rs" 58 | test = false 59 | doc = false 60 | [[bin]] 61 | name = "fuzz_interleaved" 62 | path = "fuzz_targets/fuzz_interleaved.rs" 63 | test = false 64 | doc = false 65 | [[bin]] 66 | name = "fuzz_beyond_byte_arrays" 67 | path = "fuzz_targets/fuzz_beyond_byte_arrays.rs" 68 | test = false 69 | doc = false 70 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_arbitrary.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | use arbitrary::{Arbitrary, Unstructured}; 5 | 6 | fn harness(data: &[u8]) { 7 | // Wrap it in an `Unstructured`. 8 | let mut unstructured = Unstructured::new(data); 9 | 10 | // Generate an `Name` and run our checks. 11 | if let Ok(name) = project::Name::arbitrary(&mut unstructured) { 12 | name.check_buf(); 13 | } 14 | } 15 | 16 | fuzz_target!(|data: &[u8]| { 17 | harness(data); 18 | }); 19 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_arbitrary_short.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | 5 | fn harness(data: &project::Name) { 6 | data.check_buf(); 7 | } 8 | 9 | fuzz_target!(|data: project::Name| { 10 | harness(&data); 11 | }); 12 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_beyond_byte_arrays.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | use std::slice; 5 | 6 | pub fn divide(numerator: i32, denominator: i32) -> i32 { 7 | // Rust automatically checks for division by zero at runtime, 8 | // so we don't need an explicit check. 9 | numerator / denominator 10 | } 11 | 12 | fuzz_target!(|data: &[u8]| { 13 | if data.len() != 2 * std::mem::size_of::() { 14 | return; 15 | } 16 | 17 | // Split input into numerator and denominator 18 | let numerator = i32::from_ne_bytes([data[0], data[1], data[2], data[3]]); 19 | let denominator = i32::from_ne_bytes([data[4], data[5], data[6], data[7]]); 20 | 21 | divide(numerator, denominator); 22 | }); 23 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_check_buf.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | 5 | fn harness(data: &[u8]) { 6 | project::check_buf(data); 7 | } 8 | 9 | fuzz_target!(|data: &[u8]| { 10 | harness(data); 11 | }); 12 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_divide.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | use std::slice; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let size = data.len(); 8 | if size != 2 * std::mem::size_of::() { 9 | return; 10 | } 11 | 12 | // Split input into numerator and denominator 13 | let numerator = i32::from_ne_bytes([data[0], data[1], data[2], data[3]]); 14 | let denominator = i32::from_ne_bytes([data[4], data[5], data[6], data[7]]); 15 | 16 | project::divide(numerator, denominator); 17 | }); 18 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_impossible.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | use std::process; 5 | use std::slice; 6 | 7 | fuzz_target!(|data: &[u8]| { 8 | if let Ok(string) = String::from_utf8(data.to_vec()) { 9 | if string.len() > 100 { 10 | if string.len() > 200 { 11 | if string.len() > 300 { 12 | if string.len() > 400 { 13 | if string.len() > 500 { 14 | process::abort(); 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_interleaved.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | pub trait Arithmetic: Sized { 5 | fn add(self, other: Self) -> Self; 6 | fn subtract(self, other: Self) -> Self; 7 | fn multiply(self, other: Self) -> Self; 8 | fn divide(self, other: Self) -> Option; 9 | } 10 | 11 | impl Arithmetic for f64 { 12 | fn add(self, other: Self) -> Self { 13 | self + other 14 | } 15 | 16 | fn subtract(self, other: Self) -> Self { 17 | self - other 18 | } 19 | 20 | fn multiply(self, other: Self) -> Self { 21 | self * other 22 | } 23 | 24 | fn divide(self, other: Self) -> Option { 25 | if other == 0.0 { None } else { Some(self / other) } 26 | } 27 | } 28 | 29 | fuzz_target!(|data: &[u8]| { 30 | if data.len() < 1 + 2 * std::mem::size_of::() { 31 | return; // Not enough data for mode and two f64 numbers 32 | } 33 | 34 | let mode = data[0]; 35 | let numbers = &data[1..]; 36 | 37 | if let [first, second] = *bytemuck::try_cast_slice::<_, f64>(numbers).unwrap_or_else(|_| &[0.0, 0.0]) { 38 | match mode % 4 { 39 | 0 => { first.add(second); }, 40 | 1 => { first.subtract(second); }, 41 | 2 => { first.multiply(second); }, 42 | 3 => { first.divide(second); }, 43 | _ => {} 44 | } 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/fuzz/fuzz_targets/fuzz_interleaved_int.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | pub trait Arithmetic: Sized { 5 | fn add(self, other: Self) -> Self; 6 | fn subtract(self, other: Self) -> Self; 7 | fn multiply(self, other: Self) -> Self; 8 | fn divide(self, other: Self) -> Option; 9 | } 10 | 11 | impl Arithmetic for i32 { 12 | fn add(self, other: Self) -> Self { 13 | self + other 14 | } 15 | 16 | fn subtract(self, other: Self) -> Self { 17 | self - other 18 | } 19 | 20 | fn multiply(self, other: Self) -> Self { 21 | self * other 22 | } 23 | 24 | fn divide(self, other: Self) -> Option { 25 | if other == 0 { None } else { Some(self / other) } 26 | } 27 | } 28 | 29 | fuzz_target!(|data: &[u8]| { 30 | if data.len() < 1 + 2 * std::mem::size_of::() { 31 | return; // Not enough data for mode and two i32 numbers 32 | } 33 | 34 | let mode = data[0]; 35 | let numbers = &data[1..]; 36 | 37 | if let [first, second] = *bytemuck::try_cast_slice::<_, i32>(numbers).unwrap_or_else(|_| &[0, 0]) { 38 | match mode % 4 { 39 | 0 => { first.add(second); }, 40 | 1 => { first.subtract(second); }, 41 | 2 => { first.multiply(second); }, 42 | 3 => { first.divide(second); }, 43 | _ => {} 44 | } 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn divide(numerator: i32, denominator: i32) -> i32 { 2 | // Rust automatically checks for division by zero at runtime, 3 | // so we don't need an explicit check. 4 | numerator / denominator 5 | } 6 | 7 | // -- 8 | 9 | use std::process; 10 | 11 | pub fn check_buf(buf: &[u8]) { 12 | if buf.len() > 0 && buf[0] == b'a' { 13 | if buf.len() > 1 && buf[1] == b'b' { 14 | if buf.len() > 2 && buf[2] == b'c' { 15 | process::abort(); 16 | } 17 | } 18 | } 19 | } 20 | 21 | // -- 22 | 23 | use arbitrary::{Arbitrary}; 24 | 25 | #[derive(Debug, Arbitrary)] 26 | pub struct Name { 27 | data: String 28 | } 29 | 30 | impl Name { 31 | pub fn check_buf(&self) { 32 | let data = self.data.as_bytes(); 33 | if data.len() > 0 && data[0] == b'a' { 34 | if data.len() > 1 && data[1] == b'b' { 35 | if data.len() > 2 && data[2] == b'c' { 36 | process::abort(); 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/cargo-fuzz/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | fn main() { 3 | let buffer: &[u8] = b"123"; 4 | project::check_buf(buffer); 5 | } 6 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/ogg/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ogg-fuzz" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | libfuzzer-sys = "0.4" 12 | 13 | [dependencies.ogg] 14 | path = ".." 15 | 16 | # Prevent this from interfering with workspaces 17 | [workspace] 18 | members = ["."] 19 | 20 | [profile.release] 21 | debug = 1 22 | 23 | [[bin]] 24 | name = "fuzz_target_1" 25 | path = "fuzz_targets/fuzz_target_1.rs" 26 | test = false 27 | doc = false -------------------------------------------------------------------------------- /materials/fuzzing/rust/ogg/fuzz/fuzz_targets/fuzz_target_1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use ogg::{PacketReader, PacketWriter}; 4 | use ogg::writing::PacketWriteEndInfo; 5 | use std::fs::File; 6 | use std::io::Cursor; 7 | 8 | use libfuzzer_sys::fuzz_target; 9 | 10 | fn harness(data: &[u8]) { 11 | let mut data = data.to_vec(); 12 | let mut pck_rdr = PacketReader::new(Cursor::new(data)); 13 | 14 | pck_rdr.delete_unread_packets(); 15 | 16 | let output = Vec::new(); 17 | 18 | let mut pck_wtr = PacketWriter::new(Cursor::new(output)); 19 | 20 | if let Ok(r) = pck_rdr.read_packet() { 21 | if let Ok(r) = pck_rdr.read_packet() { 22 | match r { 23 | Some(pck) => { 24 | let inf = if pck.last_in_stream() { 25 | PacketWriteEndInfo::EndStream 26 | } else if pck.last_in_page() { 27 | PacketWriteEndInfo::EndPage 28 | } else { 29 | PacketWriteEndInfo::NormalPacket 30 | }; 31 | let stream_serial = pck.stream_serial(); 32 | let absgp_page = pck.absgp_page(); 33 | let _ = pck_wtr.write_packet(pck.data, stream_serial, inf, absgp_page); 34 | } 35 | // End of stream 36 | None => return, 37 | } 38 | } 39 | } 40 | } 41 | 42 | fuzz_target!(|data: &[u8]| { 43 | harness(data); 44 | }); 45 | -------------------------------------------------------------------------------- /materials/fuzzing/rust/run.rs: -------------------------------------------------------------------------------- 1 | /// Link to the C function LLVMFuzzerTestOneInput 2 | extern { 3 | fn LLVMFuzzerTestOneInput(Data: *const u8, Size: size_t); 4 | } 5 | 6 | fn main() { 7 | // Get the first argument 8 | let args: Vec = env::args().collect(); 9 | if args.len() < 2 { 10 | println!("Please provide a directory as an argument"); 11 | return; 12 | } 13 | 14 | let dir = &args[1]; 15 | 16 | let paths = fs::read_dir(dir).unwrap(); 17 | 18 | for path in paths { 19 | let path = path.unwrap().path(); 20 | if path.is_file() { 21 | let mut file = fs::File::open(&path).unwrap(); 22 | let mut contents = Vec::new(); 23 | file.read_to_end(&mut contents).unwrap(); 24 | 25 | // call LLVMFuzzerTestOneInput for each file 26 | let c_data = CString::new(contents).unwrap(); 27 | unsafe { 28 | LLVMFuzzerTestOneInput(c_data.as_ptr() as *const u8, c_data.as_bytes().len()); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /mlc_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": [ 3 | { 4 | "pattern": "^https://twitter.com" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | # This nix-shell only supports macOS right now. Soon I will also add support for Linux 2 | # The repository supports direnv (https://direnv.net/). If your IDE supports direnv, 3 | # then you do not need to care about dependencies. 4 | 5 | { pkgs ? import { } }: 6 | with pkgs; 7 | (pkgs.mkShell.override { 8 | stdenv = stdenvNoCC; 9 | }) { 10 | nativeBuildInputs = [ 11 | pkgs.hugo 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /static/TOB_Black.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /static/code-scanning-protection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/static/code-scanning-protection.png -------------------------------------------------------------------------------- /static/code-scanning-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/static/code-scanning-setup.png -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/static/favicon.png -------------------------------------------------------------------------------- /static/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /static/generate-codeql-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/static/generate-codeql-query.png -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/static/logo.png -------------------------------------------------------------------------------- /static/svg/copy-regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/view-codeql-ast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/static/view-codeql-ast.png -------------------------------------------------------------------------------- /th-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trailofbits/testing-handbook/c40e441860d42ed5d1f9df4c167f54bc0befff2a/th-logo.jpg --------------------------------------------------------------------------------