
Toolchain de Go orientado a la seguridad, centrado en capacidades de fuzzing de última generación.
gosentry es un fork centrado en la seguridad de la cadena de herramientas de Go, que integra numerosas funciones para campañas de fuzzing de vanguardia en bases de código Go. Si antes usabas go test -fuzz, deberías usar gosentry como reemplazo.
Incluye varias mejoras de fuzzing y detectores de errores que no están presentes de forma nativa en la cadena de herramientas de Go. Consulta el TLDR; a continuación. También puedes leer el artículo de blog asociado aquí.
TLDR (funcionalidades y opciones):
struct directamente (sin necesidad de un parser personalizado). Añadir semillas con f.Add(Input{N: 7, S: "hi"}) y luego f.Fuzz(func(t *testing.T, in Input) { ... }).X + Y - Z puede convertirse en X / U + Z - 14 en lugar de X + Yè - Zcd src && ./make.bash # Produces ../bin/go. See GOFLAGS below.
> [!TIP]
> Documentación para contribuidores: lee `docs/gosentry/index.md` para ver un mapa del código, el bucle de desarrollo recomendado, los puntos de entrada de CI y los scripts de benchmark.
> Este fork utiliza la Pull GitHub App para abrir y fusionar automáticamente los PR desde `golang/go:master` hacia `master`, asegurando que nunca nos quedemos atrás de las últimas actualizaciones de la cadena de herramientas de Go.
## Característica 1: Fuzzing consciente de structs (fuzzing de structs como entradas)
#### Resumen
El fuzzing nativo de Go (`go test -fuzz=...`) solo admite un pequeño conjunto de tipos escalares como parámetros de fuzzing (`[]byte`, `string`, números, ...). En gosentry, también puedes someter a fuzzing **tipos compuestos** construidos a partir de esos escalares: structs, arrays, slices y punteros.
Esto es útil cuando tu código acepta de forma natural entradas estructuradas y no quieres construir un codificador/decodificador personalizado solo para sembrar y mutar el corpus.
Consulta `test/gosentry/examples/multiargs` y `test/gosentry/examples/composite` para ver ejemplos.
#### Ejemplo simple```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) y el fuzzing de structs (el pegamento creado)El fuzzer nativo de Go no puede fuzzear un valor struct directamente (solo sabe mutar una pequeña lista de tipos escalares). gosentry añade una pequeña capa de pegamento: cuando tu objetivo de fuzzing usa tipos compuestos (como Input), gosentry fuzzea un único []byte entre bastidores. En cada ejecución, decodifica esos bytes en tu struct (campo por campo, recursivamente para slices/arrays/punteros) y luego llama a tu callback f.Fuzz con el valor decodificado. La misma codificación se usa para las semillas, por lo que f.Add(Input{...}) se convierte en una entrada de corpus []byte codificada que el fuzzer puede reutilizar y mutar como cualquier otra semilla.
Los fuzzers (incluido LibAFL) mutan bytes crudos, por lo que queremos un decodificador que pueda convertir cualquier slice de bytes en "algún" valor de struct y seguir adelante. JSON/gob rechazarían la mayoría de las entradas aleatorias (malo para la cobertura), y además no pueblan campos no exportados, mientras que el fuzzing a menudo se beneficia de romper invariantes. Este formato personalizado es pequeño, rápido, determinista y tolerante a datos malformados.
Bajo el capó, esto usa el propio formato binario simple de gosentry (ni gob, ni JSON). El código vive en src/testing/libafl.go:
libaflMarshalInputs / libaflAppendValuelibaflUnmarshalArgs / libaflDecodeValueReglas de codificación (alto nivel):
bool: 1 byte (0 o 1)int/uint son 8 bytes)float32 = 4 bytes, float64 = 8 bytes)string: uvarint(len) y luego bytes crudos de la cadena[]byte: uvarint(len) y luego bytes crudosuvarint(len) y luego cada elemento codificado0 = nil, 1 = presente) y luego el valor apuntadoEste trabajo está inspirado en el go-panikint desarrollado anteriormente. Añade detección de desbordamiento/subdesbordamiento para operaciones aritméticas con enteros y (opcionalmente) detección de truncamiento de tipos para conversiones de enteros. Cuando se detecta un desbordamiento o truncamiento, se lanza un panic con un mensaje de error detallado, incluyendo el tipo de operación específico y los tipos de enteros implicados.
Operaciones aritméticas: Gestiona la suma +, la resta -, la multiplicación * y la división / para tipos de enteros tanto con signo como sin signo. Para enteros con signo, cubre int8, int16, int32. Para enteros sin signo, cubre uint8, uint16, uint32, uint64. El caso de la división detecta específicamente la condición de desbordamiento MIN_INT / -1 para enteros con signo. int64 y uintptr no se comprueban para operaciones aritméticas.