- 커버리지 안내 퍼즈 테스트 프로세스
- 지원되는 퍼징 엔진 및 언어
- 커버리지 안내 퍼즈 테스트 상태 확인
- 커버리지 안내 퍼즈 테스트 활성화
- 출력
- 코퍼스 레지스트리
- 커버리지 가이드 퍼즈 테스트 보고서
- FIPS 사용 가능한 이진 파일
- 오프라인 환경
- 취약점과 상호 작용
- 문제 해결
커버리지 안내 퍼즈 테스트
커버리지 안내 퍼즈 테스트는 응용 프로그램의 계측된 버전에 무작위 입력을 보내 예상치 못한 동작을 유발하려고 합니다. 이러한 동작은 해결해야 할 버그를 나타냅니다. GitLab을 사용하면 파이프라인에 커버리지 안내 퍼즈 테스트를 추가할 수 있습니다. 이를 통해 일반적인 QA 과정에서 놓칠 수 있는 버그 및 잠재적 보안 문제를 발견할 수 있습니다.
우리는 GitLab Secure의 다른 보안 스캐너와 귀하의 테스트 프로세스에 퍼즈 테스트를 사용하는 것을 권장합니다. GitLab CI/CD를 사용하는 경우 CI/CD 워크플로우의 일부로 커버리지 안내 퍼즈 테스트를 실행할 수 있습니다.
개요는 커버리지 퍼징를 참조하십시오.
커버리지 안내 퍼즈 테스트 프로세스
퍼즈 테스트 프로세스:
- 대상 응용 프로그램을 컴파일합니다.
-
gitlab-cov-fuzz
도구를 사용하여 계측된 응용 프로그램을 실행합니다. - 퍼저에 의해 출력된 예외 정보를 구문 분석합니다.
- 이전 파이프라인 또는
COVFUZZ_USE_REGISTRY
가true
로 설정된 경우 코퍼스를 다운로드합니다. - 이전 파이프라인에서 충돌 이벤트를 다운로드합니다.
- 구문 분석된 충돌 이벤트 및 데이터를
gl-coverage-fuzzing-report.json
파일에 출력합니다. - 작업의 파이프라인 또는
COVFUZZ_USE_REGISTRY
가true
로 설정된 경우 코퍼스를 업데이트합니다.
커버리지 안내 퍼즈 테스트의 결과는 CI/CD 파이프라인에서 확인할 수 있습니다.
지원되는 퍼징 엔진 및 언어
지원하는 퍼징 엔진을 사용하여 지정된 언어를 테스트할 수 있습니다.
언어 | 퍼징 엔진 | 예시 |
---|---|---|
C/C++ | libFuzzer | c-cpp-example |
Go | go-fuzz (libFuzzer support) | go-fuzzing-example |
Swift | libFuzzer | swift-fuzzing-example |
Rust | cargo-fuzz (libFuzzer support) | rust-fuzzing-example |
Java (Maven only)1 | Javafuzz (권장) | javafuzz-fuzzing-example |
Java | JQF (비권장) | jqf-fuzzing-example |
JavaScript | jsfuzz
| jsfuzz-fuzzing-example |
Python | pythonfuzz
| pythonfuzz-fuzzing-example |
AFL (AFL 상에서 작동하는 어떤 언어든) | AFL | afl-fuzzing-example |
- Gradle 지원은 이슈 409764에 계획되어 있습니다.
커버리지 안내 퍼즈 테스트 상태 확인
커버리지 안내 퍼즈 테스트 상태를 확인하려면:
- 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
- 보안 > 보안 구성을 선택합니다.
-
커버리지 퍼징 섹션에서 상태는 다음 중 하나입니다:
- 구성되지 않음
- 활성화됨
- GitLab Ultimate로 업그레이드하라는 프롬프트
커버리지 안내 퍼즈 테스트 활성화
커버리지 안내 퍼즈 테스트를 활성화하려면 .gitlab-ci.yml
을 편집합니다:
-
fuzz
스테이지를 스테이지 목록에 추가합니다. -
응용 프로그램이 Go로 작성되지 않은 경우 해당 퍼징 엔진을 사용하는 Docker 이미지를 제공합니다. 예:
yaml image: python:latest
-
제공된
Coverage-Fuzzing.gitlab-ci.yml
템플릿을 GitLab 설치의 일부로 포함합니다. -
my_fuzz_target
작업을 귀하의 요구에 맞게 사용자 정의합니다.
Coverage-Guided Fuzzing 구성 예제
stages:
- fuzz
include:
- template: Coverage-Fuzzing.gitlab-ci.yml
my_fuzz_target:
extends: .fuzz_base
script:
# 이러한 단계에서 퍼징 대상 이진 파일을 빌드한 다음 gitlab-cov-fuzz로 실행합니다.
# 지원되는 언어 중 하나로도 이 작업을 수행할 수 있는 예제 저장소를 확인하세요.
- ./gitlab-cov-fuzz run --regression=$REGRESSION -- <your fuzz target>
Coverage-Fuzzing
템플릿은 숨겨진 작업인 .fuzz_base
를 포함하며, 각 퍼징 대상에 대해 확장해야 합니다. 각 퍼징 대상은 별도의 작업이어야 합니다. 예를 들어, go-fuzzing-example 프로젝트에는 .fuzz_base
를 확장하여 하나의 퍼징 대상에 대한 작업이 하나 포함되어 있습니다.
숨겨진 작업인 .fuzz_base
는 여러 YAML 키를 사용하며, 이러한 키는 자체 작업에서 덮어쓰면 안 됩니다. 자신의 작업에 이러한 키를 포함해야 하는 경우 원본 내용을 복사해야 합니다:
before_script
artifacts
rules
사용 가능한 CI/CD 변수
CI/CD 파이프라인에서 커버리지 기준 퍼징 테스트를 구성하는 데 다음 변수를 사용합니다.
경고: GitLab 보안 스캔 도구의 모든 사용자 정의는 기본 브랜치에 변경사항을 병합하기 전에 병합 요청에서 테스트되어야 합니다. 이를 하지 않으면 예기치 않은 결과가 발생할 수 있으며, 거기에는 많은 수의 잘못된 양성 결과가 포함될 수 있습니다.
CI/CD 변수 | 설명 |
---|---|
COVFUZZ_ADDITIONAL_ARGS
|
gitlab-cov-fuzz 에 전달되는 인수입니다. 기본 퍼징 엔진의 동작을 사용자 정의하는 데 사용됩니다. 기본 퍼징 엔진의 전체 인수 목록은 퍼징 엔진의 문서를 참조하세요.
|
COVFUZZ_BRANCH
| 장기 실행 퍼징 작업을 실행할 브랜치입니다. 다른 모든 브랜치에서는 퍼징 회귀 테스트만 실행됩니다. 기본값: 저장소의 기본 브랜치. |
COVFUZZ_SEED_CORPUS
| 시드 코퍼스 디렉토리의 경로입니다. 기본값: 빈 값. |
COVFUZZ_URL_PREFIX
| 오프라인 환경에서 사용하기 위해 복제된 gitlab-cov-fuzz 저장소의 경로입니다. 오프라인 환경에서만 이 값을 변경해야 합니다. 기본값: https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz/-/raw .
|
COVFUZZ_USE_REGISTRY
| 코퍼스를 GitLab 코퍼스 레지스트리에 저장하도록 설정합니다. 이 변수를 true 로 설정하면 COVFUZZ_CORPUS_NAME 및 COVFUZZ_GITLAB_TOKEN 변수가 필요합니다. 기본값: false .
|
COVFUZZ_CORPUS_NAME
| 작업에서 사용할 코퍼스의 이름입니다. |
COVFUZZ_GITLAB_TOKEN
| API 읽기/쓰기 액세스를 위해 구성된 환경 변수로서 개인 액세스 토큰 또는 프로젝트 액세스 토큰입니다. |
시드 코퍼스
시드 코퍼스의 파일은 수동으로 업데이트해야 합니다. 커버리지 기준 퍼징 테스트 작업에 의해 업데이트되거나 덮어쓰이지 않습니다.
출력
각 퍼징 단계는 다음과 같은 아티팩트를 출력합니다:
-
gl-coverage-fuzzing-report.json
: 커버리지 기준 퍼징 테스트 및 결과에 대한 세부 정보가 포함된 보고서입니다. -
artifacts.zip
: 이 파일에는 두 개의 디렉토리가 포함되어 있습니다:-
corpus
: 현재 및 이전 모든 작업에 의해 생성된 모든 테스트 케이스가 포함됩니다. -
crashes
: 현재 작업에서 발견된 충돌 이벤트 및 이전 작업에서 수정되지 않은 이벤트가 모두 포함됩니다.
-
JSON 보고서 파일은 CI/CD 파이프라인 페이지에서 다운로드할 수 있습니다. 자세한 내용은 아티팩트 다운로드를 참조하세요.
코퍼스 레지스트리
코퍼스 레지스트리는 코퍼스의 라이브러리입니다. 프로젝트 레지스트리에 포함된 코퍼스는 해당 프로젝트의 모든 작업에서 사용할 수 있습니다. 프로젝트 전체 레지스트리는 기본적으로 작업당 하나의 코퍼스만 관리하는 기본 옵션보다 효율적인 방법입니다.
코퍼스 레지스트리는 데이터 무결성을 보장하기 위해 숨겨진 코퍼스를 사용합니다.
코퍼스를 다운로드할 때 파일의 이름은 코퍼스가 처음 업로드될 때 사용된 파일 이름과는 다르지만 artifacts.zip
로 지정됩니다. 이 파일에는 코퍼스만 포함되며, CI/CD 파이프라인에서 다운로드할 수 있는 아티팩트 파일과는 다릅니다. 또한, 리포터 이상의 프로젝트 구성원은 직접 다운로드 링크를 사용하여 코퍼스를 다운로드할 수 있습니다.
코퍼스 레지스트리의 세부 정보 보기
코퍼스 레지스트리의 세부 정보를 보려면:
- 왼쪽 사이드바에서 검색 또는 이동을 선택한 다음 프로젝트를 찾습니다.
- 보안 > 보안 구성을 선택합니다.
- 커버리지 퍼징 섹션에서 코퍼스 관리를 선택합니다.
코퍼스 레지스트리에 코퍼스 만들기
코퍼스 레지스트리에 코퍼스를 만들려면 다음 중 하나를 수행합니다:
- 파이프라인에서 코퍼스 만들기
- 기존 코퍼스 파일 업로드
파이프라인에서 코퍼스 만들기
파이프라인에서 코퍼스를 만들려면:
-
.gitlab-ci.yml
파일에서my_fuzz_target
작업을 편집합니다. - 다음 변수를 설정합니다:
-
COVFUZZ_USE_REGISTRY
를true
로 설정합니다. -
COVFUZZ_CORPUS_NAME
을 코퍼스의 이름으로 설정합니다. -
COVFUZZ_GITLAB_TOKEN
을 개인 액세스 토큰의 값으로 설정합니다.
-
my_fuzz_target
작업이 실행된 후, 코퍼스는 COVFUZZ_CORPUS_NAME
변수에서 제공된 이름으로 코퍼스 레지스트리에 저장됩니다. 코퍼스는 모든 파이프라인 실행 시 업데이트됩니다.
코퍼스 파일 업로드
기존의 코퍼스 파일을 업로드하려면:
- 왼쪽 사이드바에서 검색 또는 이동을 선택한 다음 프로젝트를 찾습니다.
- 보안 > 보안 구성을 선택합니다.
- 커버리지 퍼징 섹션에서 코퍼스 관리를 선택합니다.
- 새 코퍼스를 선택합니다.
- 필드를 완성합니다.
- 파일 업로드를 선택합니다.
- 추가를 선택합니다.
이제 .gitlab-ci.yml
파일에서 코퍼스를 참조할 수 있습니다. COVFUZZ_CORPUS_NAME
변수에 사용된 값이 업로드된 코퍼스 파일 이름과 정확히 일치하는지 확인하세요.
코퍼스 레지스트리에 저장된 코퍼스 사용
코퍼스 레지스트리에 저장된 코퍼스를 사용하려면 해당 코퍼스의 이름으로 참조해야 합니다. 관련 코퍼스의 이름을 확인하려면 코퍼스 레지스트리의 세부 정보를 확인하세요.
전제 조건:
- 프로젝트에서 coverage-guide 퍼즈 테스트를 활성화합니다.
-
.gitlab-ci.yml
파일에서 다음 변수를 설정합니다.-
COVFUZZ_USE_REGISTRY
를true
로 설정합니다. -
COVFUZZ_CORPUS_NAME
을 코퍼스의 이름으로 설정합니다. -
COVFUZZ_GITLAB_TOKEN
을 개인 액세스 토큰의 값으로 설정합니다.
-
커버리지 가이드 퍼즈 테스트 보고서
gl-coverage-fuzzing-report.json
파일 형식에 대한 상세한 정보는 스키마를 읽으세요.
커버리지 가이드 퍼즈 테스트 보고서 예시:
{
"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
## 커버리지 지도된 퍼즈 테스트의 기간
커버리지 지도된 퍼즈 테스트의 가능한 기간은 다음과 같습니다:
- 10분간(기본값): 기본 브랜치에 권장됩니다.
- 60분간: 개발 브랜치 및 병합 요청에 권장됩니다. 더 긴 기간은 더 많은 커버리지를 제공합니다.
`COVFUZZ_ADDITIONAL_ARGS` 변수에 `--regression=true` 값을 설정합니다.
자세한 예시는 [Go 커버리지 지도된 퍼징 예시](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example/-/blob/master/.gitlab-ci.yml)를 참조하십시오.
### 지속적인 커버리지 지도된 퍼징 테스트
주요 파이프라인을 차단하지 않고 커버리지 지도된 퍼징 작업을 더 오래 실행하는 것도 가능합니다. 이 구성은 GitLab [상위-하위 파이프라인](../../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines)을 사용합니다.
이 시나리오에서 제안되는 작업 흐름은 주요 또는 개발 브랜치에서 지속적으로 실행되는 비동기식 퍼징 작업, 그리고 다른 모든 브랜치 및 MR에서 짧은 동기식 퍼징 작업을 가지는 것입니다. 이는 커밋별 파이프라인을 빠르게 완료하는 필요를 균형있게 유지하면서, 퍼저가 애플리케이션을 완전히 탐색하고 테스트할 시간을 충분히 제공합니다. 커버리지 지도된 퍼징 테스트에서 깊은 버그를 찾기 위해 보통 오랜 시간 동안 진행되는 퍼징 작업은 필수적입니다.
이것은 이 작업을 위한 `.gitlab-ci.yml` 파일의 일부입니다. 전체 예시는 [Go 퍼징 예시 저장소](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example/-/tree/continuous_fuzzing)를 참조하십시오.
```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:
COVFUZZ_ADDITIONAL_ARGS: '-max_total_time=3600'
trigger:
include: .covfuzz-ci.yml
rules:
- if: $CI_COMMIT_BRANCH == 'continuous_fuzzing' && $CI_PIPELINE_SOURCE != 'merge_request_event'
이것은 두 개의 작업을 생성합니다:
-
sync_fuzzing
: 차단 구성에서 짧은 기간 동안 모든 퍼징 대상을 실행합니다. 이는 간단한 버그를 찾아내어 MR이 새로운 버그를 도입하거나 이전 버그가 재출현하는지 확인할 수 있도록 합니다. -
async_fuzzing
: 여러분의 브랜치에서 실행되며 주요 작업 주기와 MR을 차단하지 않고 코드의 깊은 버그를 찾아냅니다.
covfuzz-ci.yml
은 원래 동기식 예시와 동일합니다.
FIPS 사용 가능한 이진 파일
GitLab 15.0에서 시작하여, 커버리지 퍼징 이진 파일은 Linux x86에서 golang-fips
로 컴파일되며, 암호화 백엔드로 OpenSSL을 사용합니다. 자세한 내용은 GitLab의 Go를 통한 FIPS 준수를 참조하십시오.
오프라인 환경
오프라인 환경에서 커버리지 퍼징을 사용하려면:
-
오프라인 GitLab 인스턴스에서 액세스할 수 있는 개인 저장소에
gitlab-cov-fuzz
를 복제합니다. -
각 퍼징 단계에 대해
COVFUZZ_URL_PREFIX
를${NEW_URL_GITLAB_COV_FUZ}/-/raw
로 설정하십시오. 여기서NEW_URL_GITLAB_COV_FUZ
는 첫 번째 단계에서 설정한gitlab-cov-fuzz
복제본의 URL입니다.
취약점과 상호 작용
취약점을 찾은 후, 해결할 수 있습니다. 병합 요청 위젯에는 취약점이 나열되어 있으며, 퍼징 아티팩트를 다운로드할 수 있는 버튼이 포함되어 있습니다. 감지된 취약점 중 하나를 선택하여 해당 세부 정보를 확인할 수 있습니다.
그리고 보안 대시보드에서 취약점을 확인할 수 있으며, 여기에서 귀하의 그룹, 프로젝트 및 파이프라인에 있는 모든 보안 취약점에 대한 개요가 표시됩니다.
취약점을 선택하면 취약점에 대한 추가 정보를 제공하는 모달이 열립니다:
- 상태: 취약점의 상태입니다. 커버리지 퍼징 취약점은 감지됨, 확인됨, 기각됨 또는 해결됨과 같은 형태가 될 수 있습니다.
- 프로젝트: 취약점이 존재하는 프로젝트입니다.
- 충돌 유형: 코드의 충돌 또는 약점 유형입니다. 일반적으로 이것은 CWE와 매핑됩니다.
- 충돌 상태: 스택 트레이스의 정규화된 버전으로, 충돌의 마지막 세 함수를 포함하고 있습니다(임의의 주소는 포함되지 않음).
- 스택 트레이스 스니펫: 충돌에 대한 세부 정보를 보여주는 스택 트레이스의 마지막 몇 줄입니다.
- 식별자: 취약점의 식별자입니다. 이것은 CVE 또는 CWE 중 하나에 매핑됩니다.
- 심각도: 취약점의 심각도입니다. 이것은 Critical, High, Medium, Low, Info 또는 Unknown이 될 수 있습니다.
- 스캐너: 취약점을 감지한 스캐너입니다(예: 커버리지 퍼징).
- 스캐너 제공자: 스캔을 수행한 엔진입니다. 커버리지 퍼징의 경우 지원되는 퍼징 엔진 및 언어에 나열된 엔진 중 하나일 수 있습니다.
문제 해결
오류 Unable to extract corpus folder from artifacts zip file
이 오류 메시지가 표시되고 COVFUZZ_USE_REGISTRY
가 true
로 설정되어 있는 경우, 업로드된 코퍼스 파일이 corpus
라는 이름의 폴더로 추출되도록 확인하십시오.
오류 400 Bad request - Duplicate package is not allowed
퍼징 작업을 COVFUZZ_USE_REGISTRY
를 true
로 설정하여 실행할 때 이 오류 메시지가 표시되면, 중복이 허용되도록 설정되어 있는지 확인하십시오. 더 자세한 내용은 중복 제네릭 패키지를 참조하십시오.