تخطَّ إلى المحتوى

Snapchange - Snapshot-Based Fuzzing مع KVM

Snapchange - Snapshot-Based Fuzzing مع KVM

Snapchange (من AWS) هو Rust framework لـ snapshot-based fuzzing. Fuzzers التقليدية تعيد تشغيل الهدف لكل إدخال وهذا بطيء بشكل قاتل عندما الأكواد المثيرة للاهتمام تجلس خلف الإعداد المكلف — مصافحة الشبكة أو login أو parsed config أو قاعدة بيانات محملة. Snapchange بدلاً من ذلك يأخذ snapshot الذاكرة من الهدف في بالضبط لحظة الاهتمام ثم يستعيد تلك الحالة ويحور منها باستخدام KVM ويحقق معدلات تكرار عالية جداً ضد الأكواد التي conventional fuzzing تكافح للوصول إليها على الإطلاق.

Snapshot fuzzing يتطلب KVM و root. تشغيل في بيئة معزولة.

المتطلبات

المتطلبملاحظة
Linux مع KVM/dev/kvm accessible
Rust toolchainSnapchange هي مكتبة Rust
QEMUالمستخدمة لأخذ snapshot
Rootل KVM والوصول للذاكرة

النموذج

المرحلةما يحدث
1. Snapshotتشغيل الهدف في QEMU إلى نقطة الاهتمام وتفريغ الذاكرة + السجلات
2. Harnessكتابة fuzzer Rust توصف أين يذهب الإدخال ومتى توقف
3. FuzzSnapchange يستعيد snapshot لكل iteration ويحور الإدخال
4. Triageالأعطال تُسجل مع حالة الذاكرة/السجل بالضبط

الفكرة الحرجة: جميع تكاليف الإعداد يتم دفعها مرة واحدة في snapshot. كل iteration اللاحقة تبدأ من تلك الحالة في microseconds.

أخذ Snapshot

# مفهومي: تشغيل الهدف تحت QEMU وكسر في الدالة المثيرة للاهتمام
# ثم تفريغ الذاكرة المادية وحالة التسجيل
./snapchange/qemu_snapshot/take_snapshot.sh --target ./my-server
الأثريحتوي على
fuzzvm.physmemكامل الذاكرة المادية الضيف
fuzzvm.qemuregsحالة سجل CPU
*.symbolsجدول الرموز للتغطية/breakpoints
vmlinux / binaryللترمز

كتابة Fuzzer

// شكل مفهومي — انظر أمثلة Snapchange للأكواد الكاملة
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<()> {
        // اكتب الإدخال المحور إلى الذاكرة الضيف حيث يقرأه الهدف
        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 */ }
}
العنصرالغرض
START_ADDRESSحيث التنفيذ استئناف كل iteration
set_inputحقن fuzz input إلى الذاكرة الضيف
reset_breakpointsحيث iteration ينتهي عادة
crash_breakpointsعناوين تشير إلى crash (على سبيل المثال panic و abort)

التشغيل

الأمرالوصف
cargo run -r -- fuzz -c 8Fuzz مع 8 cores
cargo run -r -- project translateSymbolize/check snapshot
cargo run -r -- coverageإنشاء التغطية من corpus
cargo run -r -- trace <input>single-step trace input
cargo run -r -- minimize <input>انكماش crashing input

لماذا Snapshot Fuzzing يفوز هنا

خاصية الهدفConventional fuzzingSnapchange
Expensive startupيدفعها كل iterationدفع مرة واحدة
Requires auth/handshakeصعب الوصولSnapshot بعده
Stateful protocolصعبSnapshot mid-session
Kernel/hypervisor codeصعب جداًNatural fit

التغطية & Triage

القدرةملاحظة
Breakpoint coverageالتغطية عبر breakpoints على basic blocks
Crash dedupمجموعة بـ faulting address/state
Single-step tracesكامل instruction trace لـ input معطى
Memory inspectionقراءة ذاكرة الضيف عند crash time

Snapchange مقابل Fuzzers الأخرى

الجانبSnapchangeAFL++LibAFL (Nyx)syzkaller
التنفيذKVM snapshot restoreProcess forkSnapshot (Nyx)VM + syscalls
تكلفة الإعداددفع مرة واحدةكل iterationمرة واحدةلكل VM
الهدفأي شيء في VM snapshotUserspace binariesقابل للتكوينOS kernels
الجهدعالي (اكتب fuzzer Rust)منخفضعاليمتوسط

قارن مع LibAFL (التي توفر أيضاً snapshot backends) و syzkaller لـ kernel syscall fuzzing.

الموارد