الموديول ده بيركّز على محورين أساسيين:
تطوير إكسبلويت من الصفر غالبًا معقَّد ومحتاج وقت وخبرة كبيرين. من ناحية تانية، إيجاد إكسبلويت عام جاهز يطابق بالظبط ظروف تقييم حقيقي ممكن يكون صعب بنفس القدر. الحل العملي هو ناخد إكسبلويت متاح ونعدّله عشان يناسب متطلبات بيئة الهدف المحددة.
لما نتعامل مع مشاكل memory corruption — زي ثغرات buffer overflow — كذا مكوّن حرج عادةً محتاج تعديل. ده ممكن يشمل تفاصيل اتصال الشبكة، عناوين الـ return، إعداد الـ payload، وoffsets الذاكرة. كل عنصر من دول لازم يتماشى بالظبط مع نظام الهدف.
لو نظام الهدف بيشغّل نظام تشغيل حديث زي Windows Server 2022 لكن الإكسبلويت اتطوّر أصلًا لمنصة أقدم بكتير زي Windows Server 2003، آليات دفاعية حديثة — خصوصًا حماية زي Address Space Layout Randomization (ASLR) — على الأرجح هتمنع الإكسبلويت من إنه يشتغل صح وممكن تسبّب كراش للتطبيق. الكراش ده ممكن يعطّل الخدمة العرضة للاستغلال مؤقتًا أو يأثّر سلبًا على أنظمة إنتاجية — نتيجة لازم مختبري الاختراق يتجنّبوها كل ما أمكن.
قبل أي اختبار، نطاق المهمة لازم يحدد بوضوح المخاطر المقبولة، بما فيها احتمالية تعطّل الخدمة. العملاء لازم يوافقوا على المخاطر دي مُسبقًا. كمحترفين أمنيين، مسؤوليتنا هي تقليل التأثير التشغيلي مع تحقيق أهداف الاختبار برضه.
لتقليل احتمالية التعطّل، أفضل ممارسة هي مراجعة كود الإكسبلويت بدقة، تعديله بحرص، والتحقق منه جوه بيئة لاب متحكَّم فيها بتحاكي الهدف قدر الإمكان قبل استخدامه في سيناريو حي.
الاختلافات الخاصة بكل هدف كمان بتفسّر ليه مستودعات زي Exploit Database غالبًا بتوفّر نسخ متعددة من الإكسبلويت لنفس الثغرة — كل نسخة ممكن تكون معدَّلة لإصدار نظام تشغيل، معمارية، أو إعدادات مختلفة.
في بعض الحالات، ممكن يكون مفيد إننا نعيد كتابة أو نترجم إكسبلويت للغة برمجة تانية، وده بيسمح بالتكامل مع مكتبات موجودة، أدوات أتمتة، أو أطر استغلال، وده بيوسّع قدراته. كمان توافق المنصة ممكن يبقى مشكلة — إكسبلويت مصمَّم للتجميع والتنفيذ على Windows ممكن يحتاج تعديلات عشان يشتغل على بيئة مبنية على Linux زي Kali Linux، اللي بتُستخدم بشكل شائع أثناء التقييمات الأمنية.
أبعد من إكسبلويتات memory corruption، تعديل إكسبلويتات الويب بيجيب اعتبارات مختلفة. دي غالبًا بتتضمّن تعديل إعدادات اتصال الشبكة وتفاصيل خاصة بالتطبيق زي مسارات الطلبات، المعطيات، الـ headers، توكينز التوثيق، وكوكيز الجلسة عشان تطابق تطبيق الويب المستهدَف.
الـ Buffer هو جزء محجوز من الذاكرة بيُستخدم لتخزين بيانات مؤقتًا، غالبًا متوفّرة من مستخدم أو مكوّن برنامج تاني. بعض الـ buffers تقدر تتوسّع ديناميكيًا، بينما تانية بتتخصّص بحجم ثابت مُسبقًا.
ثغرات buffer overflow من أقدم أشكال عيوب memory corruption، موثَّقة من أواخر الثمانينات. رغم عقود من التحسينات الدفاعية، لسه بتظهر في سوفت وير حديث.
على مستوى عالي، buffer overflow بيحصل لما بيانات الإدخال تتجاوز المساحة المخصَّصة وتفيض لمناطق ذاكرة مجاورة. لما ده يحصل على الـ stack، يقدر يكتب فوق قيم حرجة مخزَّنة قريب.
تخيّل buffer مصمَّم لتخزين باسورد بحد أقصى 8 بايت. لو مستخدم بعت نص أطول، الحروف الزيادة هتمتد أبعد من حدود الـ buffer. من غير ضمانات مناسبة، الـ overflow ده يقدر يفسد ذاكرة قريبة ويؤدي لسلوك غير متوقَّع.
| المنطقة | الوصف |
|---|---|
| Heap | ذاكرة مُدارة ديناميكيًا بتُستخدم لبيانات كبيرة أو قابلة للوصول عالميًا |
| Stack | منطقة ذاكرة منظَّمة بتُستخدم لاستدعاءات الدوال، المتغيّرات المحلية، والتحكّم بتدفّق التنفيذ |
الـ stack عادةً بيخزّن متغيّرات محلية زي buffers وأعداد صحيحة، بالإضافة لمعلومات تحكّم زي معطيات الدوال وعناوين الـ return.
char buffer[64];
strcpy(buffer, argv[1]);
هنا، buffer بحجم ثابت 64 بايت مُعلَن، وبيانات المستخدم بتتنسخ جواه باستخدام الدالة strcpy. الدالة دي غير آمنة لأنها مابتعملش فحص حدود (bounds checking). لو الإدخال تجاوز 64 بايت، هيكتب فوق ذاكرة مجاورة.
لما دالة تتنفّذ، الـ stack كمان بيخزّن return address بيوضّح من أنهي نقطة البرنامج لازم يكمّل لما الدالة تخلّص. لو الـ overflow كتب فوق العنوان ده، الـ processor هيقفز لأي قيمة اتحطّت مكانه لما الدالة ترجع. ده ممكن لأن تعليمة الـ return بتحمّل العنوان في register الـ instruction pointer (EIP/RIP)، اللي بيتحكّم في تدفّق تنفيذ البرنامج.
مهاجم بيتحكّم في العنوان ده يقدر يوجّه التنفيذ لكود خبيث.
بإرسال إدخال أكبر من الـ buffer
بقيمة متحكَّم فيها من المهاجم
الـ shellcode جوه الـ buffer
للكود المحقون
غالبًا، المهاجمين بيكتبوا فوق الـ return address بموقع تعليمة زي "jump to stack pointer"، وده بيخلّي البرنامج ينفّذ الـ payload المخزَّن في الذاكرة. لزيادة الموثوقية، المهاجمين ممكن يضيفوا سلسلة من تعليمات no-operation (NOP sled) قبل الـ payload، وده بيسمح للتنفيذ "ينزلق" جوه الـ shellcode حتى لو القفزة مش محاذية تمامًا.
بما إن الهجمات دي موجودة من عشرات السنين، أنظمة التشغيل قدّمت دفاعات زي:
لأغراض التعلّم، سيناريوهات تطوير الإكسبلويت غالبًا بتفترض إن الحمايات دي معطَّلة.
لما بنعدّل إكسبلويت buffer overflow لهدف محدد، كذا مكوّن ممكن يحتاج تعديل:
أي تغيير بيأثّر على طول الـ buffer ممكن يزحزح الـ offset المطلوب للكتابة فوق return address، يعني الإكسبلويت لازم يتم معايرته من جديد.
حتى لو إكسبلويت عام فيه return address شغّال، الأأمن إنك تحدد العنوان الصح بنفسك. ده عادةً بيتم بمحاكاة بيئة الهدف جوه آلة افتراضية وتحليل التطبيق العرضة للاستغلال باستخدام debugger.
الإكسبلويتات العامة غالبًا بتتضمّن payloads مُرمَّزة. دي مايجبش تتوثق فيها عمياني أبدًا، لأنها ممكن تنفّذ أفعال غير مقصودة. الأفضل إن المختبرين يولّدوا ويضيفوا الـ payloads بتاعتهم بأنفسهم، معدَّة بعنوان وبورت الـ listener بتاعهم.
أثناء إنشاء الـ payload، حروف معينة لازم غالبًا تتجنّب. "الحروف السيئة" (bad characters) دي ممكن تعطّل الإكسبلويت لأن التطبيق بيفسّرها كإشارات تحكّم. مثلًا، null byte (\x00) ممكن ينهي النص بدري ويقطع الـ payload.
في بعض الحالات، الإكسبلويت بيعتمد على payload متخصّص مرتبط بإحكام بالثغرة. لو كده، فهم سلوكه ممكن يحتاج reverse engineering، اللي ممكن يكون معقَّد. عشان كده، سير العمل العملي غالبًا بيركّز على استبدال الـ shellcode بـ بديل آمن ومعروف كل ما أمكن.
الأفضل إن كود الإكسبلويت يتجمّع باستخدام compiler أصلي (native) يطابق نظام تشغيل الهدف. لكن ده مش دايمًا ممكن أثناء تقييم. في كتير من الحالات، المختبرين بيشتغلوا من منصة هجوم واحدة — غالبًا Kali Linux — بينما محتاجين يبنوا إكسبلويت مُعَد لنظام مختلف زي Windows.
لما التجميع المباشر على منصة الهدف مش ممكن، cross-compilation بتوفّر حل فعّال. الـ cross-compiler بيسمح بتجميع كود على نظام تشغيل بينما بيُنتج executable لنظام تاني.
واحدة من أكتر toolchains استخدامًا لإنتاج binaries خاصة بـ Windows من Linux هي MinGW-w64. لو مش متثبّتة، تقدر تضيفها عن طريق مدير الباكيدجات.
بالـ toolchain ده، كود C المصدري يقدر يتجمّع لملف Windows Portable Executable (PE) مباشرة من جهاز الهجوم.
أثناء التجميع، أخطاء linker ممكن تظهر بتوضّح مراجع غير محلولة لوظائف شبكية. الأخطاء دي غالبًا بتحصل لأن الكود بيعتمد على مكتبات شبكة Windows اللي مش متضمَّنة تلقائيًا.
البحث عن رسائل الخطأ عادةً بيكشف إن وظائف زي network initialization وsocket operations بتنتمي لـ Windows Sockets (Winsock) API. لحل كده، المكتبة المناسبة لازم تتربط صراحةً أثناء التجميع. إضافة linker flag الصح بيوجّه الـ compiler إنه يضمّن مكتبة الشبكة المطلوبة في الـ executable النهائي.
كتير من فشل التجميع مش بسبب أخطاء صياغة (syntax)، لكن بسبب dependencies ناقصة.
بعد التجميع الناجح، الخطوة الجاية هي مراجعة كود الإكسبلويت بحثًا عن قيم إعداد مُدمَجة (hard-coded). في كتير من الإكسبلويتات العامة، تفاصيل اتصال زي عنوان IP الهدف، البورت المستهدَف، وإعدادات البروتوكول بتكون مُدمَجة مباشرة في الكود المصدري. القيم دي لازم تتعدّل عشان تطابق بيئة الهدف الفعلية.
كود إكسبلويت نموذجي (C) — أنشئ ملف اسمه exploit.c:
#include <stdio.h>
#include <winsock2.h>
int main() {
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
printf("Starting exploit...\n");
WSAStartup(MAKEWORD(2,2), &wsa);
s = socket(AF_INET, SOCK_STREAM, 0);
server.sin_addr.s_addr = inet_addr("192.168.1.10"); // Target IP
server.sin_family = AF_INET;
server.sin_port = htons(80); // Target port
connect(s, (struct sockaddr *)&server, sizeof(server));
printf("Connected to target!\n");
closesocket(s);
WSACleanup();
return 0;
}
ده برنامج proof-of-concept بسيط بيؤسس اتصال TCP للهدف — شبيه بإيه ما كتير من إكسبلويتات الشبكة بتعمله داخليًا.
تثبيت الـ Cross-Compiler (لو مش متثبّت):
sudo apt update
sudo apt install mingw-w64
تجميع لـ Windows Executable، باستخدام الـ cross-compiler الخاص بـ Windows:
i686-w64-mingw32-gcc exploit.c -o exploit.exe -lws2_32
اختبار الـ Executable: انقل exploit.exe لجهاز Windows وشغّله. لو IP والبورت المستهدفين متاحين، الخرج هيكون:
Starting exploit...
Connected to target!
التقنية دي بالظبط بتُستخدم لما:
حالات شائعة في الواقع تشمل: إكسبلويتات local privilege escalation، هجمات client-side، ومواقف فيها runtime للسكربتات مش متاح. المختبرين الأمنيين غالبًا بيجمّعوا كود إكسبلويت عام من مصادر زي Exploit Database عشان يطابقوا بيئة المهمة بتاعتهم.
التطبيق المستهدَف هو Sync Breeze Enterprise v10.0.28. هنفحص واحد من الإكسبلويتات العامة المتاحة للثغرة دي، بهدف الحصول على إكسبلويت شغّال مناسب لبيئة اللاب بتاعتنا وبعدين فهم إزاي نعدّله لو لزم.
لما بندوّر بالاسم والإصدار، بنلاقي إدخالات متعددة، منها سكربتات proof-of-concept مكتوبة بلغات مختلفة. من بين الخيارات المتاحة، واحد منها Denial-of-Service (DoS) proof of concept، وتانيين بيوضّحوا استغلال remote buffer overflow.
هجمات DoS بس بتعطّل الخدمة من غير ما تدّي تحكّم في النظام، فغالبًا أقل فايدة أثناء اختبار اختراق لما يكون فيه مسار استغلال كامل متاح. فالتركيز لازم يتوجّه لإكسبلويتات buffer overflow، اللي بتمكّن تنفيذ الكود.
الثغرة موجودة في خدمة HTTP المدمَجة في السوفت وير. طلب POST معدّ بعناية بيحفّز حالة buffer overflow، وده بيسمح للمهاجم يكتب فوق تدفّق التنفيذ.
رغم إن مراجعة الكود المصدري الكامل موصى بيها، السلوك الأساسي يقدر يتلخّص مفاهيميًا:
| الجانب | Python | C |
|---|---|---|
| نموذج التنفيذ | بيتنفّذ عبر interpreter، مابيولّدش binaries مستقلة افتراضيًا | بيتجمّع لـ executables أصلية تقدر تشتغل بشكل مستقل |
| إدارة الذاكرة | دمج النصوص بسيط وتلقائي | الذاكرة لازم تُدار صراحةً، وعمليات النصوص محتاجة حرص شديد |
| التشغيل في بيئة مقيَّدة | مش هيشتغل من غير interpreter — PyInstaller ممكن يحوّله لـ executable لكن محتاج تعديل يدوي | مناسب لمواقف مفيهاش runtime للسكربتات متاح |
بسبب الفروق دي، تعديل إكسبلويتات مبنية على C بيحتاج حرص وفهم تقني أكتر من تعديل سكربتات مكتوبة بلغات مستوى أعلى.
عشان نبدأ تعديل الإكسبلويت، بننسخ الكود المصدري من المستودع المحلي لمجلد الشغل بتاعنا باستخدام خيار mirror (-m في SearchSploit). ده بيسمح لنا نعدّل ونجمّع الكود من غير ما نغيّر الإدخال الأصلي في قاعدة البيانات.
بعد النسخ، أول خطوة هي فحص الكود المصدري بحثًا عن تفاصيل خاصة بالمنصة. في بداية ملف C المصدري، ملفات الـ header بتكشف بيئة التجميع المقصودة — مثلًا، إشارات لمكتبات شبكة Windows بتوضّح إن الإكسبلويت اتصمّم عشان يتجمّع على نظام Windows. ده معناه إن محاولة تجميعه مباشرة على Linux هتفشل من غير خطوات إضافية.
بفحص الكود المصدري بعمق أكتر، بنلاقي إنه بيعتمد على return pointer موجود جوه مكتبة runtime الخاصة بـ Visual Basic msvbvm60.dll، اللي مش فعليًا متضمَّنة مع التطبيق العرضة للاستغلال.
لما نفحص الموديولات المحمَّلة بواسطة عملية الهدف جوه debugger على جهاز Windows الاختباري، بنلاقي إن الـ DLL ده مفقود — معناه إن الـ return pointer المختار مش هيشتغل في بيئتنا.
نبدأ خدمة Sync Breeze على نظام Windows 10، نفتح Immunity Debugger بصلاحيات إدارية، نربطه بعملية syncbrs الشغّالة، ونراجع الموديولات المحمَّلة عبر executable modules view. بفحص أسماء الموديولات ومساراتها، نقدر نتأكد إن مكتبة الـ runtime المطلوبة مش موجودة.
بما إن النسخة الـ Python من الإكسبلويت معلَّمة كـ verified على Exploit Database ومعروف إنها بتشتغل صح، نقدر نعيد استخدام الـ return address من النسخة دي بدل العنوان الغلط:
unsigned char retn[] = "\x83\x0c\x09\x10"; // 0x10090c83
لو مفيش return address شغّال متاح من إكسبلويت تاني، فيه بدائل تانية:
objdump (متاحة افتراضيًا على Kali Linux) لتحديد تعليمات زي JMP ESPفي سيناريوهات buffer overflow الكلاسيكية، الاعتماد على عناوين من مكتبات النظام غير موثوق لأن حمايات زي ASLR بتعشوّشها كل إقلاع (boot). الأأمن إننا نختار تعليمات من موديولات التطبيق نفسه اللي مش محمية بـ ASLR.
مراجعة أعمق بتوضّح إن متغيّر الـ shellcode بيحتوي payload الهجوم مُرمَّز كـ hexadecimal bytes، وده بيخلّي وظيفته مش واضحة من أول نظرة. المؤشّر الوحيد الواضح هو وجود NOP sled في البداية.
بما إن إكسبلويت Python بيحدد مسبقًا الحروف الإشكالية (bad characters) اللي لازم نتجنّبها، نقدر نولّد payload جديد مصمَّم لإعدادنا باستخدام أداة Metasploit msfvenom من Metasploit Framework. الـ payload بيتعدّ لـ 32-bit Windows reverse shell وبيتنسّق للتضمين في كود C المصدري مع استبعاد الحروف السيئة.
بعد استبدال: (1) عنوان وبورت الهدف، (2) الـ return pointer، (3) الـ payload (shellcode) — الكود المصدري للإكسبلويت دلوقتي بيبني طلب HTTP POST فيه الـ buffer الخبيث ويبعته للخدمة العرضة للاستغلال. بنية الـ buffer بتشمل:
بنجمّع الكود المعدَّل باستخدام الـ cross-compiler toolchain اللي اتكلّمنا عنه، والتجميع بيكتمل بنجاح من غير أخطاء.
نرجع لـ Immunity Debugger: نربط بعملية Sync Breeze الشغّالة، نروح لعنوان JMP ESP المختار، نحط breakpoint عند النقطة دي، ونكمّل التنفيذ. بعدين نشغّل الإكسبلويت المُجمَّع — وبما إن الـ binary بيستهدف Windows، ممكن نشغّله على Linux باستخدام Wine.
رغم إن الإكسبلويت بيتصل بنجاح ويبعت الطلب الخبيث، الـ breakpoint مابيتفعّلش. بدل كده، التطبيق بيعمل كراش، وregister الـ instruction pointer بيحتوي القيمة 0x9010090c.
ده بيدّل على إن الكتابة فوق العنوان حصلت فعلًا — لكن غلط. العنوان بيبان مُزاح بايت واحد، معناه إن الـ offset المستخدَم للوصول للـ instruction pointer المحفوظ على الـ stack غير دقيق. نتيجة لكده، الـ processor بيحمّل عنوان غير مقصود بدل تعليمة JMP المرغوبة.
عمليًا، طول buffer الإكسبلويت محسوب بشكل خاطئ قليلًا، وده بيخلّي الكتابة فوق العنوان تهبط في الموقع الغلط. تصحيح الـ offset ده أساسي عشان نحقق تحكّم موثوق في تدفّق التنفيذ.
عشان نشخّص ليه الكتابة فوق instruction pointer كانت بتهبط غلط، لازم نفحص إزاي الإكسبلويت بيبني الـ padding buffer الأولي بتاعه. في بداية الكود، بلوك كبير من الذاكرة ممتلئ بحرف "A" بيتعمل باستخدام تخصيص ديناميكي:
int initial_buffer_size = 780;
char *padding = malloc(initial_buffer_size);
القيمة دي مش عشوائية. تحليل سابق حدد إن 780 بايت هي المسافة الدقيقة المطلوبة للوصول لـ saved return address على الـ stack والكتابة فوقه، وده في النهاية بيسمح بالتحكّم في register EIP.
الذاكرة المتحصَّل عليها من malloc غير مُهيَّأة (uninitialized)، فالإكسبلويت بيملاها صراحةً:
memset(padding, 0x41, initial_buffer_size);
هنا، 0x41 بيمثّل قيمة ASCII لحرف "A"، منتجة سلسلة متواصلة من حروف "A". السلسلة دي بتخدم كـ padding عشان تدفع تدفّق التنفيذ بالظبط لموقع الـ return address.
بعدها مباشرة، عملية تانية بتعدّل آخر بايت في المنطقة دي:
memset(padding + initial_buffer_size - 1, 0x00, 1);
السطر ده بيستبدل آخر حرف بـ null byte (0x00)، وبالفعل بيحوّل الـ padding لنص C-style سليم.
في لغة C، البيانات النصية بتتعامل كـ null-terminated strings. الدوال اللي بتدمج أو تنسخ نصوص — زي strcpy وstrcat — بتحدد نهاية النص بإيجاد أول null byte. لاحقًا في الإكسبلويت، buffer طلب أكبر بيتجمّع:
char *buffer = malloc(buffer_length);
memset(buffer, 0x00, buffer_length);
strcpy(buffer, request_one);
strcat(buffer, content_length_string);
strcat(buffer, request_two);
strcat(buffer, padding);
strcat(buffer, retn);
strcat(buffer, shellcode);
strcat(buffer, request_three);
البرنامج بيخصّص مساحة للطلب النهائي، يمسحها، وبعدين يضيف مكوّنات متعددة بالترتيب: headers الطلب، طول المحتوى المحسوب، أجزاء طلب إضافية، بلوك الـ padding، الـ return pointer المختار، الـ payload، وبيانات إغلاق الطلب.
بما إن الـ padding اتحوّل لنص null-terminated، بس الحروف اللي قبل الـ null byte هي اللي بتتضاف. رغم إن حجم التخصيص كان 780 بايت، الـ padding القابل للاستخدام بقى 779 حرف، لأن آخر بايت بقى الآن هو الـ terminator.
التفصيلة الدقيقة دي بتفسّر ليه الكتابة فوق العنوان فاتت موقعها المقصود — الإكسبلويت كان فعليًا ناقص بايت واحد بالظبط.
الحل بسيط: نخصّص بايت إضافي واحد عشان طول النص الفعلي يطابق الـ offset المطلوب.
int initial_buffer_size = 781;
char *padding = malloc(initial_buffer_size);
memset(padding, 0x41, initial_buffer_size);
memset(padding + initial_buffer_size - 1, 0x00, 1);
بالتعديل ده، الـ padding دلوقتي بيحتوي 780 حرف "A" بالإضافة للـ null المنهي، وبيعيد المسافة الصحيحة للـ return address، ممكّن تحكّم دقيق في تدفّق التنفيذ.
باستخدام الـ cross-compiler القادر على إنتاج Windows executables من Linux
لاستقبال الاتصال العكسي (مثلًا Netcat على بورت 443)
التأكد إن خدمة Sync Breeze العرضة للاستغلال شغّالة على نظام الهدف
تشغيل الـ binary (على Linux، ممكن عبر Wine لتشغيل برامج Windows)
بمجرد التحفيز، الإكسبلويت بيبعت الطلب المصاغ، والـ overflow بيحصل في الموقع الصح، والـ payload بينفّذ.
لما الـ listener يستقبل اتصال داخل، ده بيدّل على إن الـ payload اتنفّذ بنجاح وفتح command shell على جهاز الهدف. المهاجم دلوقتي عنده وصول command-line عن بعد. ميزة إضافية للإكسبلويت المُحسَّن ده هي قابلية النقل (portability): مابقاش محتاج Windows attack host وممكن يتطلق مباشرة من بيئة اختبار اختراق زي Kali Linux.
على عكس ثغرات memory corruption، عيوب تطبيقات الويب عادةً مابتعملش كراش للبرامج أو تتلاعب بالذاكرة مباشرة. بسبب كده، حمايات نظام التشغيل زي DEP أو ASLR عادةً ما بتتدخّلش. نتيجة لكده، إكسبلويتات الويب غالبًا أسهل في التعديل وإعادة الاستخدام. مع ذلك، الاستغلال الناجح لسه يقدر يكشف محتوى قاعدة بيانات حساس أو حتى يوفّر تنفيذ أوامر على السيرفر.
رغم إن إكسبلويتات الويب ممكن تبان أبسط، تعديلها لسه بيحتاج مراجعة كود دقيقة. قبل إجراء تغييرات، المُقيّم لازم يحلّل إزاي الإكسبلويت بيتفاعل مع التطبيق المستهدَف عن طريق سؤال نفسه:
مهم كمان نتذكّر إن الإكسبلويتات المنشورة للعامة نادرًا ما بتاخد بالاعتبار إجراءات دفاعية زي قواعد سيرفر مخصَّصة أو web application firewalls. الحمايات دي مش معروفة للمؤلف الأصلي وممكن تمنع أو تعدّل الطلبات أثناء الاختبار الحقيقي.
تقييم فيه سيرفر Linux بيشغّل خدمة Apache. الـ enumeration كشف تثبيت CMS Made Simple v2.2.5، متاح عبر بورت TCP 443. الأبحاث بتوضّح إن الإصدار ده فيه ثغرة remote code execution وله إكسبلويت عام متاح. رغم إن الاستغلال محتاج بيانات اعتماد صالحة، تفاصيل دخول إدارية اتحصّل عليها قبل كده أثناء الاستطلاع.
base_url = "http://192.168.1.10/cmsms/admin"
base_url = "https://192.168.50.120/admin"
التغيير ده بيحاذي الإكسبلويت مع عنوان IP الصحيح، المسار، واستخدام HTTPS.
أثناء تصفّح الموقع، المختبر بيواجه خطأ تحقق شهادة بيوضّح إن السيرفر بيستخدم شهادة غير موثوقة. بما إن الإكسبلويت بيعتمد على مكتبة Python requests، التحقق من SSL لازم يتعطّل عشان نمنع فشل الاتصال. كل طلب POST في السكربت بيتعدّل بإضافة:
verify=False
ده بيوجّه المكتبة إنها تتجاهل أخطاء التحقق من الشهادة وتكمّل الاتصال.
username = "admin"
password = "password"
username = "admin"
password = "HUYfaw763"
من غير الخطوة دي، الإكسبلويت هيفشل أثناء مرحلة تسجيل الدخول.
بعد التعديل، الإكسبلويت بينفّذ التسلسل ده:
العملية دي فعليًا بتحوّل ثغرة authenticated لـ remote command execution كامل.
لما السكربت المعدَّل بيتشغّل، التوثيق بينجح، لكن خطأ runtime بيحصل أثناء معالجة CSRF token المستخرَج من رد الـ redirect بتاع السيرفر. الخطأ بيوضّح إن السكربت حاول يوصل لعنصر قائمة مش موجود.
مفسّر Python أبلغ إن الفشل حصل جوه الدالة المسؤولة عن استخراج CSRF token من URL. السطر المشكوك فيه بيستخدم ميزة تقسيم النصوص في Python (split()) لفصل URL حسب اسم معطى معين وبعدين يوصل للعنصر التاني في القائمة الناتجة.
تقسيم نص لثلاث أجزاء بيدّي indices 0، 1، 2. محاولة الوصول لـ index 1 لما جزء واحد بس موجود هيسبّب IndexError.
الإكسبلويت افترض إنه بعد التوثيق، السيرفر هيوجّه المتصفح لرابط فيه معطى معين بيُستخدم كـ anti-CSRF token. السكربت كان متوقِّع حاجة زي:
https://target/admin?__c=TOKEN_VALUEوكان مخطَّط يقسّم الـ URL عند "__c=" ويستخرج التوكين من الجزء التاني. لو المعطى ده مش موجود في الـ URL، التقسيم بيُنتج جزء واحد بس — وده بيسبّب الكراش.
بدل التخمين، بنطبع النص الحقيقي اللي التطبيق بيرجّعه قبل معالجته — خطوة debugging مهمة جدًا في تعديل الإكسبلويتات. بعد إضافة print، السكربت كشف الـ URL الفعلي للـ redirect:
https://target/admin?_sk_=TOKEN_VALUEدلوقتي بنشوف المشكلة بوضوح: الإكسبلويت افترض المعطى الغلط. التطبيق بيستخدم اسم معطى مختلف.
ليه ده ممكن يحصل؟ أسباب واقعية متعددة: (1) إصدار سوفت وير مختلف عن اللي مؤلف الإكسبلويت استخدمه، (2) اختلافات إعداد التطبيق، (3) تحديثات أمنية غيّرت أسماء المعطيات، (4) توطين (localization) أو تخصيص. في المهمات الحقيقية، اختلافات كده طبيعية.
بما إن السيرفر بيستخدم _sk_ بدل __c، بنحدّث المتغيّر جوه الإكسبلويت تبعًا لكده. ده بيحاذي السكربت مع سلوك تطبيق الهدف. بعد التعديل، منطق الاستخراج بيطلع التوكين صح.
بعد تطبيق الإصلاح: التوثيق بينجح، خطوة رفع الملف بتتنفّذ، ملف الـ payload بيتنسخ/يتغيّر اسمه، والإكسبلويت بيبلّغ عن نجاح. ده بيأكّد إن مشكلة الـ parsing كانت العائق الوحيد.
متوثقش في خرج الإكسبلويت بس — دايمًا تحقّق يدويًا. web shell اترفع، فنتفاعل معاه بإرسال طلب أمر. تنفيذ أمر نظام بسيط زي فحص المستخدم الحالي بيأكّد تنفيذ الأوامر عن بعد. لو الأمر رجّع حساب مستخدم سيرفر الويب (مثلًا www-data على أنظمة Linux)، الاستغلال مؤكَّد.
لما إكسبلويت يفشل: حدد الخطأ بالظبط ← افهم إيه اللي الكود كان متوقِّعه ← افحص سلوك التطبيق الفعلي ← حدد التباين ← عدّل تبعًا لكده ← تحقّق من النجاح يدويًا.
خطوات منظَّمة ممكن تتبعها كل ما إكسبلويت عام مش شغّال "زي ما هو":
| الأمر | الوظيفة |
|---|---|
sudo apt install mingw-w64 | تثبيت toolchain التجميع المتقاطع لـ Windows |
i686-w64-mingw32-gcc file.c -o file.exe -lws2_32 | تجميع C لـ Windows PE (32-bit) مع ربط مكتبة Winsock |
x86_64-w64-mingw32-gcc file.c -o file.exe -lws2_32 | نفس الشيء لنسخة 64-bit |
wine file.exe | تشغيل Windows binary على Linux |
| البايت | ليه مشكلة |
|---|---|
\x00 | null byte — بينهي النص قبل الأوان في دوال زي strcpy/strcat |
\x0a / \x0d | line feed / carriage return — ممكن تكسر بروتوكولات نصية زي HTTP |
\x25 | علامة % — ممكن تتفسّر كـ format specifier |
| المكوّن | الدور |
|---|---|
| Padding | يملا الـ buffer لحد الـ offset المطلوب (راعِ null terminator عند الحساب) |
| Return Address | يكتب فوق instruction pointer بعنوان تعليمة زي JMP ESP |
| NOP Sled | يحسّن موثوقية الهبوط جوه الـ shellcode |
| Shellcode | الـ payload الفعلي (يُفضَّل يتولَّد بـ msfvenom مع استبعاد bad chars) |
| العرَض | الفحص الأول |
|---|---|
| فشل الاتصال فورًا | base_url صحيح؟ HTTP ولا HTTPS؟ |
| خطأ شهادة SSL | أضف verify=False في requests |
| فشل التوثيق | بيانات الاعتماد مُحدَّثة؟ شكل الطلب صح؟ |
| IndexError / KeyError | اطبع الرد الفعلي — اسم المعطى أو بنية الرد اختلفت |
في الموديول ده، غطّينا المقاطع الأساسية لإكسبلويت stack-based buffer overflow بسيط احتاج تعديل مكثّف عشان يطابق بيئة الهدف بتاعتنا. بعد كده عملنا cross-compile للكود عشان يشتغل من منصة الهجوم Kali بتاعتنا.
كمان عدّلنا إكسبلويت ويب عشان نوضّح إزاي الأنواع دي من الإكسبلويتات ممكن تتعاد استخدامها لبيئة هدف مختلفة.
السيناريوهات دي كاشفة لحلول عوائق شائعة بتواجه مختبري الاختراق لما بيتعاملوا مع إكسبلويتات عامة أثناء مهمة. الفرق بين إكسبلويت "مكسور" وإكسبلويت شغّال غالبًا بيكون تفصيلة صغيرة — offset غلط ببايت واحد، اسم معطى مختلف، أو شهادة SSL غير موثوقة — مش مشكلة في جوهر الثغرة نفسها.
نهاية نوتس الموديول الحادي عشر — OSCP: Fixing Exploits