debian-mirror-gitlab/doc/user/application_security/coverage_fuzzing/index.md

259 lines
18 KiB
Markdown
Raw Normal View History

2020-07-28 23:09:34 +05:30
---
stage: Secure
2021-09-04 01:27:46 +05:30
group: Dynamic Analysis
2021-02-22 17:27:13 +05:30
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
2020-07-28 23:09:34 +05:30
type: reference, howto
---
2021-11-11 11:23:49 +05:30
# Coverage-guided fuzz testing **(ULTIMATE)**
2020-07-28 23:09:34 +05:30
2022-03-02 08:16:31 +05:30
Coverage-guided fuzz testing sends random inputs to an instrumented version of your application in
an effort to cause unexpected behavior. Such behavior indicates a bug that you should address.
2020-07-28 23:09:34 +05:30
GitLab allows you to add coverage-guided fuzz testing to your pipelines. This helps you discover
2021-11-18 22:05:49 +05:30
bugs and potential security issues that other QA processes may miss.
2020-07-28 23:09:34 +05:30
We recommend that you use fuzz testing in addition to the other security scanners in [GitLab Secure](../index.md)
2021-09-30 23:02:18 +05:30
and your own test processes. If you're using [GitLab CI/CD](../../../ci/index.md),
2022-03-02 08:16:31 +05:30
you can run your coverage-guided fuzz testing as part your CI/CD workflow.
2021-11-18 22:05:49 +05:30
## Coverage-guided fuzz testing process
The fuzz testing process:
1. Compiles the target application.
1. Runs the instrumented application, using the `gitlab-cov-fuzz` tool.
1. Parses and analyzes the exception information output by the fuzzer.
1. Downloads the [corpus](../terminology/index.md#corpus) and crash events from previous pipelines.
1. Outputs the parsed crash events and data to the `gl-coverage-fuzzing-report.json` file.
The results of the coverage-guided fuzz testing are available in the CI/CD pipeline.
2020-07-28 23:09:34 +05:30
## Supported fuzzing engines and languages
2022-03-02 08:16:31 +05:30
You can use the following fuzzing engines to test the specified languages.
| Language | Fuzzing Engine | Example |
|---------------------------------------------|------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| C/C++ | [libFuzzer](https://llvm.org/docs/LibFuzzer.html) | [c-cpp-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/c-cpp-fuzzing-example) |
| GoLang | [go-fuzz (libFuzzer support)](https://github.com/dvyukov/go-fuzz) | [go-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example) |
| Swift | [libFuzzer](https://github.com/apple/swift/blob/master/docs/libFuzzerIntegration.md) | [swift-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/swift-fuzzing-example) |
| Rust | [cargo-fuzz (libFuzzer support)](https://github.com/rust-fuzz/cargo-fuzz) | [rust-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/rust-fuzzing-example) |
| Java | [Javafuzz](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/javafuzz) (recommended) | [javafuzz-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/javafuzz-fuzzing-example) |
| Java | [JQF](https://github.com/rohanpadhye/JQF) (not preferred) | [jqf-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/java-fuzzing-example) |
| JavaScript | [`jsfuzz`](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/jsfuzz) | [jsfuzz-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/jsfuzz-fuzzing-example) |
| Python | [`pythonfuzz`](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/pythonfuzz) | [pythonfuzz-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/pythonfuzz-fuzzing-example) |
| AFL (any language that works on top of AFL) | [AFL](https://lcamtuf.coredump.cx/afl/) | [afl-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/afl-fuzzing-example) |
2020-07-28 23:09:34 +05:30
## Configuration
2022-03-02 08:16:31 +05:30
To enable coverage-guided fuzz testing, edit the `.gitlab-ci.yml` file:
1. Add the `fuzz` stage to the list of stages.
1. If your application is not written in Go, [provide a Docker image](../../../ci/yaml/index.md#image) using the matching fuzzing
engine. For example:
```yaml
image: python:latest
```
1. [Include](../../../ci/yaml/index.md#includetemplate) the
[`Coverage-Fuzzing.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml)
provided as part of your GitLab installation.
2020-07-28 23:09:34 +05:30
2022-03-02 08:16:31 +05:30
1. Customize the `my_fuzz_target` job to meet your requirements.
### Example extract of coverage-guided fuzzing configuration
2020-07-28 23:09:34 +05:30
```yaml
2021-03-11 19:13:27 +05:30
stages:
- fuzz
2020-07-28 23:09:34 +05:30
include:
- template: Coverage-Fuzzing.gitlab-ci.yml
2021-03-11 19:13:27 +05:30
my_fuzz_target:
extends: .fuzz_base
script:
2022-03-02 08:16:31 +05:30
# Build your fuzz target binary in these steps, then run it with gitlab-cov-fuzz
2021-03-11 19:13:27 +05:30
# See our example repos for how you could do this with any of our supported languages
- ./gitlab-cov-fuzz run --regression=$REGRESSION -- <your fuzz target>
2020-07-28 23:09:34 +05:30
```
2022-03-02 08:16:31 +05:30
The `Coverage-Fuzzing` template includes the [hidden job](../../../ci/jobs/index.md#hide-jobs)
`.fuzz_base`, which you must [extend](../../../ci/yaml/index.md#extends) for each of your fuzzing
targets. Each fuzzing target **must** have a separate job. For example, the
2020-07-28 23:09:34 +05:30
[go-fuzzing-example project](https://gitlab.com/gitlab-org/security-products/demos/go-fuzzing-example)
2022-03-02 08:16:31 +05:30
contains one job that extends `.fuzz_base` for its single fuzzing target.
2020-07-28 23:09:34 +05:30
2020-10-24 23:57:45 +05:30
Note that the hidden job `.fuzz_base` uses several YAML keys that you must not override in your own
2022-03-02 08:16:31 +05:30
job. If you include these keys in your own job, you must copy their original content:
2020-10-24 23:57:45 +05:30
- `before_script`
- `artifacts`
- `rules`
2022-03-02 08:16:31 +05:30
### Available CI/CD variables
Use the following variables to configure coverage-guided fuzz testing in your CI/CD pipeline.
2020-07-28 23:09:34 +05:30
2022-03-02 08:16:31 +05:30
| CI/CD variable | Description |
|---------------------------|---------------------------------------------------------------------------------|
| `COVFUZZ_ADDITIONAL_ARGS` | Arguments passed to `gitlab-cov-fuzz`. Used to customize the behavior of the underlying fuzzing engine. Read the fuzzing engine's documentation for a complete list of arguments. |
| `COVFUZZ_BRANCH` | The branch on which long-running fuzzing jobs are to be run. On all other branches, only fuzzing regression tests are run. Default: Repository's default branch. |
| `COVFUZZ_SEED_CORPUS` | Path to a seed corpus directory. Default: empty. |
| `COVFUZZ_URL_PREFIX` | Path to the `gitlab-cov-fuzz` repository cloned for use with an offline environment. You should only change this value when using an offline environment. Default: `https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz/-/raw`. |
2020-07-28 23:09:34 +05:30
2022-03-02 08:16:31 +05:30
#### Seed corpus
2020-07-28 23:09:34 +05:30
2022-03-02 08:16:31 +05:30
Files in the [seed corpus](../terminology/index.md#seed-corpus) must be updated manually. They are
not updated or overwritten by the coverage-guide fuzz testing job.
## Output
2020-07-28 23:09:34 +05:30
Each fuzzing step outputs these artifacts:
2022-03-02 08:16:31 +05:30
- `gl-coverage-fuzzing-report.json`: A report containing details of the coverage-guided fuzz testing
and its results.
2020-07-28 23:09:34 +05:30
- `artifacts.zip`: This file contains two directories:
2022-03-02 08:16:31 +05:30
- `corpus`: Contains all test cases generated by the current and all previous jobs.
- `crashes`: Contains all crash events the current job found and those not fixed in
2020-07-28 23:09:34 +05:30
previous jobs.
2022-03-02 08:16:31 +05:30
You can download the JSON report file from the CI/CD pipelines page. For more information, see
[Downloading artifacts](../../../ci/pipelines/job_artifacts.md#download-job-artifacts).
2020-10-24 23:57:45 +05:30
2022-03-02 08:16:31 +05:30
### Coverage-guided fuzz testing report
2020-10-24 23:57:45 +05:30
2021-12-11 22:18:48 +05:30
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220062) in GitLab 13.3 as an [Alpha feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#alpha).
2020-10-24 23:57:45 +05:30
2022-03-02 08:16:31 +05:30
For detailed information about the `gl-coverage-fuzzing-report.json` file's format, read the
[schema](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/coverage-fuzzing-report-format.json).
2020-10-24 23:57:45 +05:30
2022-03-02 08:16:31 +05:30
Example coverage-guided fuzzing report:
2020-10-24 23:57:45 +05:30
```json-doc
{
"version": "v1.0.8",
"regression": false,
"exit_code": -1,
"vulnerabilities": [
{
"category": "coverage_fuzzing",
"message": "Heap-buffer-overflow\nREAD 1",
"description": "Heap-buffer-overflow\nREAD 1",
"severity": "Critical",
"stacktrace_snippet": "INFO: Seed: 3415817494\nINFO: Loaded 1 modules (7 inline 8-bit counters): 7 [0x10eee2470, 0x10eee2477), \nINFO: Loaded 1 PC tables (7 PCs): 7 [0x10eee2478,0x10eee24e8), \nINFO: 5 files found in corpus\nINFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes\nINFO: seed corpus: files: 5 min: 1b max: 4b total: 14b rss: 26Mb\n#6\tINITED cov: 7 ft: 7 corp: 5/14b exec/s: 0 rss: 26Mb\n=================================================================\n==43405==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000001573 at pc 0x00010eea205a bp 0x7ffee0d5e090 sp 0x7ffee0d5e088\nREAD of size 1 at 0x602000001573 thread T0\n #0 0x10eea2059 in FuzzMe(unsigned char const*, unsigned long) fuzz_me.cc:9\n #1 0x10eea20ba in LLVMFuzzerTestOneInput fuzz_me.cc:13\n #2 0x10eebe020 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:556\n #3 0x10eebd765 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) FuzzerLoop.cpp:470\n #4 0x10eebf966 in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:698\n #5 0x10eec0665 in fuzzer::Fuzzer::Loop(std::__1::vector\u003cfuzzer::SizedFile, fuzzer::fuzzer_allocator\u003cfuzzer::SizedFile\u003e \u003e\u0026) FuzzerLoop.cpp:830\n #6 0x10eead0cd in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:829\n #7 0x10eedaf82 in main FuzzerMain.cpp:19\n #8 0x7fff684fecc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)\n\n0x602000001573 is located 0 bytes to the right of 3-byte region [0x602000001570,0x602000001573)\nallocated by thread T0 here:\n #0 0x10ef92cfd in wrap__Znam+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x50cfd)\n #1 0x10eebdf31 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:541\n #2 0x10eebd765 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) FuzzerLoop.cpp:470\n #3 0x10eebf966 in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:698\n #4 0x10eec0665 in fuzzer::Fuzzer::Loop(std::__1::vector\u003cfuzzer::SizedFile, fuzzer::fuzzer_allocator\u003cfuzzer::SizedFile\u003e \u003e\u0026) FuzzerLoop.cpp:830\n #5 0x10eead0cd in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:829\n #6 0x10eedaf82 in main FuzzerMain.cpp:19\n #7 0x7fff684fecc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)\n\nSUMMARY: AddressSanitizer: heap-buffer-overflow fuzz_me.cc:9 in FuzzMe(unsigned char const*, unsigned long)\nShadow bytes around the buggy address:\n 0x1c0400000250: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000260: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000270: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000280: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000290: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n=\u003e0x1c04000002a0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa[03]fa\n 0x1c04000002b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\nShadow byte legend (one shadow byte represents 8 application bytes):\n Addressable: 00\n Partially addressable: 01 02 03 04 05 06 07 \n Heap left redzone: fa\n Freed heap region: fd\n Stack left redzone: f1\n Stack mid redzone: f2\n Stack right redzone: f3\n Stack after return: f5\n Stack use after scope: f8\n Global redzone: f9\n Global init order: f6\n Poisoned by user: f7\n Container overflow: fc\n Array cookie: ac\n Intra object redzone: bb\n ASan internal: fe\n Left alloca redzone: ca\n Right alloca redzone: cb\n Shadow gap:
"scanner": {
"id": "libFuzzer",
"name": "libFuzzer"
},
"location": {
"crash_address": "0x602000001573",
"crash_state": "FuzzMe\nstart\nstart+0x0\n\n",
"crash_type": "Heap-buffer-overflow\nREAD 1"
},
"tool": "libFuzzer"
}
]
}
```
2020-07-28 23:09:34 +05:30
2022-03-02 08:16:31 +05:30
## Duration of coverage-guided fuzz testing
2020-10-24 23:57:45 +05:30
2022-03-02 08:16:31 +05:30
The available durations for coverage-guided fuzz testing are: 10 minutes (default) and 60 minutes.
2020-10-24 23:57:45 +05:30
2022-03-02 08:16:31 +05:30
- 10-minute duration: Recommended for the default branch.
- 60-minute duration: Recommended for the development branch and merge requests. The longer duration provides greater coverage.
In the `COVFUZZ_ADDITIONAL_ARGS` variable set the value `--regression=true`.
2020-10-24 23:57:45 +05:30
2022-03-02 08:16:31 +05:30
For a complete example, read the [Go coverage-guided fuzzing example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example/-/blob/master/.gitlab-ci.yml).
2020-10-24 23:57:45 +05:30
2022-03-02 08:16:31 +05:30
### Continuous coverage-guided fuzz testing
2021-01-03 14:25:43 +05:30
2022-03-02 08:16:31 +05:30
It's also possible to run the coverage-guided fuzzing jobs longer and without blocking your main
pipeline. This configuration uses the GitLab
[parent-child pipelines](../../../ci/pipelines/parent_child_pipelines.md).
2021-01-03 14:25:43 +05:30
2022-03-02 08:16:31 +05:30
The suggested workflow in this scenario is to have long-running, asynchronous fuzzing jobs on the
main or development branch, and short synchronous fuzzing jobs on all other branches and MRs. This
balances the needs of completing the per-commit pipeline complete quickly, while also giving the
fuzzer a large amount of time to fully explore and test the app. Long-running fuzzing jobs are
usually necessary for the coverage-guided fuzzer to find deeper bugs in your codebase.
2021-01-03 14:25:43 +05:30
2022-03-02 08:16:31 +05:30
The following is an extract of the `.gitlab-ci.yml` file for this
workflow. For the full example, see the [Go fuzzing example's repository](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example/-/tree/continuous_fuzzing):
2021-01-03 14:25:43 +05:30
```yaml
sync_fuzzing:
variables:
COVFUZZ_ADDITIONAL_ARGS: '-max_total_time=300'
trigger:
include: .covfuzz-ci.yml
strategy: depend
rules:
- if: $CI_COMMIT_BRANCH != 'continuous_fuzzing' && $CI_PIPELINE_SOURCE != 'merge_request_event'
async_fuzzing:
variables:
2021-03-11 19:13:27 +05:30
COVFUZZ_ADDITIONAL_ARGS: '-max_total_time=3600'
2021-01-03 14:25:43 +05:30
trigger:
include: .covfuzz-ci.yml
rules:
- if: $CI_COMMIT_BRANCH == 'continuous_fuzzing' && $CI_PIPELINE_SOURCE != 'merge_request_event'
```
2022-03-02 08:16:31 +05:30
This creates two jobs:
2021-01-03 14:25:43 +05:30
1. `sync_fuzzing`: Runs all your fuzz targets for a short period of time in a blocking
configuration. This finds simple bugs and allows you to be confident that your MRs aren't
introducing new bugs or causing old bugs to reappear.
1. `async_fuzzing`: Runs on your branch and finds deep bugs in your code without blocking your
development cycle and MRs.
The `covfuzz-ci.yml` is the same as that in the [original synchronous example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example#running-go-fuzz-from-ci).
2022-03-02 08:16:31 +05:30
## Offline environment
To use coverage fuzzing in an offline environment:
1. Clone [`gitlab-cov-fuzz`](https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz)
to a private repository that your offline GitLab instance can access.
1. For each fuzzing step, set `COVFUZZ_URL_PREFIX` to `${NEW_URL_GITLAB_COV_FUZ}/-/raw`, where
`NEW_URL_GITLAB_COV_FUZ` is the URL of the private `gitlab-cov-fuzz` clone that you set up in the
first step.
2021-01-29 00:20:46 +05:30
## Interacting with the vulnerabilities
2021-06-08 01:23:25 +05:30
After a vulnerability is found, you can [address it](../vulnerabilities/index.md).
2021-01-29 00:20:46 +05:30
The merge request widget lists the vulnerability and contains a button for downloading the fuzzing
artifacts. By clicking one of the detected vulnerabilities, you can see its details.
![Coverage Fuzzing Security Report](img/coverage_fuzzing_report_v13_6.png)
You can also view the vulnerability from the [Security Dashboard](../security_dashboard/index.md),
which shows an overview of all the security vulnerabilities in your groups, projects, and pipelines.
Clicking the vulnerability opens a modal that provides additional information about the
vulnerability:
2021-11-18 22:05:49 +05:30
<!-- vale gitlab.Acronyms = NO -->
2021-01-29 00:20:46 +05:30
- Status: The vulnerability's status. As with any type of vulnerability, a coverage fuzzing
vulnerability can be Detected, Confirmed, Dismissed, or Resolved.
- Project: The project in which the vulnerability exists.
- Crash type: The type of crash or weakness in the code. This typically maps to a [CWE](https://cwe.mitre.org/).
2021-03-11 19:13:27 +05:30
- Crash state: A normalized version of the stack trace, containing the last three functions of the
2021-01-29 00:20:46 +05:30
crash (without random addresses).
2021-03-11 19:13:27 +05:30
- Stack trace snippet: The last few lines of the stack trace, which shows details about the crash.
2021-01-29 00:20:46 +05:30
- Identifier: The vulnerability's identifier. This maps to either a [CVE](https://cve.mitre.org/)
or [CWE](https://cwe.mitre.org/).
- Severity: The vulnerability's severity. This can be Critical, High, Medium, Low, Info, or Unknown.
- Scanner: The scanner that detected the vulnerability (for example, Coverage Fuzzing).
- Scanner Provider: The engine that did the scan. For Coverage Fuzzing, this can be any of the
engines listed in [Supported fuzzing engines and languages](#supported-fuzzing-engines-and-languages).
2021-11-18 22:05:49 +05:30
<!-- vale gitlab.Acronyms = YES -->