
واجهة برمجة تطبيقات بايثون للاستخدام مع مواصفات C2 الخارجية لـ Cobalt Strike
# إطار عمل external_c2 إطار عمل بلغة بايثون لبناء واستخدام واجهات لنقل البيانات بين الأطر، مع تركيز خاص على العمل كامتداد لأطر القيادة والتحكم. حالياً، هذا مخصص فقط كتنفيذ لمواصفات External C2 الخاصة بـ Cobalt Strike كما هو موضح في [وثيقة المواصفات هذه](https://www.cobaltstrike.com/downloads/externalc2spec.pdf)، لكنه عرضة للتغيير مع نضوج المشروع. ## الإشادات شكر كبير لـ [xychix](https://twitter.com/xychix). لم يكن هذا المشروع ممكناً على الإطلاق بدون مساهماتهم القيمة. أساساً، هذا المشروع هو إعادة بناء وتوسيع [مشروع External C2 الخاص بـ Outflank](https://github.com/outflanknl/external_c2) # البنية يتكون هذا المشروع من الأجزاء الرئيسية التالية: - Builder - Skeletons - Frameworks - Transports - Encoders - Manager (لم يتم تنفيذه بعد) ## Builder يقرأ Builder ملف تهيئة، ويستخدم الخيارات المهيأة لإنشاء بناء عن طريق استبدال `علامات` داخل `الهياكل العظمية`. يمكن استخدام Builder مع `build_files.py`. يتم توفير نموذج لتهيئة Builder كـ `sample_builder_config.config.sample`. ## Skeletons `Skeletons` هي "الهياكل العظمية" المختلفة للكود التي سيقوم `Builder` بملئها ديناميكياً لإنشاء بناء قابل للاستخدام بالكامل. تحتوي `Skeletons` على `علامات` سيتم استبدالها بقيم قابلة للاستخدام بواسطة `Builder`. هناك ثلاثة 'أنواع' مختلفة من الهياكل العظمية: ### علامات Skeleton يمكن وضع علامة داخل أي ملف في `skeleton`، والتي سيتم استبدالها بقيمة محددة في تهيئة builder. في أفضل الممارسات، **يجب ألا تُستخدم العلامات مطلقاً لكتابة المتغيرات مباشرة، بل يجب استخدامها فقط لتعيين القيم**. إذا كان يجب إعادة استخدام قيمة علامة ما، فيفضل تخزين القيمة في متغير والإشارة إليها بهذه الطريقة، بدلاً من إعادة استخدام نفس العلامة. تنسيق العلامة هو: ` ```[var:::identifier_for_the_marker]``` ` سيتم كتابة السلاسل النصية في الهيكل العظمي مباشرةً محاطة بعلامات اقتباس مفردة، وسيتم كتابة الأرقام كما هي. **في حالة أن السلسلة النصية في التهيئة محاطة بعلامات اقتباس مزدوجة**، ستتم كتابة السلسلة مباشرةً في الملف محاطة بعلامات اقتباس مزدوجة بدلاً من ذلك، وسيتم إزالة علامات الاقتباس المفردة المحيطة. يمكن توضيح هذه العلاقة على النحو التالي: ```python ################# # كود الهيكل # ################# # يحتوي الهيكل على السطر التالي من الكود: foo = ```[var:::bar]``` ############## # النتيجة النهائية # ############## # مخزنة في التهيئة كـ: # foo = bar # مكتوبة كـ: foo = 'bar' # مخزنة في التهيئة كـ: # foo = "bar" # مكتوبة كـ: foo = "bar" # مخزنة في التهيئة كـ: # foo = 2 # مكتوبة كـ: foo = 2 # مخزنة في التهيئة كـ: # foo = "2" # مكتوبة كـ: foo = "2" ``` ## Frameworks Frameworks هي التطبيق الأساسي الذي يحدد البيانات التي يستخدمها `Transport` و `Encoder`، وكيفية استخدام تلك البيانات. ما يفعله `Framework` معين لا يهم كثيراً، طالما أن المنطق موجود لاستيراد واستخدام `Encoder` و `Transport`. سيكون معظم الأجزاء الأساسية من الـ Framework (بشكل أساسي منطق `Client`) مخزناً كـ `skeleton`، مع وجود واجهة للتفاعل مع جزء الـ Server منه مخزنة ككائن `framework` أساسي. بشكل عام، يحتوي الـ Framework على `Server` و `Client`، ويستخدم `Encoders` و `Transports` لنقل البيانات بينهما. هناك بعض الأساسيات التي يجب مراعاتها عند بناء `Framework`: * الـ `Framework` مسؤول عن ضمان أن `Encoder` متاح لـ `Transport` لاستخدامه. * إذا كان الـ `Framework` يستخدم علاقة عميل-خادم، فيجب تنظيمهما بشكل مناسب. * افهم أنه في معظم الحالات، لن يتفاعل المستخدم النهائي مباشرةً مع `Client` الخاص بـ Framework، لذا إذا كنت تريد أن تكون الأشياء قابلة لإعادة التهيئة على `Client`، فيجب أن يكون قادراً على فعل ذلك أثناء وقت التشغيل دون أي تفاعل مباشر. * يجب أن تكون هناك حاجة ضئيلة لإنشاء `skeleton` لـ `Server` لأن المستخدم النهائي سيتفاعل مباشرةً مع `Server` الخاص بـ Framework. بدلاً من ذلك، اختر قراءة الخيارات من ملف تهيئة، وإعطاء المستخدم النهائي القدرة على تعديل الخيارات (مثل مؤقت الكتلة أو الإسهاب) أثناء وقت التشغيل. * سيتم معالجة `skeleton` الخاص بـ Framework بواسطة Builder، بالتكرار عبر كل ملف فيه، لذا إذا كانت هناك حاجة لتهيئة وسيط معين في وقت البناء، يمكن القيام بذلك بسهولة. * يجب أن يكون `Server` الخاص بـ Framework قابلاً للتفاعل من خلال `framework_manager` شائع. ### Framework Server الـ Server هو التطبيق الذي يدير الاتصال بين `Client` و `C2 Server`. منطق الـ Server ثابت بشكل أساسي. منطق الـ Server لـ Framework `cobalt_strike`، المشار إليه باسم `third-party Client Controller` في المواصفات، موضح أدناه: 1. تحليل التهيئة 2. استيراد وحدة الترميز المحددة 3. استيراد وحدة النقل المحددة 4. إنشاء اتصال بـ C2 Server 5. طلب stager من C2 Server 6. ترميز الـ stager باستخدام وحدة `Encoder` 7. نقل الـ stager باستخدام وحدة `Transport` 8. انتظار استجابة metadata من الـ Client يتم استلامها عبر `Transport` 9. فك ترميز الـ metadata باستخدام وحدة `Encoder` 10. إرسال الـ metadata إلى C2 Server. 11. استلام مهمة جديدة من C2 Server. 12. ترميز المهمة الجديدة 13. إرسال المهمة الجديدة إلى الـ Client عبر `Transport` 14. انتظار استجابة من الـ Client يتم استلامها عبر `Transport` 15. فك ترميز الاستجابة عبر وحدة `Encoder` 16. إرسال الاستجابة إلى C2 Server. 17. تكرار الخطوات 11-16 يجب أن يدعم `Server` القدرة على التعامل مع عدة Clients (لم يتم تنفيذه بعد)، وأن يكون قابلاً للتفاعل من خلال `framework_manager`. ### Framework Client الـ Client هو الحمولة التي تعمل على نقطة النهاية. منطق الـ Client لـ Framework `cobalt_strike` ثابت بشكل أساسي، وموضح أدناه: 1. تنفيذ أي تحضيرات ضرورية لاستخدام `Transport` 2. استلام الـ stager 3. حقن الـ stager وفتح المقبض على الـ beacon 4. الحصول على metadata من الـ beacon 5. إرسال الـ metadata من الـ beacon إلى C2 Server عبر `Transport` 6. مراقبة `Transport` للمهام الجديدة 7. إرسال المهام الجديدة إلى الـ beacon 8. إرسال الاستجابات من الـ beacon عبر `Transport` 9. تكرار الخطوات 6-8. يستخدم الـ Client `Encoder` و `Transport` المحددين لنقل البيانات بينه وبين `Server` الخاص به. ## Encoders تستقبل الـ Encoders البيانات، ثم تعدل تلك البيانات إما لتحضيرها للاستخدام للإرسال عبر الـ Transport، أو لفك ترميز البيانات المستلمة عبر الـ Transport إلى شكلها الخام ليتم تفسيرها بواسطة أي مكون من الـ Framework يستخدمها. يجب أن تتوقع الـ Encoders أن يتم التفاعل معها مباشرةً بواسطة الـ Transport، وأن تتعامل مع البيانات بطريقة محايدة للـ Framework والمكون. ## Transports تخدم الـ Transports دور إرسال واستقبال البيانات عبر قناة اتصال، والتفاعل مع الـ Encoder لضمان تحويل البيانات إلى أي تنسيق ضروري. يجب أن تتوقع الـ Transports استقبال البيانات من مكون Framework، أو عبر قناة الاتصال، وأن تكون قادرة على إرسال البيانات عبر قناة الاتصال. **الـ Transports مسؤولة عن استدعاء `Encoder` لترميز أو فك ترميز البيانات حسب الحاجة**. يجب أن تتوقع الـ Transports أن يتم التفاعل معها مباشرةً بواسطة مكون `Framework`، وأن تتعامل مع البيانات بطريقة محايدة للـ Framework والمكون. # كيفية استخدام هذا 1. أولاً، حدد أي وحدة نقل وترميز ترغب في استخدامها. سنستخدم `transport_imgur` و `encoder_lsbjpg` للمثال التالي. 2. بعد ذلك، أنشئ ملف `builder_config.config` يناسب احتياجاتك، راجع ملف التهيئة النموذجي والقالب المقدمين للحصول على إرشادات حول كيفية القيام بذلك. 3. أنشئ بناء باستخدام `build_files.py`. كمثال، يمكن إنشاء بناء في دليل `builds` باستخدام `encoder_lsbjpg` و `transport_imgur` لـ Cobalt Strike، بشكل مفصل، باستخدام الأمر التالي: ```bash python build_files.py -b builds -f cobalt_strike -c sample_builder_config.config.sample -e encoder_lsbjpg -t transport_imgur -v ``` 4. بعد ذلك، ابدأ بتشغيل الخادم الذي قمت ببنائه ووزع الـ Client الخاص بك. ### Cobalt Strike على الجهاز الذي يعمل عليه الخادم، قم بتنفيذ: `python server.py` للحصول على مخرجات أكثر تفصيلاً، يمكنك تشغيل: `python server.py -v` للحصول على مخرجات أكثر تفصيلاً ومخرجات إضافية مفيدة لتصحيح الأخطاء، يمكنك تشغيل: `python server.py -d` بعد ذلك، قم بتنفيذ الـ Client على نقطة النهاية المستهدفة. إذا نجح كل شيء، سيتم تسجيل beacon جديد في وحدة تحكم Cobalt Strike يمكنك التفاعل معه. # الأسئلة الشائعة **لماذا كتبت هذا؟**: لم يكن هناك الكثير من التطبيقات المنشورة لمواصفات Cobalt Strike، ومن بين تلك المنشورة، إما أنها ليست بلغة مألوفة لدي أو لا تحتوي على النمطية والتجريد الذي كنت أبحث عنه. **لماذا بايثون 2؟**: أنا كسول ومن السهل تنفيذ قنوات نقل وترميز جديدة فيه. **الكود الخاص بك سيء**: هذا ليس سؤالاً. **هل يمكنني تقديم وحدات نقل و/أو ترميز جديدة؟**: نعم من فضلك! أرسل طلب سحب وسأكون سعيداً بمراجعته. **كيف يمكنني تجميع الـ Client في ملف تنفيذي يمكنني توزيعه؟**: لقد اختبرت هذا بنجاح في Kali، لإعادة إنشاء بيئتي، فقط تأكد من تثبيت [veil-evasion](https://github.com/Veil-Framework/Veil-Evasion) وأنك نفذت الإعداد الخاص به. يجب أن يكون قد أنشأ بيئة wine مثبتة عليها بايثون ولديها جميع التبعيات التي تحتاجها. قد تضطر أيضاً إلى تثبيت وحدة `pefile` في هذه البيئة. بعد ذلك، يمكنك الانتقال إلى دليل الـ Client الذي تريد إنشاء ملف تنفيذي له وتشغيل: ```bash chmod +x compile_dll.sh ./compile_dll.sh wine "C:\\Python27\\python.exe" /usr/share/veil/pyinstaller/pyinstaller.py -F -r c2file.dll -w --key "ayyyyyyylmao" client.py ``` استبدل قيمة `key` بأي شيء تريده. يجب أن ترى الملف التنفيذي للـ Client في دليل `dist/`. إذا كنت ترغب في إنشاء ملف تنفيذي يوفر وحدة تحكم يمكنك استخدامها لتصحيح الأخطاء، قم بتجميع الملف التنفيذي باستخدام `wine "C:\\Python27\\python.exe" /usr/share/veil/pyinstaller/pyinstaller.py -F -r c2file.dll -c client.py`.