Aller au contenu

Snapchange - Fuzzing Basé sur Snapshot avec KVM

Snapchange - Fuzzing Basé sur Snapshot avec KVM

Snapchange (par AWS) est un framework Rust pour le fuzzing basé sur snapshot. Les testeurs traditionnels redémarrent la cible pour chaque entrée, ce qui est fatalement lent quand le code intéressant s’assoit derrière une configuration coûteuse — une poignée de main réseau, une connexion, une config analysée, une base de données chargée. Snapchange prend plutôt un snapshot mémoire de la cible au moment exact d’intérêt, puis restaure cet état et mute à partir de là en utilisant KVM, atteindre des taux d’itération très élevés contre le code que le fuzzing conventionnel peine à atteindre du tout.

Le fuzzing de snapshot nécessite KVM et root. Exécuter dans un environnement isolé.

Exigences

ExigenceNote
Linux avec KVM/dev/kvm accessible
Chaîne d’outils RustSnapchange est une bibliothèque Rust
QEMUUtilisé pour prendre le snapshot
RootPour KVM et l’accès à la mémoire

Le Modèle

PhaseCe qui se passe
1. SnapshotExécuter la cible dans QEMU jusqu’au point d’intérêt, déverser la mémoire + registres
2. HarnaisÉcrire un testeur Rust décrivant où va l’entrée et quand arrêter
3. FuzzSnapchange restaure le snapshot par itération et mute l’entrée
4. TriageLes plantages sont enregistrés avec l’état exact du registre/mémoire

L’idée critique : tout le coût de la configuration est payé une fois, dans le snapshot. Chaque itération suivante commence à partir de cet état en microsecondes.

Prendre un Snapshot

# Conceptuel : exécuter la cible sous QEMU, casser au point de fonction d'intérêt,
# puis déverser la mémoire physique et l'état du registre
./snapchange/qemu_snapshot/take_snapshot.sh --target ./my-server
ArtefactContient
fuzzvm.physmemMémoire physique invitée complète
fuzzvm.qemuregsÉtat du registre CPU
*.symbolsTableau de symboles pour couverture/breakpoints
vmlinux / binairePour la symbolisation

Écrire un Testeur

// Forme conceptuelle — voir les exemples Snapchange pour le code complet
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<()> {
        // Écrire l'entrée mutée dans la mémoire invitée où la cible la lit
        fuzzvm.write_bytes_dirty(VirtAddr(BUFFER_ADDR), CR3, input)?;
        Ok(())
    }

    fn reset_breakpoints(&self) -> Option<&[AddressLookup]> { /* conditions d'arrêt */ }
    fn crash_breakpoints(&self) -> Option<&[AddressLookup]> { /* sites de plantage */ }
}
ÉlémentObjectif
START_ADDRESSOù l’exécution reprend chaque itération
set_inputInjecter l’entrée de fuzzing dans la mémoire invitée
reset_breakpointsOù une itération se termine normalement
crash_breakpointsAdresses qui indiquent un plantage (p. ex. panic, abort)

Exécution

CommandeDescription
cargo run -r -- fuzz -c 8Tester avec 8 cœurs
cargo run -r -- project translateSymboliser/inspecter le snapshot
cargo run -r -- coverageGénérer la couverture du corpus
cargo run -r -- trace <input>Trace d’exécution pas à pas d’une entrée
cargo run -r -- minimize <input>Réduire une entrée plantante

Pourquoi le Fuzzing de Snapshot Gagne Ici

Caractéristique de cibleFuzzing conventionnelSnapchange
Démarrage coûteuxLa paie chaque itérationLa paie une fois
Nécessite auth/handshakeDifficile à atteindreSnapshot après
Protocole avec étatDifficileSnapshot mid-session
Noyau/code hypervisorTrès difficileAjustement naturel

Couverture & Triage

CapacitéNote
Couverture par breakpointCouverture via breakpoints sur blocs de base
Déduplication de plantageGroupé par adresse de défaut/état
Traces d’exécution pas à pasTrace complète d’instruction pour une entrée donnée
Inspection de mémoireLire la mémoire invitée au moment du plantage

Snapchange vs Autres Testeurs

AspectSnapchangeAFL++LibAFL (Nyx)syzkaller
ExécutionRestauration de snapshot KVMFork du processusSnapshot (Nyx)VM + appels système
Coût de configurationPayé une foisChaque itérationUne foisPar VM
CibleN’importe quoi dans un snapshot VMBinaires userspaceConfigurableNoyaux OS
EffortÉlevé (écrire un testeur Rust)BasÉlevéMoyen

Comparer avec LibAFL (qui offre également des backends de snapshot) et syzkaller pour le fuzzing d’appels système du noyau.

Ressources