
مكتبة بايثون لـ Turbo Intruder تضيف دعم موضع الحمولة وأنواع الهجوم Sniper/Clusterbomb/Pitchfork مع توليد اختبارات قائم على الوسوم لاختبار الاختراق عبر HTTP.

Haptyc هي مكتبة Python تم بناؤها لإضافة دعم مواقع الحمولات (Payload Positions) وأنواع الهجمات Sniper/Clusterbomb/Batteringram/Pitchfork إلى Turbo Intruder. بينما يحقق Haptyc هذه الأهداف بشكل جيد، فإنه يقدم أيضًا طريقة أبسط للتعبير عن تسلسلات الاختبار بشكل عام. على الرغم من أن هذه المكتبة صُممت لاستهداف Turbo Intruder، إلا أنها لا تعتمد بشكل صارم على Turbo Intruder ويمكن استخدامها في أي مكان يتطلب توليد اختبار في سياق Python. للأسف، في الوقت الحالي، نظرًا لأن Haptyc بُنيت لمفسر Jython، فهي تدعم فقط Python 2.7 (على الرغم من أن التغييرات المستقبلية ستعمل على إصلاح ذلك).
وسوم Haptyc هي وسوم يمكن للمختبر استخدامها لتعليق حمولة إدخال أصلية. يمكن للمختبر استخدام وسوم متعددة لإحاطة أجزاء رئيسية من البيانات في طلب HTTP لتغليفها كحمولة موضعية. عند توليد الاختبارات، سيقوم Haptyc بتحليل جميع الوسوم في الحمولة الأصلية وتوليد اختبارات وفقًا للوظائف المرتبطة بأسماء الوسوم. عندما يقوم Haptyc بتقييم وسم Haptyc، فسينفذ وظيفة الوسم المرتبطة (تسمى هذه تحويل Haptyc) لحمولة اختبار لوضعها في موضع الوسم المقابل في الطلب. تستلم كل وظيفة وسم وسيطه data ووسيطه state. قد يحتوي وسيط data على البيانات الداخلية للوسم أو قد يحتوي على تسلسل حمولة اختبار آخر. وسيط state هو كائن حالة مرتبط بالوسم حيث يمكن تخزين الحالة بين تكرارات الاختبار. دعنا نستعرض مثالاً.
الحمولة الأصلية:
GET /animal/[+GuessAnimal]dog[+end] HTTP/1.1
فئة Haptyc وتحويل Haptyc:
from haptyc import *
original = "GET /animal/[+GuessAnimal]dog[+end] HTTP/1.1"
class TestLogic(Transform):
@ApplyList(["snake","cat","owl","lion"])
def test_GuessAnimal(self, data, state):
return data + "?original=" + self.inner() + "&attempt=" + str(state.iter)
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
الاختبارات المولدة:
GET /animal/snake?original=dog&attempt=0 HTTP/1.1
GET /animal/cat?original=dog&attempt=1 HTTP/1.1
GET /animal/owl?original=dog&attempt=2 HTTP/1.1
GET /animal/lion?original=dog&attempt=3 HTTP/1.1
في المثال أعلاه، نرى كيف يمكن التعبير عن الاختبارات بطريقة بسيطة باستخدام Haptyc. أولاً، يتم استيراد مكتبة Haptyc. ثانيًا، قمنا بتعريف البيانات الأصلية مع تعليقات وسوم Haptyc (GuessAnimal). بعد ذلك، يتم تعريف فئة TestLogic وتمديدها كفئة Transform. داخل هذه الفئة، يتم تسجيل كل طريقة تبدأ بـ test_ كوسم Haptyc للتقييم في الحمولة الأصلية. نستخدم مزخرف منطق (decorator) لتطبيق منطق الحالة لهذا التحويل Haptyc. في هذه الحالة، نستخدم المزخرف @ApplyList(list) لإخبار Haptyc بتوليد اختبار لكل عنصر في القائمة المحددة ووضع ذلك العنصر في تحويل Haptyc كوسيط data. داخل التحويل، نعيد نسخة مطفرة (mutated) من البيانات لإدراجها مرة أخرى في موضع الوسم. في هذه الحالة، يكون التحوير هو عنصر القائمة كبيانات متسلسلة مع البيانات المحاطة بالوسم (dog) ثم متسلسلة مع قيمة iter في كائن الحالة. أخيرًا، يظهر باقي كود Python إنشاء كائن TestFactory وتوليد جميع الاختبارات في حلقة for. هذا مثال على هجوم نمط Sniper القياسي الذي يستهدف موضع حمولة واحد. لنلق نظرة بعد ذلك على أنماط هجوم أخرى.
الحمولة الأصلية:
GET /animal?type=[%type]dog[%end]&name=[%name]fido[%end] HTTP/1.1
فئة Haptyc وتحويل Haptyc:
from haptyc import *
original = "GET /animal?type=[%type]dog[%end]&name=[%name]fido[%end] HTTP/1.1"
class TestLogic(Transform):
@ApplyList("snake","cat","owl","lion")
def test_type(self, data, state):
return data
@ApplyList("Frank", "Lisa", "Jin", "Tooth")
def test_name(self, data, state):
return data
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
الاختبارات المولدة:
GET /animal?type=snake&name=Frank HTTP/1.1
GET /animal?type=snake&name=Lisa HTTP/1.1
GET /animal?type=snake&name=Jin HTTP/1.1
GET /animal?type=snake&name=Tooth HTTP/1.1
GET /animal?type=cat&name=Frank HTTP/1.1
GET /animal?type=cat&name=Lisa HTTP/1.1
GET /animal?type=cat&name=Jin HTTP/1.1
GET /animal?type=cat&name=Tooth HTTP/1.1
GET /animal?type=owl&name=Frank HTTP/1.1
GET /animal?type=owl&name=Lisa HTTP/1.1
GET /animal?type=owl&name=Jin HTTP/1.1
GET /animal?type=owl&name=Tooth HTTP/1.1
GET /animal?type=lion&name=Frank HTTP/1.1
GET /animal?type=lion&name=Lisa HTTP/1.1
GET /animal?type=lion&name=Jin HTTP/1.1
GET /animal?type=lion&name=Tooth HTTP/1.1
أظهر المثال 1 كيفية تقييم التحويلات بنمط Sniper باستخدام علامة '+' في الوسم [+tag][+end]. يوضح المثال 2 كيف يمكننا استخدام تحويلين/موضعين لشن هجوم بنمط Clusterbomb. كما ترى، نستخدم وسطين تحويل منفصلين يسمى [%type][%end] و [%name][%end]. تخبر علامة '%' Haptyc بتقييم هذه التحويلات بنمط Clusterbomb، أي لكل حمولة في التحويل الأول يتم إنشاء اختبار مع الحمولة من التحويل الثاني. عدد الاختبارات هو عدد اختبارات كل تحويل مضروبًا في بعضها البعض.
باستخدام نفس كود Python تمامًا، يمكننا تغيير نمط الهجوم من Clusterbomb إلى Pitchfork عن طريق تغيير '%' إلى '#'. تضع هجمات نمط Pitchfork الحمولات الموضعية بالتوازي. عدد الاختبارات هو أقل عدد اختبارات بين جميع التحويلات المشاركة.
الحمولة الأصلية:
GET /animal?type=[#type]dog[#end]&name=[#name]fido[#end] HTTP/1.1
الاختبارات المولدة:
GET /animal?type=snake&name=Frank HTTP/1.1
GET /animal?type=cat&name=Lisa HTTP/1.1
GET /animal?type=owl&name=Jin HTTP/1.1
GET /animal?type=lion&name=Tooth HTTP/1.1
الحمولة الأصلية:
GET /animal?type=dog&id=[+idor]0[+end]&process=[@randbool]False[@end] HTTP/1.1
فئة Haptyc وتحويل Haptyc:
from haptyc import *
import random
original = "GET /animal?type=dog&id=[+idor]0[+end]&process=[@randbool]False[@end] HTTP/1.1"
class TestLogic(Transform):
@ApplyIteration(10)
def test_idor(self, data, state):
return str(state.iter)
def per_randbool(self, data):
return random.choice(["True", "False"])
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
الاختبارات المولدة:
GET /animal?type=dog&id=0&process=False HTTP/1.1
GET /animal?type=dog&id=1&process=True HTTP/1.1
GET /animal?type=dog&id=2&process=False HTTP/1.1
GET /animal?type=dog&id=3&process=True HTTP/1.1
GET /animal?type=dog&id=4&process=False HTTP/1.1
GET /animal?type=dog&id=5&process=True HTTP/1.1
GET /animal?type=dog&id=6&process=False HTTP/1.1
GET /animal?type=dog&id=7&process=True HTTP/1.1
GET /animal?type=dog&id=8&process=False HTTP/1.1
GET /animal?type=dog&id=9&process=False HTTP/1.1
التحويلات الثابتة يُشار إليها بعلامة '@' ووظائف التحويل تبدأ دائمًا بـ per_ لأن هذه التحويلات ليست تكرارية، فهي لا تنشئ اختبارات أو تحتفظ بحالة. هذه التحويلات هي مجرد تحويلات بسيطة (naive) يمكنك تطبيقها في أي مكان في الحمولة لتحويل بدون حالة دون التأثير على التحويلات الحافظه للحالة. نظرًا لأنها لا تفرض أي اختبارات، فلا يمكنك توليد اختبارات باستخدام التحويلات الثابتة وحدها، فهي مصممة ليتم خلطها مع التحويلات التكرارية. في المثال أعلاه، لدينا تحويل بنمط Snipe مكون من 10 اختبارات يضع معرفًا متزايدًا. لدينا أيضًا تحويل ثابت يضع قيمة منطقية عشوائية في موضعه.
قد تكون هناك حالات يرغب فيها المختبر في إجراء بعض المعالجة/التهيئة قبل بدء تسلسل الاختبار. لدعم ذلك، يقوم Haptyc بتنفيذ جميع التحويلات المشاركة لمرحلة تهيئة قبل تنفيذ التحويل لتوليد الاختبار. يمكن استخدام خطوة التهيئة لأداء أي تهيئة يطلبها المختبر ووضعها في كائن الحالة. لهذا، يمكن للمختبر استخدام state.init كقيمة منطقية لتحديد ما إذا كان التنفيذ في مرحلة التهيئة. سيتم تجاهل أي بيانات يتم إرجاعها من خطوة التهيئة.
الحمولة الأصلية:
GET /animal?data=[+b64mutate]SGVsbG8gSGFja2VyIQ==[+end] HTTP/1.1
فئة Haptyc وتحويل Haptyc:
from haptyc import *
import base64
original = "GET /animal?data=[+b64mutate]SGVsbG8gSGFja2VyIQ==[+end] HTTP/1.1"
class TestLogic(Transform):
@ApplyIteration(10)
def test_b64mutate(self, data, state):
if state.init:
state.decoded = base64.b64decode(data)
return
return base64.b64encode(random_insert(state.decoded, ["'"]))
TestFactory = TestLogic(original)
for test in TestFactory:
print(test)
الاختبارات المولدة:
GET /animal?data=SGVsbG8gSCdhY2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFja2VyISc= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjaydlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGEnY2tlciE= HTTP/1.1
GET /animal?data=SCdlbGxvIEhhY2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjaydlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFja2VyISc= HTTP/1.1
GET /animal?data=SCdlbGxvIEhhY2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjJ2tlciE= HTTP/1.1
GET /animal?data=SGVsbG8gSGFjJ2tlciE= HTTP/1.1
في المثال أعلاه، يستخدم الاختبار state.init لفك تشفير base64 للحمولة الداخلية المغلفة مرة واحدة فقط في بداية تسلسل الاختبار وتخزين تلك النتيجة في state.decoded. ثم لجميع عمليات توليد الاختبار العادية، يتم استخدام state.decoded كالبيانات الداخلية المفككة ليتم معالجتها. هذا النوع من الأنماط مفيد لتحسين أداء التحويل نظرًا لأن عملية فك تشفير واحدة فقط تحدث في البداية (بدلاً من فك تشفير نفس الحمولة عند توليد كل اختبار).
[+tag]inner[+end] - تحويل تكرار بنمط Sniper[%tag]inner[%end] - تحويل تكرار بنمط Clusterbomb[#tag]inner[#end] - تحويل تكرار بنمط Batteringram/Pitchfork[@tag]inner[@end] - تحويل ثابت بدون حالة| الاسم | الوسائط | الوصف |
|---|---|---|
| @CloneTransform(srcname, destname) | srcname=سلسلة لاسم طريقة تحويل للنسخ منها، destname=سلسلة لاسم تحويل غير موجود للنسخ إليه | يُستخدم CloneTransform لنسخ تنفيذ تحويل واحد إلى مساحة اسم أخرى دون الحاجة إلى نسخ/لصق. هذا مفيد في هجمات نمط '%' و '#' عندما تحتاج إلى إعادة استخدام نفس تنفيذ التحويل في مواضع متعددة |
| الاسم | الوصف |
|---|---|
| self.inner() | يسترجع الحمولة الداخلية للوسم |
| self.stop() | سيوقف فورًا توليد الاختبار لهذا التحويل |
| الاسم | الوصف |
|---|---|
| state.iter | عدد التكرارات الحالي للتحويل (يبدأ من 0) |
| state.init | قيمة منطقية تشير إلى ما إذا كان في مرحلة التهيئة |
| الاسم | الوصف |
|---|---|
| radamsa(data) | هذه الدالة تنفذ radamsa على بيانات الإدخال وتعيد نتيجتها (مطلوب تثبيت radamsa) |
| index_insert(data, list, index) | هذه الدالة تقوم بإدراج حمولة من القائمة في البيانات المقدمة في الفهرس المحدد |
| random_insert(data, list) | هذه الدالة تقوم بإدراج حمولة من القائمة في البيانات المقدمة في فهرس عشوائي |
هناك طريقتان لتثبيت Haptyc
turbo-intruder-all_w_haptyc.jar المرفق بهذا المستودعأيًا كانت الطريقة التي تختارها، فإن هذه الإصدارات لا تتضمن radamsa، وإذا كنت تريد دعم radamsa فيجب عليك تثبيته من هذا المستودع: (اختياري) قم بتثبيت radamsa عبر https://gitlab.com/akihe/radamsa
turbo-intruder-all_w_haptyc.jar في دليل الإصداراتAddSelect File ... واختر turbo-intruder-all_w_haptyc.jar./install.sh <المسار المطلق الذي يحتوي على turbo-intruder-all.jar>| الاسم | الوسائط | الإدخال data | الوصف |
|---|
| @ApplyIteration(n) | n= عدد التكرارات | القيمة الداخلية لوسم haptyc | منطق لتوليد N اختبار مع inner كـ data |
| @ApplyRange(b,e,s=1) | b = قيمة البداية، e = القيمة القصوى، s = الخطوة | القيمة المولدة من النطاق | منطق لتوليد اختبار لكل قيمة يتم التدرج بها مع إعطاء القيمة كـ data |
| @ApplyList(L) | L = قائمة Python | عنصر القائمة | منطق لتوليد اختبار لكل قيمة في القائمة مع إعطاء القيمة كـ data |
| @ApplyFilelist(path) | path = مسار نظام الملفات | عنصر القائمة | منطق لتوليد اختبار لكل قيمة في قائمة الملفات مع إعطاء القيمة كـ data |
| @ApplyPayloads(name) | name = اسم قائمة مدمجة | عنصر القائمة | منطق لتوليد اختبار لكل قيمة في القائمة المدمجة مع إعطاء القيمة كـ data |
| self.me() | سيعيد اسم سياق التحويل الحالي |
| self.set_label(label) | سيضع التسمية لهذا الاختبار الحالي |
| self.get_label(label) | سيحصل على التسمية لهذا الاختبار الحالي |