업데이트로 돌아가기
New releaseAug 26, 2026

gosentry v0.4.1

보안 지향 Go 툴체인으로, 최첨단 퍼징 기능에 중점을 둡니다.

공유

gosentry

integration tests

gosentry는 Go 코드베이스에 대한 최첨단 퍼징 캠페인을 위해 다양한 기능을 통합한 보안 중심의 Go 툴체인 포크입니다. 이전에 go test -fuzz를 사용하고 있었다면 gosentry를 대체 도구로 사용해야 합니다. 여기에는 Go 툴체인에 기본적으로 없는 다양한 퍼징 개선 사항과 버그 탐지 기능이 포함되어 있습니다. 아래 TLDR;을 참조하세요. 관련 블로그 기사는 여기에서 읽을 수 있습니다.

TLDR (기능 및 옵션):

  • struct 입력을 직접 퍼징합니다 (사용자 정의 파서 불필요). f.Add(Input{N: 7, S: "hi"})로 시드를 추가한 다음 f.Fuzz(func(t *testing.T, in Input) { ... })를 실행하세요.
  • 정수 오버플로우 발생 시 패닉을 일으키고 산술 문제를 탐지합니다
  • 경로 제약 해결과 같은 최첨단 퍼징 기법을 위해 LibAFL로 퍼징합니다
  • 문법에서 입력을 생성/변이시켜 무의미한 변이를 방지합니다. 변이는 유효한 수학 연산을 생성합니다. 예: X + Y - Z는 X / U + Z - 14가 될 수 있지만 X + Yè - Z는 되지 않습니다
  • 선택된 함수(예: 치명적 오류 로거)에서 패닉을 일으키고 호출 시 크래시합니다
  • 최근 변경된 라인과 새로운 커버리지에 퍼저를 집중시켜 주로 새 커밋을 대상으로 합니다
  • 퍼징 시점에 데이터 레이스를 포착합니다
  • 퍼징 시점에 Go 누수(leak)를 포착합니다
  • 퍼징 시점에 타임아웃으로 중단된 실행을 포착합니다
  • 단일 CLI로 퍼징 캠페인 코퍼스에서 HTML 커버리지 보고서를 생성합니다

목차

빌드```bash

cd src && ./make.bash # Produces ../bin/go. See GOFLAGS below.

> [!TIP]
> 기여자 문서:  `docs/gosentry/index.md`를 읽고 코드 맵, 권장 개발 루프, CI 진입점 및 벤치마크 스크립트를 확인하세요.
> 이 포크는 Pull GitHub App을 사용하여 `golang/go:master`에서 `master`로 PR을 열고 자동 병합하므로 Go 툴체인 최신 업데이트에서 뒤처지지 않습니다.

## 기능 1: 구조체 인식 퍼징 (구조체를 입력으로 퍼징)

#### 개요

Go의 기본 퍼징(`go test -fuzz=...`)은 퍼징 매개변수로 소수의 스칼라 타입(`[]byte`, `string`, 숫자, ...)만 지원합니다. gosentry에서는 이러한 스칼라로 구성된 **복합 타입**(구조체, 배열, 슬라이스, 포인터)도 퍼징할 수 있습니다.
이 기능은 코드가 자연스럽게 구조화된 입력을 받고, 코퍼스를 시드하고 변형하기 위해 맞춤형 인코더/디코더를 만들고 싶지 않을 때 유용합니다.
예시는 `test/gosentry/examples/multiargs`와 `test/gosentry/examples/composite`를 참조하세요.

#### 간단한 예제```go
type Input struct {
	Data []byte
	S    string
	N    int
	OK   bool
}

func FuzzStructInput(f *testing.F) {
	// Seed the initial corpus with a Go struct (gosentry feature).
	f.Add(Input{Data: []byte("A"), S: "B", N: 7, OK: true})

	f.Fuzz(func(t *testing.T, in Input) {
		if in.OK && in.N == 1337 && in.S == "BOOMMOOB" && bytes.Equal(in.Data, []byte("A")) {
			t.Fatalf("boom")
		}
	})
}
구조체 시드(f.Add) 및 구조체 퍼징이 작동하는 방식 (만들어진 접착 계층)

Go의 기본 퍼저는 struct 값을 직접 퍼징할 수 없습니다(소수의 스칼라 타입 목록만 변형할 수 있음). gosentry는 작은 접착 계층을 추가합니다: 퍼즈 타겟이 (Input 같은) 복합 타입을 사용할 때, gosentry는 내부적으로 단일 []byte를 퍼징합니다. 매 실행마다 그 바이트를 구조체로 디코딩하고(필드 단위로, 슬라이스/배열/포인터에 대해 재귀적으로), 그런 다음 디코딩된 값으로 f.Fuzz 콜백을 호출합니다. 시드에도 동일한 인코딩이 사용되므로 f.Add(Input{...})는 인코딩된 []byte 코퍼스 항목이 되어 퍼저가 다른 시드처럼 재사용하고 변형할 수 있습니다.

퍼저(LibAFL 포함)는 원시 바이트를 변형하므로, 어떤 바이트 슬라이스든 "어떤" 구조체 값으로 바꾸고 계속 진행할 수 있는 디코더가 필요합니다. JSON/gob는 대부분의 임의 입력을 거부하고(커버리지에 나쁨), 내보내지지 않은(unexported) 필드도 채우지 않으며, 퍼징은 종종 불변식을 깨뜨리는 데서 이점을 얻습니다. 이 사용자 정의 형식은 작고, 빠르고, 결정적이며, 잘못된 데이터에 관대합니다.

내부적으로 이는 gosentry 자체의 단순 바이너리 형식(gob도 JSON도 아님)을 사용합니다. 코드는 src/testing/libafl.go에 있습니다:

  • 인코딩: libaflMarshalInputs / libaflAppendValue
  • 디코딩: libaflUnmarshalArgs / libaflDecodeValue

인코딩 규칙(높은 수준):

  • bool: 1바이트 (0 또는 1)
  • 정수: 리틀엔디언 바이트 (int/uint는 8바이트)
  • 부동소수점: 리틀엔디언 IEEE-754 비트 (float32 = 4바이트, float64 = 8바이트)
  • string: uvarint(len) 다음에 원시 문자열 바이트
  • []byte: uvarint(len) 다음에 원시 바이트
  • 기타 슬라이스: uvarint(len) 다음에 각 요소 인코딩
  • 구조체: 선언 순서대로 필드 인코딩
  • 포인터: 1바이트 (0 = nil, 1 = 존재함) 다음에 포인팅하는 값 인코딩

기능 2: 정수 오버플로 및 절단(truncation) 문제 탐지

개요

이 작업은 이전에 개발된 go-panikint에서 영감을 받았습니다. 정수 산술 연산에 대한 오버플로/언더플로 탐지와 (선택적으로) 정수 변환에 대한 타입 절단 탐지를 추가합니다. 오버플로나 절단이 감지되면 관련된 특정 연산 유형과 정수 타입을 포함한 상세한 오류 메시지와 함께 패닉이 발생합니다.

산술 연산: 부호 있는 정수와 부호 없는 정수 타입 모두에 대해 덧셈 +, 뺄셈 -, 곱셈 *, 나눗셈 /을 처리합니다. 부호 있는 정수는 int8, int16, int32를 다룹니다. 부호 없는 정수는 uint8, uint16, uint32, uint64를 다룹니다. 나눗셈의 경우 부호 있는 정수에 대한 MIN_INT / -1 오버플로 조건을 특별히 감지합니다. int64와 uintptr은 산술 연산에 대해 검사하지 않습니다.

타입 절단 탐지: 데이터 손실이 발생할 수 있는 정수 타입 변환을 감지합니다. 모든 정수 타입을 다룹니다: int8, int16, int32, int64, uint8, uint16, uint32, uint64. 플랫폼 의존적 사용으로 인해 uintptr은 제외합니다. 이 기능은 기본적으로 비활성화되어 있습니다.

오버플로 탐지는 기본적으로 활성화되어 있습니다. 비활성화하려면 ./make.bash 앞에 GOFLAGS='-gcflags=-overflowdetect=false'를 추가하세요. 절단 문제 검사기도 다음과 같이 활성화할 수 있습니다: -gcflags=-truncationdetect=true

작동 방식

이 기능은 컴파일러 SSA 생성을 패치하여 정수 산술 연산과 정수 변환에 추가 런타임 검사를 삽입합니다. 이 검사는 런타임을 호출하여 버그가 감지되면 상세한 오류 메시지와 함께 패닉을 발생시킵니다. 검사는 소스 위치 기반 필터링을 사용하여 적용되므로 사용자 코드는 계측되지만 표준 라이브러리 파일과 의존성(모듈 캐시 및 vendor/)은 건너뜁니다.

이에 대한 관련 블로그 게시물은 여기에서 읽을 수 있습니다.

오탐(false positive) 억제

특정 보고를 억제하려면 연산과 같은 줄이나 바로 위 줄에 마커를 추가하세요:

  • 오버플로/언더플로: overflow_false_positive
  • 절단: truncation_false_positive

예시:```go // overflow_false_positive intentionalOverflow := a + b // truncation_false_positive x := uint8(big) sum2 := a + b // overflow_false_positive x2 := uint8(big) // truncation_false_positive

때로는 이것이 작동하지 않을 수 있는데, 그 이유는 Go가 함수를 인라인 처리하기 때문입니다. `// overflow_false_positive`만으로 충분하지 않다면 함수 시그니처 앞에 `//go:noinline`을 추가하세요.

## 기능 3: 선택된 함수에서 패닉 발생

퍼징 대상에서 특정 함수가 호출될 때 패닉을 유발하는 것에 관심이 있을 수 있습니다. 예를 들어, 일부 소프트웨어는 패닉을 일으키는 대신 `log.error` 메시지를 출력할 수 있는데, 이러한 조건은 종종 보안 연구자들이 퍼징 중에 탐지하고자 하는 상태를 나타냅니다.
그러나 이러한 오류는 일반적으로 내부적으로 처리되므로(예: 재시도 또는 일시 중지 메커니즘을 통해, 또는 로그에 메시지를 출력하여) 퍼저가 거의 인식하지 못합니다. 이 기능의 목적은 이 문제를 해결하는 것입니다.

#### 사용 방법

gosentry를 컴파일한 후 `--panic-on` 플래그를 사용하세요.```bash
./bin/go test -fuzz=FuzzHarness --use-libafl --focus-on-new-code=false --catch-races=false --catch-leaks=false --panic-on="test_go_panicon.(*Logger).Warning,test_go_panicon.(*Logger).Error"

위 예제는 (*Logger).Warning 또는 (*Logger).Error가 호출될 때 패닉이 발생합니다(쉼표로 구분된 목록).

선택한 함수에서 패닉이 발생하는 기능의 작동 방식```text ┌───────────────────────────────────────────────────────────────────────────┐ │ 1) gosentry `go test` │ │ - parses + validates `-panic-on=...` against packages being built │ │ - forwards patterns to the compiler via `-panic-on-call=...` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) `cmd/compile` │ │ - prevents inlining of matching calls so the call stays visible │ │ - SSA pass inserts a call to `runtime.panicOnCall(...)` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) `runtime.panicOnCall` │ │ - panics with: "panic-on-call: func-name" │ └───────────────────────────────────────────────────────────────────────────┘ ``` In practice, this makes any matched call site behave like a crash/panic for fuzzers (note: only static call sites can be trapped).
```

카테고리