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
| Requisito | Nota |
|---|
| Linux con KVM | /dev/kvm accesible |
| Toolchain Rust | Snapchange es una librería Rust |
| QEMU | Usado para tomar el snapshot |
| Root | Para KVM y acceso a memoria |
El modelo
| Fase | Qué sucede |
|---|
| 1. Snapshot | Ejecutar el objetivo en QEMU hasta el punto de interés, volcar memoria + registros |
| 2. Harness | Escribir un fuzzer Rust describiendo dónde entra la entrada y cuándo parar |
| 3. Fuzz | Snapchange restaura el snapshot por iteración y muta la entrada |
| 4. Triage | Los 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
| Artefacto | Contiene |
|---|
fuzzvm.physmem | Memoria física del guest completa |
fuzzvm.qemuregs | Estado del registro CPU |
*.symbols | Tabla de símbolos para cobertura/breakpoints |
vmlinux / binario | Para 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 */ }
}
| Elemento | Propósito |
|---|
START_ADDRESS | Dónde reanuda la ejecución cada iteración |
set_input | Inyectar la entrada fuzz en memoria del guest |
reset_breakpoints | Dónde una iteración termina normalmente |
crash_breakpoints | Direcciones que indican un crash (p.ej. panic, abort) |
Ejecutando
| Comando | Descripción |
|---|
cargo run -r -- fuzz -c 8 | Hacer fuzzing con 8 cores |
cargo run -r -- project translate | Simbolizar/inspeccionar el snapshot |
cargo run -r -- coverage | Generar 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 objetivo | Fuzzing convencional | Snapchange |
|---|
| Startup costoso | Pagado cada iteración | Pagado una vez |
| Requiere auth/handshake | Difícil de alcanzar | Snapshot pasado |
| Protocolo stateful | Difícil | Snapshot mid-sesión |
| Código del kernel/hypervisor | Muy difícil | Ajuste natural |
Cobertura & triage
| Capacidad | Nota |
|---|
| Cobertura de breakpoint | Cobertura vía breakpoints en bloques básicos |
| Dedup de crash | Agrupados por dirección de fallo/estado |
| Traces de single-step | Trace de instrucción completa para una entrada dada |
| Inspección de memoria | Leer memoria del guest en tiempo de crash |
Snapchange vs otros fuzzers
| Aspecto | Snapchange | AFL++ | LibAFL (Nyx) | syzkaller |
|---|
| Ejecución | Restauración de snapshot KVM | Fork de proceso | Snapshot (Nyx) | VM + syscalls |
| Costo de setup | Pagado una vez | Cada iteración | Una vez | Por VM |
| Objetivo | Cualquier cosa en snapshot VM | Binarios userspace | Configurable | OS kernels |
| Esfuerzo | Alto (escribir fuzzer Rust) | Bajo | Alto | Medio |
Compara con LibAFL (que también ofrece backends de snapshot) y syzkaller para fuzzing de syscall del kernel.
Recursos