
Frida-based in-process fuzzing suite with AFL++ proxy, standalone active/passive modes, and shared memory communication for high-performance coverage-guided vulnerability discovery across platforms.
fpicker هي مجموعة أدوات اختبار ضبابي (fuzzing) مبنية على Frida، وتوفر أنماطًا متنوعة من الاختبار الضبابي داخل العملية (in-process fuzzing)، مثل نمط AFL++ أو نمط التتبع السلبي. يجب أن تعمل على جميع المنصات التي تدعمها Frida.
يمكن العثور على بعض المعلومات الأساسية والأفكار وراء fpicker في منشور مدونة كتبته.
يعتمد fpicker على جهود سابقة في ToothPicker، الذي تم تطويره خلال رسالة الماجستير الخاصة بي. تم تطوير معظم fpicker خلال ساعات العمل لدى صاحب عملي (ERNW).
مطلوب لتشغيل fpicker:
frida-core-devkit للمنصة المقابلة الموجودة في إصدارات Frida على GitHub.
libfrida-core-ios.a أو libfrida-core-macos.a أو libfrida-core-linux.a.frida-core.h). قم بتخزينها كـ frida-core-linux.h أو frida-core-ios.h حسب المنصة.update_frida_version.sh قبل البناء.مطلوب فقط عند التشغيل في وضع AFL++:
CFLAGS="-DUSEMMAP=1".CFLAGS="-DUSEMMAP=1 -DTARGET_OS_IOS".يمكن بناء fpicker لـ macOS أو iOS أو Linux. يدعم ملف Makefile حاليًا البناء فقط لـ iOS على macOS ولكن يجب أن يكون من الممكن تمامًا بناء fpicker باستخدام سلسلة أدوات iOS على Linux.
اعتمادًا على الهدف المطلوب، قم بتشغيل:
make fpicker-macos
make fpicker-ios
make fpicker-linux
لبناء fpicker.
بمجرد بناء fpicker، يجب بناء أداة الاختبار الضبابي بعد ذلك:
انظر إلى مجلد الأمثلة للحصول على حالات اختبار ضبابي مختلفة. النهج العام هو كما يلي:
examples/test/test.js) (انظر هنا لمزيد من المعلومات حول الأدوات)frida-compile test.js -o harness.jsالآن يمكن لـ fpicker بدء الاختبار الضبابي. يعتمد الأمر الدقيق بشكل كبير على التكوين والإعداد. فيما يلي بعض الحالات النموذجية. تتوافق هذه الحالات في الغالب مع الأمثلة الموجودة في مجلد الأمثلة.
afl-fuzz -i examples/test-network/in -o ./examples/test-network/out -- \\
./fpicker --fuzzer-mode afl -e attach -p test-network -f ./examples/test-network/harness.js
./fpicker --fuzzer-mode standalone -e attach -p server-process -f harness.js --input-mode cmd \\
--command "./client-send @@" -i indir -o outdir
./fpicker --fuzzer-mode active --communication-mode shm -e attach -p server-process -f harness.js \\
-i indir -o outdir --standalone-mutator cmd --mutator-command "radamsa"
./fpicker --fuzzer-mode passive --communication-mode send -e attach -p server-process -o outdir -f harness.js
./fpicker --fuzzer-mode active -e attach -p test -D remote -o examples/test/out/ -i examples/test/in/ \\
-f fuzzer-agent.js --standalone-mutator cmd --mutator-command "radamsa"
كل هدف يتطلب أداة اختبار ضبابي خاصة به. الجزء الأكثر أهمية في هذه الأداة هو تعريف وظيفة الدخول لـ Frida's Stalker، والتي تحدد بشكل فعال النقطة التي يتم فيها إدراج التجهيز. في وضع in-process، هذا بسيط. ستكون الوظيفة عادةً هي التي يتم استدعاؤها في كل تكرار اختبار ضبابي. ومع ذلك، يمكن أن تكون وظيفة مختلفة أيضًا.
قد يكون تنفيذ أداة بسيطة (في وضع command) كما يلي:
// استيراد الفئة الأساسية للاختبار الضبابي
const Fuzzer = require("harness/fuzzer.js");
// يجب أن تكون فئة الاختبار الضبابي المخصصة فئة فرعية من فئة Fuzzer لتعمل بشكل صحيح
class TestFuzzer extends Fuzzer.Fuzzer {
constructor() {
// يجب أن يحدد المنشئ عنوان الوظيفة المستهدفة وكائن NativeFunction
// الذي يمكن استدعاؤه لاحقًا بواسطة أداة الاختبار الضبابي.
const FUZZ_FUNCTION_ADDR = Module.getExportByName(null, "FUZZ_FUNCTION");
const FUZZ_FUNCTION = new NativeFunction(
FUZZ_FUNCTION_ADDR,
"void", ["pointer", "int64"], {
});
super("test", FUZZ_FUNCTION_ADDR, FUZZ_FUNCTION);
}
}
const f = new TestFuzzer();
exports.fuzzer = f;
تكوّن هذه الأداة التجهيز لتتبع الوظيفة FUZZ_FUNCTION. سيبدأ التجهيز عند الدخول إلى هذه الوظيفة ويتوقف عند عودتها. يجب اختيار هذه الوظيفة بعناية لأنها مكلفة وكلما زادت الأجزاء (التي قد تكون غير مهمة) من العملية التي يتم تجهيزها، كلما تباطأت أداة الاختبار الضبابي. بالطبع، هذا اعتبار بين السرعة والتغطية المقصودة. بالإضافة إلى ذلك، تدعم أداة الاختبار الضبابي حاليًا فقط الوظائف التي يتم الدخول إليها مرة واحدة فقط خلال تكرار اختبار ضبابي واحد، أي لا ينبغي استدعاء الوظيفة أكثر من مرة واحدة خلال حالة اختبار واحدة، وإلا قد تصبح معلومات التغطية غير موثوقة.
عند استخدام وضع in-process، يلزم وجود وظيفة أخرى في سكريبت الأداة. وهي طريقة fuzz. سيتم استدعاؤها في كل تكرار. سيتم استدعاؤها مع معلمتين: مؤشر إلى مخزن مؤقت وطول المخزن. تأخذ وظيفتنا المستهدفة النموذجية معلمتين: مؤشر إلى مخزن مؤقت وطوله. وبالتالي، يمكننا ببساطة تمرير المعاملات التي نحصل عليها في طريقة fuzz.
fuzz(payload, len) {
this.target_function(payload, parseInt(len));
}
في وضع passive، يجب تحديد رد اتصال يعالج البيانات المطلوبة. تتوقع أداة الاختبار الضبابي استقبال مخزن حمولة مؤقت وطوله. اعتمادًا على الوظيفة المستهدفة التي يتم اختبارها، يجب استخراج هذه البيانات. في المثال التالي، لدينا مرة أخرى وظيفة تحتوي على معلمتين: مؤشر إلى مخزن مؤقت وطوله. تحتوي المعلمة args على جميع المعاملات المحتملة التي تستقبلها الوظيفة المستهدفة، لذلك يمكن الوصول إلى معلمة الطول (وهي الثانية في حالتنا) باستخدام args[1]. ثم نقرأ المخزن المؤقت كـ Uint8Array ونرسله مرة أخرى إلى أداة الاختبار الضبابي باستخدام طريقة sendPassiveCorpus.
passiveCallback(args) {
const len = args[1];
const data = new Uint8Array(Memory.readByteArray(args[0], parseInt(len)));
// هذا يشفر البيانات ويرسلها مرة أخرى إلى أداة الاختبار الضبابي
this.sendPassiveCorpus(data, len);
}
في حالة احتياج الهدف إلى نوع من التحضير قبل أن تبدأ أداة الاختبار الضبابي، يوفر fpicker طريقة prepare يتم استدعاؤها أثناء تهيئة الأداة. يمكن أن يكون التحضير هو إنشاء حالة، على سبيل المثال عن طريق إنشاء كائن. قد تبدو وظيفة التحضير هذه كما يلي:
prepare() {
// يمكن إرفاق الكائن بمثيل الأداة بحيث يمكن استخدامه داخل
// طريقة fuzz() لاحقًا.
this.required_object = call_native_function_that_creates_object();
}
يقدم pficker مجموعة كبيرة من الأنماط والإعدادات التي يتم شرحها فيما يلي. يمكن دمج معظم هذه الأنماط بطرق مختلفة. في نهاية هذا القسم يوجد جدول يوضح الخيارات التي يمكن دمجها وحالة تنفيذها.
لدى Fpicker ثلاثة أنماط اختبار ضبابي مختلفة: وضع AFL++، الوضع المستقل النشط والوضع المستقل السلبي: