
مختبر عشوائي قائم على التغطية لتطبيقات بايثون
pip3 install frelatage
مُختبر بايثون الطَفيلي الذي يستحقه العالم
التنصيب | كيف يعمل | المُميزات | استخدام Frelatage | الإعدادات
Frelatage هي مكتبة اختبار طفيلي (fuzzing) لبايثون تعتمد على التغطية، ويمكن استخدامها لاختبار كود بايثون. استُلهم تطوير Frelatage من مُختبرين آخرين، من بينهم AFL/AFL++، وAtheris وPythonFuzz. الهدف الرئيسي للمشروع هو الاستفادة من أفضل مميزات هؤلاء المُختبرين وجمعها معاً في أداة جديدة من أجل اختبار تطبيقات بايثون بكفاءة.
تنويه: هذا المشروع في مرحلة ألفا، وقد يتسبب في سلوكيات غير متوقعة. لا ينبغي استخدام Frelatage في بيئة إنتاج في الوقت الحالي.
pip3 install frelatage
مُوصى به للمطورين. يقوم تلقائياً باستنساخ الفرع الرئيسي من مستودع frelatage، والتنصيب من المصدر.
# استنساخ مستودع Frelatage تلقائياً وتثبيت Frelatage من المصدر
bash <(wget -q https://raw.githubusercontent.com/Rog3rSm1th/Frelatage/main/scripts/autoinstall.sh -O -)
الفكرة وراء تصميم Frelatage هي استخدام خوارزمية جينية لتوليد طفرات تغطي أكبر قدر ممكن من الكود. يمكن تلخيص آلية دورة الاختبار الطفيلي تقريباً في هذا المخطط:
graph TB
m1(طفرة 1) --> |إدخال| function(الدالة المُختبرة)
m2(طفرة 2) --> |إدخال| function(الدالة المُختبرة)
mplus(طفرة ...) --> |إدخال| function(الدالة المُختبرة)
mn(طفرة n) --> |إدخال| function(الدالة المُختبرة)
function --> generate_reports(إنشاء التقارير)
generate_reports --> rank_reports(ترتيب التقارير)
rank_reports --> select(اختيار أفضل n تقرير)
select --> |طفرة| nm1(طفرة 1) & nm2(طفرة 2) & nmplus(طفرة ...) & nmn(طفرة n)
subgraph طفرات الدورة
direction LR
m1
m2
mplus
mn
end
subgraph طفرات الدورة التالية
direction LR
nm1
nm2
nmplus
nmn
end
style function fill:#5388e8,stroke:white,stroke-width:4px
يتيح Frelatage اختبار دالة عن طريق تمرير ملف كإدخال.
import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.parse(data)
input = frelatage.Input(value="initial_value")
f = frelatage.Fuzzer(MyFunctionFuzz, [[input]])
f.fuzz()
يمنحك Frelatage إمكانية اختبار وسائط إدخال من نوع ملف. لتهيئة قيمة هذه الملفات، يجب إنشاء ملفات في مجلد الإدخال (./in بشكل افتراضي).
إذا أردنا تهيئة قيمة ملف يُستخدم في الاختبار، يمكننا القيام بذلك كالتالي:
echo "initial value" > ./in/input.txt
ثم تشغيل المُختبر:
import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.load_file(data)
input = frelatage.Input(file=True, value="input.txt")
f = frelatage.Fuzzer(MyFunctionFuzz, [[input]])
f.fuzz()
import frelatage
import my_vulnerable_library
input = frelatage.Input(file=True, value="input.txt")
@frelatage.instrument([[input]])
def MyFunctionFuzz_1(data):
my_vulnerable_library.load_file(data)
@frelatage.instrument([[input]])
def MyFunctionFuzz_1(data):
my_vulnerable_library.load_file_but_different(data)
# وهكذا دواليك
# سيختبر الطرق المزينة واحدة تلو الأخرى
frelatage.Fuzzer.fuzz_all()
إذا كنت بحاجة إلى تحميل عدة ملفات في مجموعة أساسية دفعة واحدة (مفيد إذا كنت تستخدم مجموعة أساسية كبيرة)، يمكنك استخدام الدالة المدمجة في Frelatage load_corpus. تُعيد هذه الدالة قائمة من الإدخالات.
load_corpus(directory: str, file_extensions: list) -> list[Input]
./، ./images["jpeg", "gif"]، ["pdf"]import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.load_file(data)
my_vulnerable_library.load_file(data2)
# تحميل كل ملف في المجلد ./in
corpus_1 = frelatage.load_corpus(directory="./")
# تحميل كل ملف .gif/.jpeg في المجلد الفرعي ./in/images
corpus_2 = frelatage.load_corpus(directory="./images", file_extension=["gif", "jpeg"])
f = frelatage.Fuzzer(MyFunctionFuzz, [corpus_1, corpus_2])
f.fuzz()
يمكنك نسخ قاموس أو أكثر من هنا إلى المجلد المُخصص للقواميس (./dict بشكل افتراضي).
الاختبار الطفيلي التفاضلي هو تقنية اختبار برمجيات شائعة تحاول اكتشاف الأخطاء من خلال توفير نفس الإدخال لمكتبات/برامج متعددة وملاحظة الاختلافات في سلوكياتها. ستجد مثالاً هنا على استخدام الاختبار التفاضلي مع Frelatage باستخدام مكتبتي json وujson.
يمكنك العثور على المزيد من الأمثلة للمُختبرات والمجموعات الأساسية في دليل الأمثلة.
يتم حفظ كل تقرير عطل في مجلد الإخراج (./out بشكل افتراضي)، في مجلد يُسمى: id:<معرف العطل>,err:<نوع الخطأ>,err_pos:<موضع الخطأ>,err_file:<ملف الخطأ>.
يكون هيكل مجلد التقرير كالتالي:
├── out
│ ├── id:<معرف العطل>,err:<نوع الخطأ>,err_file:<ملف الخطأ>,err_pos:<موضع الخطأ>
│ ├── message
│ ├── input
│ ├── 0
│ ├── <ملف الإدخال 1>
│ ├── ...
│ ├── ...
يحتوي كل تقرير عطل على ملف message يحتوي على رسالة الخطأ.
يتم حفظ كل تقرير زيادة تغطية في مجلد التغطية (./cov بشكل افتراضي)، في مجلد يُسمى: coverage_<المعرف>، ويكون هيكل مجلد التقرير مشابهاً لهيكل مجلدات تقارير الأعطال.