
طبّق أسلوب فرّق تسد لتجاوز أنظمة EDR
خوارزمية فرِّق تسُد (Divide and Conquer) هي خوارزمية تُستخدم بشكل شائع في البرمجة لحل مشكلة معقدة عن طريق تقسيمها إلى العديد من المشكلات الفرعية الأبسط. يمكننا تطبيق هذا الأسلوب على الأمن الهجومي بهدف مختلف: إرباك حلول حماية نقاط النهاية (EDRs) بحيث تفقد أثر أنشطتنا ولا تتمكن من إطلاق أي تنبيه. وهذا مشابه لما يمكن رؤيته مؤخرًا في أي حملة تصيّد تقريبًا في البرية: سلاسل إصابة طويلة، وتشغيل ملفات متعددة خطوة بخطوة (مثل .url -> .one -> .js -> .bat -> .dll) بدلاً من تشغيل الحمولة النهائية مباشرة. كل ملف من الملفات المنفَّذة يقوم بمهمة بسيطة (تنزيل ملف آخر، إجراء أي تغيير في سجل النظام، نقل الملفات بين المجلدات أو تغيير أسمائها/امتداداتها وما إلى ذلك) يصعب وسمها بأنها خبيثة بمفردها، مما يهيئ البيئة للتنفيذ النهائي.
قررت اختبار هذه الفكرة البسيطة لكن مطبَّقة على شيء مختلف، في هذه الحالة، حقن العمليات عن بُعد (Remote Process Injection). الكود المقدم في هذا المستودع ليس جديدًا، بل على العكس، إنه غالبًا أحد أكثر الطرق شيوعًا ومباشرة لحقن شيلكود في عملية بعيدة: استخدام NtOpenProcess وNtAllocateVirtualMemory وNtWriteVirtualMemory وNtProtectVirtualMemory وNtCreateThreadEx. الاختلاف الوحيد هو أنني أعمل fork للعملية باستخدام NtCreateUserProcess بعد كل واحدة من تلك الاستدعاءات. وبما أن العملية المتفرعة تستكمل التنفيذ من RIP + 1 والذاكرة منسوخة بالكامل من العملية الأم، يمكننا تنفيذ حقن العمليات عن بُعد ولكن باستخدام 5 عمليات مختلفة، فقط نحتاج إلى التأكد من أن أي handle مطلوب لاستدعاءات API اللاحقة يتم توريثه بشكل صحيح.
بهذه الطريقة، نقوم بتقسيم إجراء حقن الشيلكود إلى مهام أبسط، وتشغيل كل واحدة منها في سياق (عملية) منفصل.
لقد اختبرت إثبات المفهوم هذا (PoC) ضد ثلاثة من أكثر حلول EDR شيوعًا حاليًا: MDE وCrowdStrike وSentinelOne. النتائج تتحدث عن نفسها: 2 من 3 حلول EDR أطلقت تنبيه حقن العمليات عن بُعد عند تشغيل الـ PoC بدون الـ forks؛ وعلى النقيض، لم يطلق أيٌّ منها أي تنبيه بمجرد إدخال آلية الـ fork.
بالطبع، حتى مع آلية الـ fork يمكننا رؤية الأحداث المقابلة لإنشاء العمليات وإنشاء الخيوط وكذلك كل السلوك العابر بين العمليات في التليمتري الخام، لكن يبدو أن ذلك لا يكفي حلول EDR لتصنيف النشاط بأنه خبيث، مما يثبت الغرض من هذا الـ PoC. من خلال تقسيم السلوك الخبيث إلى مهام أبسط وتشغيل كل واحدة منها من عملية مختلفة، يمكننا إرباك حلول EDR ومنعها من إطلاق أي تنبيه.
يمكن تحقيق هذه النتيجة نفسها بطرق مختلفة، لقد استخدمت آلية الـ fork فقط لتبسيط الكود وتقليل النشاط العابر بين العمليات.
إذا كنت تريد اختبار ذلك بنفسك، قم بتجميع الكود مع ومن دون استدعاءات الدالة fork()، ثم شغّل الحمولتين في بيئة تحتوي على حل EDR المطلوب.
نظرًا لأننا نستخدم إضافة LITCRYPT لتعتيم النصوص الحرفية (فقط لشفرة Dinvoke_rs)، فمن المطلوب تعيين متغير البيئة LITCRYPT_ENCRYPT_KEY قبل تجميع الكود:
C:\Users\User\Desktop\Split> set LITCRYPT_ENCRYPT_KEY="yoursupersecretkey"
بعد ذلك، ما عليك سوى تجميع الكود وتشغيل الأداة:
C:\Users\User\Desktop\Split> cargo build --release
C:\Users\User\Desktop\Split\target\release> split.exe -h
هذه التقنية بمفردها ليست كافية لتجاوز حل EDR؛ إذا كان كودك لا يراعي مبادئ opsec إطلاقًا، فمن المحتمل جدًا أن يتم اكتشافك على أي حال. هذه ليست حلاً سحريًا، بل مجرد طبقة أخرى من التهرب يمكنك إضافتها إلى أدواتك. ومع ذلك، فإن الكود المقدم في هذا المستودع لا يراعي مبادئ opsec إطلاقًا للأسباب التالية من بين أسباب أخرى:
من ناحية أخرى، لقد اختبرت هذا الأسلوب فقط ضد حلول EDR المذكورة، ولا أعلم ما إذا كانت حلول EDR أخرى سيتم تجاوزها أيضًا. يمكنك اختباره وإخباري بالنتيجة ;)