
Toolchain Go orientata alla sicurezza, focalizzata su capacità di fuzzing all'avanguardia.
gosentry è un fork della toolchain Go incentrato sulla sicurezza, che integra numerose funzionalità per campagne di fuzzing all'avanguardia su codebase Go. Se prima usavi go test -fuzz, dovresti usare gosentry come sostituto.
Include vari miglioramenti per il fuzzing e rilevatori di bug che non sono presenti nativamente nella toolchain Go. Vedi TLDR; qui sotto. Puoi anche leggere l'articolo del blog associato qui.
TLDR (funzionalità e opzioni):
struct (nessun parser personalizzato necessario). Aggiungi seed con f.Add(Input{N: 7, S: "hi"}) e poi f.Fuzz(func(t *testing.T, in Input) { ... }).X + Y - Z può diventare X / U + Z - 14 invece di X + Yè - Zcd src && ./make.bash # Produces ../bin/go. See GOFLAGS below.
> [!TIP]
> Documentazione per contributori: leggi `docs/gosentry/index.md` per una mappa del codice, il ciclo di sviluppo consigliato, i punti di ingresso della CI e gli script di benchmark.
> Questo fork utilizza la Pull GitHub App per aprire e unire automaticamente le PR da `golang/go:master` in `master`, assicurandoci di non rimanere mai indietro rispetto agli ultimi aggiornamenti della toolchain Go.
## Funzionalità 1: Fuzzing consapevole delle struct (fuzz di struct come input)
#### Panoramica
Il fuzzing nativo di Go (`go test -fuzz=...`) supporta solo un piccolo insieme di tipi scalari come parametri di fuzz (`[]byte`, `string`, numeri, ...). In gosentry, puoi anche fare fuzz di **tipi compositi** costruiti da quegli scalari: struct, array, slice e puntatori.
Questo è utile quando il tuo codice accetta naturalmente input strutturati e non vuoi costruire un encoder/decoder personalizzato solo per inizializzare e mutare il corpus.
Vedi `test/gosentry/examples/multiargs` e `test/gosentry/examples/composite` per esempi.
#### Esempio semplice```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) e il fuzzing delle struct (la colla creata)Il fuzzer nativo di Go non può fare fuzzing direttamente su un valore struct (sa solo mutare una piccola lista di tipi scalari). gosentry aggiunge un piccolo strato di colla: quando il tuo fuzz target usa tipi compositi (come Input), gosentry esegue il fuzzing su un singolo []byte dietro le quinte. A ogni esecuzione, decodifica quei byte nella tua struct (campo per campo, ricorsivamente per slice/array/puntatori) e poi chiama la callback f.Fuzz con il valore decodificato. La stessa codifica viene usata per i seed, quindi f.Add(Input{...}) diventa una voce di corpus []byte codificata che il fuzzer può riutilizzare e mutare come qualsiasi altro seed.
I fuzzer (incluso LibAFL) mutano byte grezzi, quindi vogliamo un decoder che possa trasformare qualsiasi slice di byte in un valore di struct "qualsiasi" e continuare. JSON/gob rifiuterebbero la maggior parte degli input casuali (male per la copertura), e inoltre non popolano i campi non esportati, mentre il fuzzing trae spesso beneficio dalla rottura degli invarianti. Questo formato personalizzato è piccolo, veloce, deterministico e tollerante ai dati malformati.
Dietro le quinte, usa il semplice formato binario di gosentry (non gob, non JSON). Il codice si trova in src/testing/libafl.go:
libaflMarshalInputs / libaflAppendValuelibaflUnmarshalArgs / libaflDecodeValueRegole di codifica (a livello generale):
bool: 1 byte (0 o 1)int/uint sono 8 byte)float32 = 4 byte, float64 = 8 byte)string: uvarint(len) poi byte grezzi della stringa[]byte: uvarint(len) poi byte grezziuvarint(len) poi ogni elemento codificato0 = nil, 1 = presente) poi il valore puntatoQuesto lavoro trae ispirazione dal go-panikint sviluppato in precedenza. Aggiunge il rilevamento di overflow/underflow per le operazioni aritmetiche sugli interi e (opzionalmente) il rilevamento del troncamento di tipo per le conversioni tra interi. Quando viene rilevato overflow o troncamento, viene generato un panic con un messaggio di errore dettagliato, che include il tipo di operazione specifico e i tipi di interi coinvolti.
Operazioni aritmetiche: Gestisce addizione +, sottrazione -, moltiplicazione * e divisione / sia per i tipi interi con segno che senza segno. Per gli interi con segno, copre int8, int16, int32. Per gli interi senza segno, copre uint8, uint16, uint32, uint64. Il caso della divisione rileva specificamente la condizione di overflow MIN_INT / -1 per gli interi con segno. int64 e uintptr non sono controllati per le operazioni aritmetiche.
Rilevamento del troncamento di tipo: Rileva conversioni tra tipi interi potenzialmente con perdita di dati. Copre tutti i tipi interi: int8, int16, int32, int64, uint8, uint16, uint32, uint64. Esclude uintptr a causa dell'uso dipendente dalla piattaforma. Questa funzione è disabilitata per impostazione predefinita.