
보안 지향 Go 툴체인으로, 최첨단 퍼징 기능에 중점을 둡니다.
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) { ... })를 실행하세요.X + Y - Z는 X / U + Z - 14가 될 수 있지만 X + Yè - Z는 되지 않습니다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 / libaflAppendValuelibaflUnmarshalArgs / libaflDecodeValue인코딩 규칙(높은 수준):
bool: 1바이트 (0 또는 1)int/uint는 8바이트)float32 = 4바이트, float64 = 8바이트)string: uvarint(len) 다음에 원시 문자열 바이트[]byte: uvarint(len) 다음에 원시 바이트uvarint(len) 다음에 각 요소 인코딩0 = nil, 1 = 존재함) 다음에 포인팅하는 값 인코딩이 작업은 이전에 개발된 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/)은 건너뜁니다.
이에 대한 관련 블로그 게시물은 여기에서 읽을 수 있습니다.
특정 보고를 억제하려면 연산과 같은 줄이나 바로 위 줄에 마커를 추가하세요:
overflow_false_positivetruncation_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가 호출될 때 패닉이 발생합니다(쉼표로 구분된 목록).