Salta ai contenuti

Snapchange - Fuzzing Basato su Snapshot con KVM

Snapchange - Fuzzing Basato su Snapshot con KVM Cheatsheet

Snapchange (di AWS) è un framework Rust per snapshot fuzzing. I fuzzer tradizionali riavviano il target per ogni input, che è fatalmente lento quando il codice interessante siede dietro una setup costosa — un handshake di rete, un login, una configurazione analizzata, un database caricato. Snapchange invece scatta una memoria snapshot del target esattamente nel momento di interesse, poi ripristina quello stato e muta da lì usando KVM, conseguendo tassi di iterazione molto alti contro il codice che il fuzzing convenzionale fa fatica a raggiungere.

Il snapshot fuzzing richiede KVM e root. Esegui in un ambiente isolato.

Requisiti

RequisitoNota
Linux con KVM/dev/kvm accessibile
Toolchain RustSnapchange è una libreria Rust
QEMUUsato per scattare lo snapshot
RootPer KVM e accesso alla memoria

Il Modello

FaseCosa succede
1. SnapshotEsegui il target in QEMU al punto di interesse, dumpa memoria + registri
2. HarnessScrivi un fuzzer Rust descrivendo dove va l”input e quando fermarsi
3. FuzzSnapchange ripristina lo snapshot per iterazione e muta l”input
4. TriageI crash sono registrati con lo stato esatto di registro/memoria

L”insight critico: tutto il costo di setup è pagato una volta, nello snapshot. Ogni iterazione successiva inizia da quello stato in microsecondi.

Scattare Uno Snapshot

# Concettuale: esegui il target sotto QEMU, interrompi alla funzione di interesse,
# poi dumpa la memoria fisica e lo stato di registro
./snapchange/qemu_snapshot/take_snapshot.sh --target ./my-server
ArtefattoContiene
fuzzvm.physmemMemoria fisica guest completa
fuzzvm.qemuregsStato di registro CPU
*.symbolsTabella di simboli per copertura/breakpoint
vmlinux / binarioPer simbolizzazione

Scrivere Un Fuzzer

// Forma concettuale — vedi esempi di Snapchange per codice 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<()> {
        // Scrivi l''input mutato in memoria guest dove il target lo legge
        fuzzvm.write_bytes_dirty(VirtAddr(BUFFER_ADDR), CR3, input)?;
        Ok(())
    }

    fn reset_breakpoints(&self) -> Option<&[AddressLookup]> { /* condizioni di stop */ }
    fn crash_breakpoints(&self) -> Option<&[AddressLookup]> { /* siti di crash */ }
}
ElementoScopo
START_ADDRESSDove l”esecuzione riprende ogni iterazione
set_inputInietta l”input di fuzz nella memoria guest
reset_breakpointsDove un”iterazione termina normalmente
crash_breakpointsIndirizzi che indicano un crash (es. panic, abort)

Esecuzione

ComandoDescrizione
cargo run -r -- fuzz -c 8Fuzz con 8 core
cargo run -r -- project translateSimbolizza/ispeziona lo snapshot
cargo run -r -- coverageGenera copertura dal corpus
cargo run -r -- trace <input>Traccia single-step di un input
cargo run -r -- minimize <input>Restringi un input che crasha

Perché Snapshot Fuzzing Vince Qui

Caratteristica targetFuzzing convenzionaleSnapchange
Startup costosoLo paga ogni iterazioneLo paga una volta
Richiede auth/handshakeDifficile da raggiungereSnapshot oltre
Protocollo statefulDifficileSnapshot mid-session
Codice kernel/hypervisorMolto difficileFit naturale

Copertura & Triage

CapacitàNota
Copertura di breakpointCopertura via breakpoint su blocchi di base
Dedup di crashRaggruppato per indirizzo di fallo/stato
Tracce single-stepTraccia di istruzione completa per un dato input
Ispezione della memoriaLeggi la memoria guest al momento del crash

Snapchange vs Altri Fuzzer

AspettoSnapchangeAFL++LibAFL (Nyx)syzkaller
EsecuzioneRipristino snapshot KVMFork di processoSnapshot (Nyx)VM + syscall
Costo di setupPagato una voltaOgni iterazioneUna voltaPer VM
TargetQualsiasi cosa in uno snapshot VMBinari userspaceConfigurabileKernel del sistema operativo
SforzoAlto (scrivi un fuzzer Rust)BassoAltoMedio

Confronta con LibAFL (che offre anche backend di snapshot) e syzkaller per fuzzing syscall del kernel.

Risorse