커버리지 지도 지도된 퍼즈 테스트 (ULTIMATE)

Tier: Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

커버리지 지도 지도된 퍼즈 테스트는 애플리케이션의 이상 동작을 유발하기 위해 계기화된 버전의 응용 프로그램에 무작위 입력을 보냅니다. 이러한 동작은 해결해야 할 버그를 나타냅니다. GitLab을 사용하면 파이프라인에 커버리지 지도 지도된 퍼즈 테스트를 추가할 수 있습니다. 이를 통해 다른 QA 프로세스에서 놓칠 수 있는 버그 및 잠재적 보안 문제를 발견할 수 있습니다.

GitLab Secure의 다른 보안 스캐너 및 사용자의 테스트 프로세스 외에 퍼즈 테스팅을 사용하는 것을 권장합니다. GitLab CI/CD를 사용하는 경우 CI/CD 워크플로우의 일부로 커버리지 지도 지도된 퍼즈 테스트를 실행할 수 있습니다.

개요는 Coverage Fuzzing를 참조하세요.

커버리지 지도 지도된 퍼즈 테스트 프로세스

퍼즈 테스트 프로세스는 다음과 같습니다:

  1. 대상 응용프로그램을 컴파일합니다.
  2. gitlab-cov-fuzz 도구를 사용하여 계기화된 애플리케이션을 실행합니다.
  3. 퍼저가 출력한 예외 정보를 구문 분석하고 분석합니다.
  4. 이전 파이프라인 또는 COVFUZZ_USE_REGISTRYtrue로 설정된 경우 코퍼스를 다운로드합니다.
  5. 이전 파이프라인에서 충돌 이벤트를 다운로드합니다.
  6. 구문 분석된 충돌 이벤트 및 데이터를 gl-coverage-fuzzing-report.json 파일에 출력합니다.
  7. 이를 작업 파이프라인 또는 COVFUZZ_USE_REGISTRYtrue로 설정된 경우 코퍼스 레지스트리에 업데이트합니다.

커버리지 지도 지도된 퍼즈 테스트의 결과는 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 (recommended) javafuzz-fuzzing-example
Java JQF (not preferred) jqf-fuzzing-example
JavaScript jsfuzz jsfuzz-fuzzing-example
Python pythonfuzz pythonfuzz-fuzzing-example
AFL (AFL에서 작동하는 모든 언어) AFL afl-fuzzing-example
  1. Gradle 지원은 issue 409764에서 계획 중입니다.

Coverage-guided fuzz testing 상태 확인

Coverage-guided fuzz testing 상태를 확인하려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. 보안 > 보안 구성을 선택합니다.
  3. Coverage Fuzzing 섹션에서 상태는 다음과 같습니다:
    • 구성되지 않음
    • 활성화됨
    • GitLab Ultimate로 업그레이드하기 위한 프롬프트.

Coverage-guided fuzz testing 활성화

Coverage-guided fuzz testing을 활성화하려면 .gitlab-ci.yml을 편집하세요:

  1. fuzz 단계를 단계 목록에 추가합니다.

  2. 애플리케이션이 Go로 작성되지 않은 경우 일치하는 퍼징(튀김) 엔진을 사용하는 Docker 이미지를 제공합니다. 예:

    image: python:latest
    
  3. GitLab 설치의 일부로 제공되는 Coverage-Fuzzing.gitlab-ci.yml 템플릿포함시킵니다.

  4. 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 파이프라인에서 coverage-guided fuzz testing을 구성하기 위해 다음 변수를 사용하세요.

경고: 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로 설정하세요. 이 변수를 true로 설정하는 경우 COVFUZZ_CORPUS_NAMECOVFUZZ_GITLAB_TOKEN 변수가 필요합니다. 기본값: false. GitLab 14.8에서 도입됨.
COVFUZZ_CORPUS_NAME 작업에서 사용되는 코퍼스의 이름. GitLab 14.8에서 도입됨.
COVFUZZ_GITLAB_TOKEN 개인 액세스 토큰 또는 프로젝트 액세스 토큰으로 구성된 환경 변수로 API 읽기/쓰기 액세스가 설정됩니다. GitLab 14.8에서 도입됨.

시드 코퍼스

시드 코퍼스(files in the seed corpus)는 수동으로 업데이트해야 합니다. coverage-guide 퍼즈 테스트 작업에 의해 업데이트되거나 덮어씌워지지 않습니다.

결과

각 퍼징 단계는 다음 산출물을 내놓습니다:

  • gl-coverage-fuzzing-report.json: 커버리지 유도 퍼즈 테스트와 그 결과에 대한 세부 정보를 담은 보고서.
  • artifacts.zip: 이 파일에는 두 개의 디렉토리가 포함되어 있습니다:
    • corpus: 현재 및 이전 작업에서 생성된 모든 테스트 케이스를 포함합니다.
    • crashes: 현재 작업에서 발견된 모든 충돌 이벤트 및 이전 작업에서 수정되지 않은 충돌 이벤트를 포함합니다.

JSON 보고서 파일은 CI/CD 파이프라인 페이지에서 다운로드할 수 있습니다. 자세한 정보는 산출물 다운로드를 참조하세요.

코퍼스 레지스트리

코퍼스 레지스트리는 코퍼스의 라이브러리입니다. 프로젝트의 레지스트리에 있는 코퍼스는 해당 프로젝트의 모든 작업에서 사용할 수 있습니다. 프로젝트 전역 레지스트리는 각 작업당 하나의 코퍼스를 관리하는 기본 옵션보다 더 효율적인 방법입니다.

코퍼스 레지스트리는 프로젝트의 코퍼스를 저장하기 위해 패키지 레지스트리를 사용합니다. 레지스트리에 저장된 코퍼스는 데이터 무결성을 보장하기 위해 숨겨져 있습니다.

코퍼스를 다운로드하면 해당 파일은 초기 업로드될 때의 파일 이름과 관계없이 artifacts.zip로 명명됩니다. 이 파일은 CI/CD 파이프라인에서 다운로드할 수 있는 산출물 파일과 다릅니다. 또한, 리포터 이상의 프로젝트 멤버는 직접 다운로드 링크를 사용하여 코퍼스를 다운로드할 수 있습니다.

코퍼스 레지스트리의 세부 정보 보기

코퍼스 레지스트리의 세부 정보를 보려면 다음 단계를 수행합니다:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. Secure > Security configuration을 선택합니다.
  3. Coverage Fuzzing 섹션에서 Manage corpus를 선택합니다.

코퍼스 레지스트리에 코퍼스 생성

코퍼스 레지스트리에 코퍼스를 생성하려면 다음 중 하나를 수행합니다:

  • 파이프라인에서 코퍼스 생성
  • 기존 코퍼스 파일 업로드

파이프라인에서 코퍼스 생성

파이프라인에서 코퍼스를 생성하려면:

  1. .gitlab-ci.yml 파일에서 my_fuzz_target 작업을 편집합니다.
  2. 다음 변수를 설정합니다:
    • COVFUZZ_USE_REGISTRYtrue로 설정합니다.
    • COVFUZZ_CORPUS_NAME을 코퍼스의 이름으로 설정합니다.
    • COVFUZZ_GITLAB_TOKEN을 개인 액세스 토큰의 값으로 설정합니다.

my_fuzz_target 작업이 실행되면 COVFUZZ_CORPUS_NAME 변수에서 제공된 이름으로 코퍼스가 코퍼스 레지스트리에 저장됩니다. 코퍼스는 모든 파이프라인 실행 시에 업데이트됩니다.

기존 코퍼스 파일 업로드

기존 코퍼스 파일을 업로드하려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. Secure > Security configuration을 선택합니다.
  3. Coverage Fuzzing 섹션에서 Manage corpus를 선택합니다.
  4. New corpus를 선택합니다.
  5. 필드를 입력합니다.
  6. Upload file을 선택합니다.
  7. Add을 선택합니다.

이제 .gitlab-ci.yml 파일에서 코퍼스를 참조할 수 있습니다. COVFUZZ_CORPUS_NAME 변수에 업로드된 코퍼스 파일의 이름과 정확히 일치해야 합니다.

코퍼스 레지스트리에 저장된 코퍼스 사용

코퍼스 레지스트리에 저장된 코퍼스를 사용하려면 해당 이름으로 코퍼스를 참조해야 합니다. 관련 코퍼스의 이름을 확인하려면 코퍼스 레지스트리의 세부 정보를 확인하세요.

전제 조건:

  1. .gitlab-ci.yml 파일에서 다음 변수를 설정합니다:
    • COVFUZZ_USE_REGISTRYtrue로 설정합니다.
    • 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": "..."
      ...
    }
  ]
}

커버리지 지도된 퍼즈 테스트의 기간

커버리지 지도된 퍼즈 테스트의 가능한 기간은 다음과 같습니다:

  • 10분 동안(기본값): 기본 브랜치에 권장됩니다.
  • 60분 동안: 개발 브랜치 및 병합 요청에 권장됩니다. 더 긴 기간은 더 많은 커버리지를 제공합니다. COVFUZZ_ADDITIONAL_ARGS 변수에서 값을 --regression=true로 설정하세요.

완전한 예제는 Go 커버리지 지도된 퍼징 예제를 참조하세요.

지속적인 커버리지 지도된 퍼징 테스트

주요 파이프라인을 차단하지 않고도 커버리지 지도된 퍼징 작업을 길게 실행하는 것이 가능합니다. 이 구성은 GitLab의 상위-하위 파이프라인을 사용합니다.

이 시나리오에서 권장되는 워크플로우는 기본 또는 개발 브랜치에서 오랫동안 비동기식 퍼징 작업을 수행하고, 다른 모든 브랜치와 MR에서는 짧은 동기식 퍼징 작업을 완료하는 것입니다. 이로써 커밋당 파이프라인이 빠르게 완료될 수 있도록 동시에, 퍼저가 애플리케이션을 완전히 탐색하고 테스트할 수 있는 많은 시간을 제공합니다. 커버리지 지도된 퍼징 퍼저가 코드베이스에서 더 깊은 버그를 찾는 데는 오랜 실행 시간이 필요합니다.

다음은 이 워크플로우에 대한 .gitlab-ci.yml 파일의 일부입니다. 전체 예제는 Go 퍼징 예제의 저장소를 참조하세요.

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'

이렇게 두 개의 작업이 생성됩니다:

  1. sync_fuzzing: 블로킹 구성에서 짧은 시간 동안 모든 퍼징 대상을 실행합니다. 이로써 단순한 버그를 찾는 동시에, MR이 새로운 버그를 도입하거나 이전 버그를 재현하지 않는지 확인할 수 있습니다.
  2. async_fuzzing: 브랜치에서 실행되며, 개발 주기와 MR을 차단하지 않고 코드의 심층적인 버그를 찾습니다.

covfuzz-ci.yml원래 동기식 예제와 동일합니다.

FIPS 활성화된 이진 파일

GitLab 15.0에서 시작하여 리눅스 x86에서 커버리지 퍼징 바이너리는 golang-fips로 컴파일되며, 암호화 백엔드로 OpenSSL을 사용합니다. 자세한 내용은 Go에서 GitLab의 FIPS 준수를 참조하세요.

오프라인 환경

오프라인 환경에서 커버리지 퍼징을 사용하려면 다음을 수행하세요:

  1. 오프라인 GitLab 인스턴스에서 액세스할 수 있는 개인 저장소에 gitlab-cov-fuzz를 복제하세요.

  2. 각 퍼징 단계에 대해 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일 수 있습니다.
  • 스캐너: 취약점을 감지한 스캐너(예: 커버리지 퍼징).
  • 스캐너 제공자: 스캔을 수행한 엔진. 커버리지 퍼징의 경우, 지원되는 퍼징 엔진 및 언어에 나열된 엔진 중 하나가 될 수 있습니다.

Fuzz 엔진과 언어를 지원하는 fuzz 엔진에 대해서는 Supported fuzzing engines and languages를 참조하세요.

문제 해결

오류 Unable to extract corpus folder from artifacts zip file (아티팩트 zip 파일에서 코퍼스 폴더를 추출할 수 없음)

만약 이 오류 메시지를 보게 된다면, 그리고 COVFUZZ_USE_REGISTRYtrue로 설정되어 있다면, 업로드한 코퍼스 파일이 corpus라는 이름의 폴더로 추출되도록 확인하세요.

오류 400 Bad request - Duplicate package is not allowed (400 잘못된 요청 - 중복 패키지 허용되지 않음)

만약 이 오류 메시지를 보게 된다면, COVFUZZ_USE_REGISTRYtrue로 설정된 상태에서 퍼징 작업을 실행할 때, 중복이 허용되도록 확인하세요. 더 많은 세부사항은 중복 제네릭 패키지를 참조하세요.