Ir al contenido

Snapchange - Fuzzing basado en snapshot con KVM

Snapchange - Fuzzing basado en snapshot con KVM

Snapchange (por AWS) es un framework Rust para fuzzing basado en snapshot. Los fuzzers tradicionales reinician el objetivo para cada entrada, lo cual es fatalmente lento cuando el código interesante se sienta detrás de setup costoso — un handshake de red, un login, un config parseado, una base de datos cargada. Snapchange en su lugar toma un snapshot de memoria del objetivo exactamente en el momento de interés, luego restaura ese estado y muta desde allí usando KVM, logrando tasas de iteración muy altas contra código que el fuzzing convencional lucha por alcanzar.

El fuzzing de snapshot requiere KVM y root. Ejecuta en un entorno aislado.

Requisitos

RequisitoNota
Linux con KVM/dev/kvm accesible
Toolchain RustSnapchange es una librería Rust
QEMUUsado para tomar el snapshot
RootPara KVM y acceso a memoria

El modelo

FaseQué sucede
1. SnapshotEjecutar el objetivo en QEMU hasta el punto de interés, volcar memoria + registros
2. HarnessEscribir un fuzzer Rust describiendo dónde entra la entrada y cuándo parar
3. FuzzSnapchange restaura el snapshot por iteración y muta la entrada
4. TriageLos crashes se registran con el estado exacto de registro/memoria

La insight crítica: todo el costo de setup se paga una vez, en el snapshot. Cada iteración subsecuente comienza desde ese estado en microsegundos.

Tomando un snapshot

# Conceptual: ejecutar el objetivo bajo QEMU, romper en la función de interés,
# luego volcar memoria física y estado de registro
./snapchange/qemu_snapshot/take_snapshot.sh --target ./my-server
ArtefactoContiene
fuzzvm.physmemMemoria física del guest completa
fuzzvm.qemuregsEstado del registro CPU
*.symbolsTabla de símbolos para cobertura/breakpoints
vmlinux / binarioPara simbolización

Escribiendo un fuzzer

// Forma conceptual — ver ejemplos de Snapchange para código completo
impl Fuzzer for MyFuzzer {
    type Input = Vec<u8>;
    const START_ADDRESS: u64 = 0x555555555000;
    const MAX_INPUT_LENGTH: usize = 1024;

    fn set_input(&mut self, input: &Self::Input, fuzzvm: &mut FuzzVm<Self>) -> Result<()> {
        // Escribir la entrada mutada en memoria del guest dónde el objetivo la lee
        fuzzvm.write_bytes_dirty(VirtAddr(BUFFER_ADDR), CR3, input)?;
        Ok(())
    }

    fn reset_breakpoints(&self) -> Option<&[AddressLookup]> { /* stop conditions */ }
    fn crash_breakpoints(&self) -> Option<&[AddressLookup]> { /* crash sites */ }
}
ElementoPropósito
START_ADDRESSDónde reanuda la ejecución cada iteración
set_inputInyectar la entrada fuzz en memoria del guest
reset_breakpointsDónde una iteración termina normalmente
crash_breakpointsDirecciones que indican un crash (p.ej. panic, abort)

Ejecutando

ComandoDescripción
cargo run -r -- fuzz -c 8Hacer fuzzing con 8 cores
cargo run -r -- project translateSimbolizar/inspeccionar el snapshot
cargo run -r -- coverageGenerar cobertura del corpus
cargo run -r -- trace <input>Single-step trace una entrada
cargo run -r -- minimize <input>Encoger una entrada que crashea

Por qué snapshot fuzzing gana aquí

Característica del objetivoFuzzing convencionalSnapchange
Startup costosoPagado cada iteraciónPagado una vez
Requiere auth/handshakeDifícil de alcanzarSnapshot pasado
Protocolo statefulDifícilSnapshot mid-sesión
Código del kernel/hypervisorMuy difícilAjuste natural

Cobertura & triage

CapacidadNota
Cobertura de breakpointCobertura vía breakpoints en bloques básicos
Dedup de crashAgrupados por dirección de fallo/estado
Traces de single-stepTrace de instrucción completa para una entrada dada
Inspección de memoriaLeer memoria del guest en tiempo de crash

Snapchange vs otros fuzzers

AspectoSnapchangeAFL++LibAFL (Nyx)syzkaller
EjecuciónRestauración de snapshot KVMFork de procesoSnapshot (Nyx)VM + syscalls
Costo de setupPagado una vezCada iteraciónUna vezPor VM
ObjetivoCualquier cosa en snapshot VMBinarios userspaceConfigurableOS kernels
EsfuerzoAlto (escribir fuzzer Rust)BajoAltoMedio

Compara con LibAFL (que también ofrece backends de snapshot) y syzkaller para fuzzing de syscall del kernel.

Recursos