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
| Exigence | Note |
|---|
| Linux avec KVM | /dev/kvm accessible |
| Chaîne d’outils Rust | Snapchange est une bibliothèque Rust |
| QEMU | Utilisé pour prendre le snapshot |
| Root | Pour KVM et l’accès à la mémoire |
Le Modèle
| Phase | Ce qui se passe |
|---|
| 1. Snapshot | Exé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. Fuzz | Snapchange restaure le snapshot par itération et mute l’entrée |
| 4. Triage | Les 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
| Artefact | Contient |
|---|
fuzzvm.physmem | Mémoire physique invitée complète |
fuzzvm.qemuregs | État du registre CPU |
*.symbols | Tableau de symboles pour couverture/breakpoints |
vmlinux / binaire | Pour 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ément | Objectif |
|---|
START_ADDRESS | Où l’exécution reprend chaque itération |
set_input | Injecter l’entrée de fuzzing dans la mémoire invitée |
reset_breakpoints | Où une itération se termine normalement |
crash_breakpoints | Adresses qui indiquent un plantage (p. ex. panic, abort) |
Exécution
| Commande | Description |
|---|
cargo run -r -- fuzz -c 8 | Tester avec 8 cœurs |
cargo run -r -- project translate | Symboliser/inspecter le snapshot |
cargo run -r -- coverage | Gé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 cible | Fuzzing conventionnel | Snapchange |
|---|
| Démarrage coûteux | La paie chaque itération | La paie une fois |
| Nécessite auth/handshake | Difficile à atteindre | Snapshot après |
| Protocole avec état | Difficile | Snapshot mid-session |
| Noyau/code hypervisor | Très difficile | Ajustement naturel |
Couverture & Triage
| Capacité | Note |
|---|
| Couverture par breakpoint | Couverture via breakpoints sur blocs de base |
| Déduplication de plantage | Groupé par adresse de défaut/état |
| Traces d’exécution pas à pas | Trace complète d’instruction pour une entrée donnée |
| Inspection de mémoire | Lire la mémoire invitée au moment du plantage |
Snapchange vs Autres Testeurs
| Aspect | Snapchange | AFL++ | LibAFL (Nyx) | syzkaller |
|---|
| Exécution | Restauration de snapshot KVM | Fork du processus | Snapshot (Nyx) | VM + appels système |
| Coût de configuration | Payé une fois | Chaque itération | Une fois | Par VM |
| Cible | N’importe quoi dans un snapshot VM | Binaires userspace | Configurable | Noyaux 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