Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
Inline-Execute-PE — تنفيذ ملفات ويندوز التنفيذية غير المُدارة في بيقون CobaltStrike | Kitploit
أدوات/GitHubGitHub/octoberfest7/inline-execute-pe
تصعيد الامتيازات
GitHuboctoberfest7/inline-execute-pe

Inline-Execute-PE

تنفيذ ملفات ويندوز التنفيذية غير المُدارة في بيقون CobaltStrike

عرض المستودع
723103منذ 3 سنواتتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

Inline-Execute-PE

إخلاء المسؤولية:

هذا المشروع معقد، وقد يؤدي عدم فهم كيفية عمله واختباره بشكل كافٍ إلى تعطل الـ Beacons وفقدان الوصول!

أنصح بشدة بقراءة جميع الوثائق حتى قسم "اعتبارات التصميم والتعليقات"!

مقدمة

Inline-Execute-PE هي مجموعة من ملفات Beacon Object Files (BOFs) وسكريبت Aggressor لـ CobaltStrike، تتيح للمشغلين تحميل برامج ويندوز القابلة للتنفيذ غير المُدارة (unmanaged executables) إلى ذاكرة Beacon وتنفيذها، واسترجاع المخرجات وعرضها في وحدة تحكم Beacon.

يمكّن ذلك المشغلين من استخدام العديد من الأدوات الخارجية (Mimikatz, Dsquery, أدوات Sysinternals, إلخ) دون الحاجة إلى إسقاطها على القرص، أو إعادة تنسيقها إلى كود مستقل عن الموضع (position independent code) باستخدام أداة مثل Donut، أو إنشاء عملية جديدة لتشغيلها.

يتم تعيين هذه البرامج القابلة للتنفيذ في ذاكرة Beacon بحيث يمكن تشغيلها مرارًا دون الحاجة إلى إرسالها عبر الشبكة، أو تخصيص ذاكرة جديدة، أو إنشاء عملية conhost.exe جديدة في كل مرة.

البرامج القابلة للتنفيذ المحملة في Beacons يمكن الوصول إليها وتشغيلها من قبل جميع عملاء CobaltStrike المتصلين بخادم CobaltStrike Team Server.

تم تصميم Inline-Execute-PE لـ Beacons 64 بت وبرامج ويندوز C أو C++ القابلة للتنفيذ 64 بت والمجمعة باستخدام Mingw أو Visual Studio. لا يدعم هذا المشروع برامج 32 بت أو برامج 64 بت المكتوبة بلغة أخرى أو المترجمة باستخدام مترجم مختلف.

الإعداد

استنساخ المستودع، وتشغيل make اختياريًا لإعادة ترجمة الـ BOFs.

قم بتحميل Inline-Execute-PE.cna إلى عميل CobaltStrike. تأكد من أن الدليل الذي يعمل منه CobaltStrike قابل للكتابة بواسطة المستخدم الخاص بك؛ يقوم Inline-Execute-PE بإنشاء ملف نصي هناك (petable.txt) لضمان توفر البيانات المطلوبة لتشغيل Inline-Execute-PE.

الأوامر

يتكون Inline-Execute-PE من 3 أوامر موجهة للهدف تقوم بتشغيل الـ BOFs، و3 أوامر داخلية تتعامل مع بنية بيانات المشروع:

موجهة للهدف:

  1. peload
  2. perun
  3. peunload

بنية البيانات الداخلية:

  1. petable
  2. peconfig
  3. pebroadcast

peload

peload هو البداية لـ Inline-Execute-PE. يُستخدم هذا الأمر لتحميل PE في ذاكرة Beacon. يقوم بالإجراءات الرئيسية التالية:

  1. إرسال الـ PE المحدد عبر الشبكة إلى Beacon أو إرسال اسم الـ PE لقراءته من القرص على الجهاز الهدف
  2. إنشاء هيكل في ذاكرة Beacon لحفظ المؤشرات والمقابض المختلفة المطلوبة من Inline-Execute-PE طوال دورة حياته
  3. تخصيص ذاكرة في Beacon وكتابة الـ PE إليها بحماية RW
  4. تشفير الـ PE في الذاكرة باستخدام مفتاح يحدده المستخدم (XOR)
  5. تخصيص قطعة أخرى من الذاكرة ونسخ الـ PE المشفر بـ XOR إليها. هذا ضروري للتمكن من "إعادة" الـ PE للتنفيذات اللاحقة
  6. إنشاء عملية فرعية conhost.exe تحت Beacon لتهيئة stdin/stdout/stderr
  7. إعادة توجيه stdout و stderr إلى أنبوب مجهول (anonymous pipe) بحيث يمكن التقاط مخرجات الـ PE

perun

perun هو الخطوة الثانية في Inline-Execute-PE. يقوم بالإجراءات الرئيسية التالية:

  1. إرسال وسائط سطر الأوامر عبر الشبكة إلى Beacon
  2. فك تشفير الـ PE في الذاكرة باستخدام XOR
  3. إصلاح جدول عناوين الاستيراد (IAT) للـ PE، مع ربط بعض API المتعلقة بوسائط سطر الأوامر والخروج من العمليات
  4. تغيير حماية ذاكرة الـ PE إلى RWX
  5. تشغيل الـ PE في سلسلة محادثات (thread) خاصة به
  6. التقاط المخرجات من الـ PE وإعادتها إلى CobaltStrike
  7. إعادة حماية ذاكرة الـ PE إلى RW
  8. استبدال الـ PE في الذاكرة بالنسخة المشفرة بـ XOR التي تم إنشاؤها أثناء peload

peunload

يتم استدعاء peunload لإزالة الـ PE من ذاكرة Beacon عندما ينتهي المشغل منه أو يرغب في تحميل PE مختلف. يقوم بالإجراءات الرئيسية التالية:

  1. إغلاق المقابض ومؤشرات الملفات التي تم إنشاؤها أثناء peload
  2. إنهاء عملية conhost.exe التي تم إنشاؤها أثناء peload
  3. تصفير ثم تحرير كلتا نسختي الـ PE في الذاكرة
  4. محاولة تفريغ أي DLLs تم تحميلها بواسطة الـ PE في عملية Beacon (اختياري)

petable

يتم استخدام petable لعرض معلومات حول جميع الـ PEs المحملة حاليًا في Beacons.

كل عميل CobaltStrike لديه petable خاص به؛ يبذل Inline-Execute-PE جهودًا كبيرة لضمان تزامن بياناته بين جميع عملاء CobaltStrike المتصلين بحيث يمكن لجميع المشغلين استخدام الـ PEs. لمزيد من المعلومات، راجع "اعتبارات التصميم والتعليقات".

image

peconfig

يتم استخدام peconfig لتكوين الخيارات المتعلقة بكيفية عمل Inline-Execute-PE. الخياران الحاليان اللذان يمكن تغييرهما هما:

  1. المهلة الزمنية (Timeout). تحدد المدة التي سينتظرها perun حتى يكتمل تنفيذ الـ PE قبل إنهائه. يوجد هذا كإجراء أمان في حالة تمرير وسائط غير صحيحة إلى PE تتسبب في عدم عودته/إنهاء التنفيذ أبدًا. الإعداد الافتراضي هو 60 ثانية ولكن يمكن تعديله لاستيعاب الـ PEs ذات التشغيل الطويل.
  2. UnloadLibraries. يتحكم هذا الخيار في ما إذا كان peunload سيحاول تحرير DLLs من عملية Beacon التي تم تحميلها بواسطة الـ PE. الإعداد الافتراضي هو TRUE. بعض الـ PEs تسبب مشاكل عند تفريغ الـ DLLs من عملية Beacon وقد تؤدي إلى تعطل Beacon، وفي هذه الحالة من الأفضل ترك جميع الـ DLLs التي تم تحميلها بواسطة الـ PE في عملية Beacon. لوحظ ذلك عند استخدام powershell.exe (ربما بسبب تحميل .Net CLR في عملية Beacon).

pebroadcast

يمكن استخدام pebroadcast لنشر محتويات petable الخاص بأحد العملاء يدويًا إلى جميع عملاء CobaltStrike الآخرين المتصلين.

سيقوم كل عميل CobaltStrike آخر بتحديث petable الخاص به بالبيانات المنشورة. لا ينبغي أن يكون هذا ضروريًا أبدًا، لكن الميزة موجودة فقط في حالة الحاجة.

الاستخدام

استخدم peload لتحميل PE في ذاكرة Beacon
image

بدلاً من ذلك، إذا كان هناك PE على الجهاز الهدف ترغب في استخدامه دون إنشاء عملية جديدة، فقدم المسار والمفتاح --local
image

اتصل بـ perun، مررًا أي وسائط إلى الـ PE المحمل
image

يجب الهروب من علامات الاقتباس المزدوجة في الوسائط باستخدام الخطوط المائلة العكسية
image

إذا اكتشفت أن PE يسبب مشاكل عند محاولة تحرير الـ DLLs أثناء التفريغ، استخدم peconfig لضبط unloadlibraries على false
image

بمجرد الانتهاء من استخدام PE، اتصل بـ peunload لتنظيفه من Beacon
image

يمكن الآن تحميل PE مختلف إلى Beacon
image

مهلة perun

يجب أن تكون حذرًا بشأن وسائط سطر الأوامر التي تمررها إلى الـ PE؛ بعض الـ PEs ستعطل تمامًا إذا أعطيت وسائط خاطئة، بينما سيعمل البعض الآخر إلى ما لا نهاية مما يؤدي إلى عدم عودة Beacon أبدًا على الرغم من أن العملية لا تزال قيد التشغيل.

يمكن رؤية ذلك مع Mimikatz.exe عندما لا يتم تحديد 'exit' في نهاية قائمة الوسائط
image

...

image

سيقوم Inline-Execute-PE بإنهاء سلسلة محادثات الـ PE الجاري تشغيله بعد الوصول إلى قيمة المهلة المحددة. يتيح ذلك لـ Beacon استئناف الاتصالات العادية (لا يتصل Beacon مرة أخرى حتى يكتمل تنفيذ BOF perun). بينما لا يزال من الممكن استخدام أوامر CobaltStrike العادية و BOFs الأخرى في هذا Beacon، فإن Inline-Execute-PE معطل الآن؛ عندما يتم إنهاء PE قيد التشغيل بهذه الطريقة، يبدو أنه يعطل stdout و stderr في عملية Beacon، ولا تعمل الـ PEs المحملة لاحقًا بشكل صحيح.

لا يزال من الممكن (ويجب) تفريغ الـ PE من ذاكرة Beacon، ومع ذلك فإن النظر إلى petable سيظهر أن هذا Beacon لم يعد بإمكانه تحميل PEs إضافية إليه. image

من الضروري أن تختبر الـ PEs التي ترغب في تشغيلها باستخدام Inline-Execute-PE، وأن تكون حذرًا عند تمرير وسائط سطر الأوامر إلى perun. بعض الـ PEs أكثر تسامحًا من غيرها.

نصائح وحيل وملاحظات

فيما يلي بعض الملاحظات دون ترتيب معين والتي تم إجراؤها أثناء الاختبار والتطوير بخصوص بعض الـ PEs التي قد يرغب المستخدمون في تحميلها إلى Beacon.

  1. استخدام peunload على Powershell.exe عادة ما يتسبب في تعطل Beacon عندما يكون UnloadLibraries مساوياً لـ TRUE؛ أعتقد أن هذا له علاقة بتحميل Powershell.exe لـ CLR.
  2. سيتعطل Cmd.exe في Beacon ما لم يتم استخدام '/c' كوسيطة أولى. مثال: 'perun /c cd' جيد، بينما 'perun cd' ليس جيدًا.
  3. سيتعطل Mimikatz.exe في Beacon إذا تم تحميله واستخدامه وتفريغه ثم تحميله مرة أخرى إذا كان UnloadLibraries مساوياً لـ TRUE أثناء أول peunload.
  4. بعض الـ PEs مبرمجة لطباعة قوائم المساعدة الخاصة بها عند الخروج؛ لن يتم عرض هذه القوائم لأن استدعاءات ExitProcess و exit() وما شابهها يتم ربطها وإعادة توجيهها إلى ExitThread حتى لا يتسبب الـ PE في خروج عملية Beacon الخاصة بنا.
  5. بعض الـ PEs ليست جيدة في تحرير الذاكرة عند الانتهاء منها وتعتمد على تحرير تلك الذاكرة عند خروج العملية؛ نظرًا لأن الـ PE يعمل داخل عملية Beacon (وبالتالي لا تخرج العملية عند انتهاء الـ PE)، يمكن أن تميل Beacon إلى الانتفاخ مع تحميل وتشغيل المزيد من الـ PEs داخلها. لاحظ ذلك أثناء الاختبار باستخدام شيء مثل Process Explorer وكن واعيًا له أثناء العمليات.
  6. يبدو أن Sysinternal's Psexec لا يعمل؛ على الرغم من أنه يعمل، إلا أنه يشتكي من أن مقبض الجهاز البعيد غير صالح. عمليًا، إذا أراد شخص استخدام شيء مثل psexec، فمن الأفضل تحقيقه باستخدام وكيل socks الخاص بـ CobaltStrike وإصدار psexec الخاص بصندوق الهجوم على أي حال.
  7. إنشاء beacon جديد لاستخدامه مع Inline-Execute-PE ليس فكرة سيئة، خاصة عندما تبدأ في التعود على كيفية تفاعل وعمل الـ PEs المختلفة داخل الإطار. اثنان يساوي واحد، واحد يساوي لا شيء.
  8. إذا كان هناك LOLBIN تريد استخدامه دون التتبع عن إنشاء عملية جديدة، فاستخدم المفتاح --local مع peload واقرأه من القرص على النظام الهدف. يمكن أن يكون هذا مفيدًا أيضًا لتجنب مشكلات الإصدارات.

IOC's و AV/EDR

تشمل IOC's المرتبطة بـ Inline-Execute-Pe على سبيل المثال لا الحصر:

  1. تخصيص الذاكرة باستخدام VirtualAlloc
  2. تغيير حماية الذاكرة المخصصة بين RW و RWX
  3. إنشاء عملية فرعية conhost.exe
  4. تحميل الـ DLLs المطلوبة بواسطة الـ PE المُخطط
  5. أي إجراءات يقوم بها الـ PE الفعلي؛ على سبيل المثال، لمس Mimikatz لـ LSASS

AV/EDR

لم أقم باختبار كامل للبطارية ضد EDR أثناء التطوير، جزئيًا بسبب الكسل وجزئيًا لعدم توفر بيئة اختبار. ومع ذلك، تم اختباره ضد أحدث إصدار من Windows Defender (وهو في تجربتي منتج AV جيد جدًا).

Mimikatz.exe هو على الأرجح أكثر PE اشتباهًا ومعروفًا يتبادر إلى الذهن كمرشح للاستخدام مع Inline-Execute-PE. وجدت أن قدرة Windows Defender على اكتشاف Mimikatz الجاري تشغيله باستخدام Inline-Execute-PE تعتمد على العملية التي يعمل فيها Beacon.

سيتم اكتشاف Beacon يعمل في برنامج مستقل (فكر في beacon.exe مع Artifact Kit بحيث يمكنه التنفيذ والعمل بشكل طبيعي عبر Defender) عند استخدام Mimikatz.exe مع Inline-Execute-PE.

لن يتم اكتشاف Beacon يعمل في عملية ويندوز (محقون في Explorer.exe أو notepad.exe إلخ أو تحميل DLL بشكل جانبي في عملية شرعية) عند استخدام Mimikatz.exe مع Inline-Execute-PE.

فيما يتعلق بـ EDRs التي تقوم بـ userland hooking، كما قلت لم أختبر ولكن لدي الأفكار العامة التالية:

نظرًا لأن الـ PE يعمل داخل عملية Beacon، والتي من المفترض أنك قد أزلت فيها/أنعشت NTDLL بالفعل، أعتقد أنه لا ينبغي أن تواجه مشاكل كبيرة مع استدعاءات API التي يقوم بها الـ PE والتي يتم وضع علامة عليها. لا تزال نفس المشكلات المتعلقة بما يفعله الـ PE فعليًا (لمس العمليات، تغيير مفاتيح التسجيل، إلخ) سارية.

اعتبارات التصميم والتعليقات

قبل بضعة أشهر عثرت على RunPE-In-Memory وفكرت في محاولة تحويله إلى BOF لـ CobaltStrike. الرحلة التي تلت ذلك كانت أكثر تعقيدًا واستغرقت وقتًا أطول بكثير مما كان متوقعًا. كان هذا المشروع صعبًا بشكل خاص لأنه ليس أداة قائمة بذاتها بحد ذاتها، بل هو أداة تستخدم لتشغيل أدوات أخرى. يتطلب هذا قدرًا كبيرًا من المرونة والجهد باتجاه التوافق مع مجموعة واسعة من الـ PEs وجميع الطرق المختلفة التي قد تحقق بها تلك الـ PEs نفس المهمة (الحصول على الوسائط، الإنهاء، إلخ).

في البداية، تم تصور Inline-Execute-PE كـ BOF متكامل، مسؤول عن تحميل وتنفيذ وتحرير PE في Beacon. بعد حوالي 3 أسابيع من المشروع، كنت قد أكملت حوالي 75% من برهان المفهوم (POC)، وجدت Pezor الذي تم إصداره منذ حوالي 1.5 سنة وكان يقوم بالفعل بكل ما كنت أحاول فعله تقريبًا؛ الفرق الرئيسي هو أن Pezor كان يستدعي Donut تحت الغطاء لتحويل الـ PE إلى شيل كود، بدلاً من تعيين الـ PE الأصلي يدويًا في الذاكرة.

كان هذا الاكتشاف مرحبًا به من ناحية ومخيبًا للآمال من ناحية أخرى؛ كان من الرائع وجود مشروع ناضج يمكن استلهام الأفكار منه ومساعدتي في تجاوز بعض النقاط الصعبة في الكود الخاص بي، ولكن كان محبطًا أنني كنت أعيد اختراع العجلة دون علمي. بعد القراءة عن Pezor والتفكير في تصميمه، وبعض الأمور المتعلقة بحرفية العمل (tradecraft)، والاحتياجات التشغيلية لمؤسستي، قمت بتغيير مسار Inline-Execute-PE إلى ما تراه اليوم. كان هذا القرار مدفوعًا بعدة عوامل سيتم مناقشتها أدناه، بالإضافة إلى بعض خيارات التصميم الأكثر فضولًا التي ربما أثارت الدهشة لدى أولئك الذين قرأوا حتى الآن.

Inline-Execute-PE ضد Pezor

عند فحص خبرتي التشغيلية، توصلت إلى حالات وأدوات متعددة حيث كنت بحاجة إلى تشغيل الأداة بشكل متكرر؛ مع Pezor، يجب على المشغل إرسال الـ PE بشكل متكرر عبر الشبكة، وإنشاء conhost.exe، وتخصيص ذاكرة جديدة في Beacon، إلخ، مما بدا لي غير مرغوب فيه عند التفكير في AV/EDR. قادني هذا التفكير إلى فكرة "تحميل" PE في Beacon، على غرار كيفية تحميل .PS1 في Beacon للاستخدام المتكرر. يتم إنشاء conhost.exe عند تحميل الـ PE لأول مرة ويستمر طالما أن الـ PE محمل في الذاكرة؛ وبالمثل، يتم تخصيص ذاكرة جديدة للـ PE مرة واحدة عند تحميله لأول مرة، وبالطبع تتجنب الحاجة إلى إرسال الـ PE عبر الشبكة في كل مرة تريد استخدامه. النموذج الذي اعتمده Inline-Execute-Pe ليس خالياً من العيوب، والتي حاولت معالجتها بدرجات متفاوتة من النجاح.

نسختان من الـ PE

يجب أن يلفت الانتباه خيار التصميم المتمثل في أن Inline-Execute-Pe يقوم بتعيين الـ PE في Beacon مرتين. هذا بالتأكيد ليس مرغوبًا أو خيارًا اتخذته عن طيب خاطر، بل وُلد من الضرورة. كما ذكرنا سابقًا، يجب على Inline-Execute-Pe ربط العديد من الوظائف المتعلقة بوسائط سطر الأوامر في الـ PE. نظرًا لأن الـ PE المُخطط يعمل داخل عملية Beacon، سيحاول الـ PE استخدام وسائط سطر الأوامر المحددة في قسم PROCESS_PARAMETERS من PEB؛ لتجاوز ذلك، عندما يستدعي الـ PE إحدى الوظائف المختلفة التي تسترجع وسائط سطر الأوامر، يجب علينا توجيه الـ PE إلى وظائفنا المخصصة حيث يمكننا تقديم الوسائط المقصودة كما تم تمريرها من CobaltStrike باستخدام perun.

يعمل هذا بشكل جيد، لكن خلال التطوير لاحظت شيئًا غريبًا مع العديد من الـ PEs المختلفة. في المرة الأولى التي يتم فيها تشغيل الـ PE، تم استدعاء الوظيفة المخصصة التي قدمناها لـ IAT الخاصة بالـ PE بشكل صحيح، ولكن في جميع المرات اللاحقة التي تم فيها تشغيل الـ PE وتم تقديم وسائط مختلفة، لم يستدعي الـ PE الوظيفة المخصصة وبالتالي لم يتلق الوسائط الممررة من CobaltStrike. لست متأكدًا مما يحدث بالفعل تحت الغطاء، لكنني أميل إلى الاعتقاد أنه بعد تشغيل الـ PE مرة واحدة، يقوم بنسخ وسائط سطر الأوامر في مكان ما في الذاكرة، وفي عمليات التشغيل اللاحقة ينظر إلى ذلك الموقع في الذاكرة أولاً قبل استدعاء الوظائف المرتبطة لاسترجاع وسائط سطر الأوامر كما فعل في المرة الأولى. لقد دعمت هذه النظرية عن طريق استرجاع الموقع في الذاكرة حيث يوجد مؤشر لمؤشر آخر لمصفوفة المؤشرات التي تحتوي على الوسائط، وتعديل هذا الموقع يدويًا في الذاكرة ليحتوي على المؤشر الصحيح في كل تشغيل. نجح هذا مع وظائف __getmainargs و __wgetmainargs، لكن الـ PEs الأخرى تستدعي وظائف بديلة مثل __p___argv و __p___argc والتي لم تعمل معها هذه الطريقة.

لكي أتمكن من "إعادة ضبط" الـ PE إلى حالة يستدعي فيها الوظائف المرتبطة فعليًا لجلب الوسائط، لجأت إلى إنشاء نسخة ثانية من الـ PE في الذاكرة أثناء peload. هذه النسخة مشفرة أيضًا بـ XOR وتجلس بحماية RX طوال دورة حياة Inline-Execute-PE، ويتم استخدامها ببساطة لاستبدال نسخة الـ PE التي يتم تنفيذها فعليًا باستخدام perun. كما ذكرنا، إنه ليس حلاً مثاليًا، لكنه حل شامل يغطي جميع الـ PEs دون الحاجة إلى الضياع في التفاصيل الدقيقة لمحاولة التوصل إلى حل لجميع الـ PEs المختلفة وواجهات برمجة التطبيقات المختلفة التي تستخدمها.

Conhost.exe

مع أن أحد أهم نقاط البيع لـ Inline-Execute-Pe هو أنه يمكنك تشغيل الأدوات دون إنشاء عمليات جديدة، فإنها ضربة قوية لدرجة أنني مضطر إلى ... إنشاء عملية جديدة (conhost.exe) للقيام بذلك. يأتي هذا المطلب من حقيقة أن التدفقات القياسية (stdin/stdout/stderr) لا يتم تهيئتها في برامج ويندوز ما لم يكن هناك وحدة تحكم (console). في حالتنا لا نحتاج إلى وحدة التحكم على الإطلاق؛ يتم إعادة توجيه التدفقات القياسية إلى أنبوب مجهول والتقاطها بهذه الطريقة، ولكن بدون conhost لا يتم تهيئة التدفقات ولا يمكن إعادة توجيهها.

يتعامل Inline-Execute-Pe مع مشكلة conhost بنفس الطريقة التي يتعامل بها Pezor، حيث يستدعي AllocConsole ثم يخفيها على الفور عن العرض باستخدام ShowWindow. على جهاز افتراضي يعمل بنظام Windows 11 مع 8 جيجابايت من ذاكرة الوصول العشوائي، لا أرى أبدًا نافذة وحدة التحكم تومض ثم تختفي، لكن المسافة المقطوعة ستختلف بناءً على النظام الهدف.

تحدثت مع مطور يعمل على C2 تجاري متقدم جدًا أصدر مؤخرًا ما يعادل محليًا (حسنًا، إصدار أكثر تقدمًا بكثير) من Inline-Execute-Pe، وأخبرني أنهم تمكنوا من تجنب إنشاء conhost.exe عن طريق "خداع ويندوز لتعتقد أن لديها وحدة تحكم". مع هذه المعلومة، قضيت حوالي أسبوع في البحث في الإنترنت عن وثائق حول كيفية تفاعل برامج ويندوز مع conhost، محاولاً تتبع استدعاءات API المرتبطة بوظائف الكتابة ووحدة التحكم في WinDBG، وحتى فحص شفرة مصدر Windows Terminal المتاحة بشكل مدهش على Github. بينما تعلمت الكثير عن PEB والأشياء المتعلقة بالتدفق القياسي، خرجت من الجانب الآخر من هذا خالي الوفاض. أشتبه في أن الطريق إلى الأمام قد يتضمن تصحيح وظائف معينة متعلقة بوحدة التحكم في kernel32 لكني لا أعرف. أنا صادقًا أشعر بخيبة أمل كبيرة لعدم تمكني من إيجاد حل هنا، ولكن كونني علمت نفسي بنفسي وفقط بضع سنوات في مسيرتي المهنية، فمن المحتمل أن يكون متوقعًا.### مهلة PE والإنقاذ جميع الذين حاولوا كتابة BOF يعلمون أنه رغم كل المزايا المصاحبة لها، يكمن خطر كبير في حقيقة أن خطأ أو تعطل في BOF الخاص بك يمكنه بل وسيقتل Beacon الخاص بك. ويتضاعف الخطر في هذا المشروع بسبب طبيعة مقدار التحكم الذي يتمتع به المستخدمون في البيانات التي يتم تمريرها إلى Inline-Execute-PE وقلة إجراءات السلامة التي يمكنني كمطور وضعها بسهولة أو بشكل موثوق. يمكن للمستخدمين مثلاً تعطيل Beacon الخاص بهم عن طريق تحميل PE خاص بمعمارية x86 في Beacon بمعمارية x64، أو بشكل أكثر شيوعاً عن طريق تمرير وسائط غير صحيحة إلى PE المُعيّن كما أشرت سابقًا. بينما لا أستطيع منع المستخدمين من تعطيل Beacons الخاصة بهم بوسائط خاطئة لـ PE الخاصة بهم، يمكنني محاولة إنقاذ Beacon الخاص بهم في حالة تشغيل PE بشكل لا نهائي، كما في حالة Mimikatz عندما لا يتم تحديد 'exit'.

من الناحية المثالية، أود أن أكون قادرًا على إيقاف تنفيذ PE، مما يسمح لـ Beacon باستئناف وظيفته الطبيعية، ثم السماح للمستخدم فورًا بإعادة المحاولة مع الوسائط الصحيحة (على أمل) هذه المرة. عمليًا، وجدت أن إنهاء PE يبدو أنه يكسر FILE* المرتبطة بـ stdout/stderr، وحتى تفريغ PE بالكامل ثم تحميله من جديد لا يحل هذه المشكلة؛ فهي معطلة على مستوى العملية بأكملها.

لإنهاء PE الذي يستمر في التشغيل بعد تجاوز خيار 'timeout'، يتم استدعاء TerminateThread على المعالج الذي تم إرجاعه من CreateThread. هذا لا يسمح للخيط بالخروج بأمان من أي شيء، لذلك من المنطقي أن بعض الأشياء قد تنكسر. حاولت التخفيف من ذلك عن طريق تطبيق اختطاف الخيوط، بهدف تعليق خيط PE وتوجيه تنفيذه إلى API ExitThread(). كان الأمل هنا أنه إذا كان الخيط هو الذي بدأ إجراءات الخروج (بدلاً من إنهائه بالقوة من الخارج)، فقد يؤدي ذلك إلى استمرار عمل stdout/stderr، لكن انتهى بي الأمر بنفس المشكلة (بالإضافة إلى عدم القدرة على تعليق خيط PE في حالة Mimikatz).

نظرًا لعدم تمكني من تخفيف هذه المشكلة، استقررت ببساطة على منع المستخدمين من الاستمرار في تشغيل PE أو تحميل PEs إضافية في Beacon المتأثر (مما سيؤدي إلى تعطل). هذه حالة أخرى حيث يقصر Inline-Execute-PE عن المستوى الذي أريده، لكنني اقتنعت بحقيقة أن المشغل سيظل على الأقل يحتفظ بـ Beacon الخاص به ويمكنه استخدامه للوظائف العادية.

هيكل بيانات Inline-Execute-PE

كان الجزء الصعب في هذا المشروع هو ضمان توفر PEs المُحمّلة في Beacons لجميع عملاء CobaltStrike المتصلين بخادم الفريق. يتم تخزين بيانات Inline-Execute-PE في هياكل تم إنشاؤها بواسطة Inline-Execute-PE.cna، والتي يجب تحميلها في كل عميل يرغب في استخدام الأداة؛ ونتيجة لذلك، تعيش هياكل البيانات هذه داخل كل عميل، وليس على خادم الفريق. إذا كانت هذه البيانات موجودة في موقع مركزي واحد (خادم الفريق) لكان من السهل استرجاعها من كل عميل وسيكون هذا الموضوع برمته غير ذي أهمية؛ لو قام فريق CobaltStrike بدمج إمكانية مثل Inline-Execute-PE رسميًا في CobaltStrike، فأنا متأكد أنهم سيسلكون هذا الاتجاه. ولكن نظرًا لأن هذه إضافة مجتمعية، فإننا نتعامل بما لدينا.

هناك عدة سيناريوهات مختلفة يجب أن نقلق بشأنها فيما يتعلق بضمان حصول كل عميل CobaltStrike على أحدث البيانات الدقيقة حول PEs المُحمّلة في Beacons:

  1. عملاء جدد يتصلون بخادم الفريق ويحتاجون إلى petable الحالية
  2. حالات حيث يتصل عميل واحد فقط بخادم الفريق ويعيد تشغيل CobaltStrike (وبالتالي يفقد petable المخزنة في ذاكرة العميل)
  3. العميل A يقوم بتغيير في بيانات Inline-Execute-PE والتي يجب إبلاغ العميل B بها

تم اتخاذ نهج متعدد الجوانب لمعالجة هذه السيناريوهات. للتعامل مع حالة اتصال عميل CobaltStrike واحد فقط بخادم الفريق (وبالتالي هو الكيان الوحيد الذي لديه بيانات petable)، في كل مرة يقوم العميل بتعديل petable (peload، peconfig، peunload، إلخ)، فإنه يكتب أيضًا محتويات petable الخاصة به إلى ملف نصي محلي موجود في دليل CobaltStrike. إذا خرج العميل/أعاد التشغيل، أو عند إعادة تحميل Inline-Execute-PE.cna، فإنه سيحاول أولاً القراءة من ملف petable.txt المحلي لتعبئة petable في الذاكرة.

عندما يكون عدة عملاء متصلين بخادم الفريق وينضم عميل جديد (وفقاً لسجل الأحداث)، يقوم كل عميل بجلب قائمة بجميع المستخدمين المتصلين بخادم الفريق وفرزها أبجديًا. يتم اختيار العميل الأول في تلك القائمة كـ "بث" العميل، وبعد الانتظار لمدة 5 ثوانٍ (للسماح للعميل الجديد بالتهيئة وقراءة ملف petable.txt المحلي الخاص به)، سيرسل رسائل (إجراءات) في سجل الأحداث لكل إدخال في petable الخاصة به. جميع العملاء (باستثناء العميل الذي يبث) سيقرؤون هذه الرسائل ويحدّثون petables الخاصة بهم بمعلومات البث؛ يتضمن ذلك تحديث الإدخالات الحالية بالإضافة إلى إضافة أي إدخالات إضافية لا تحتويها petables الخاصة بهم.

تعتمد العمليات العادية التي تتضمن Inline-Execute-PE أيضًا على إرسال رسائل في سجل الأحداث. عندما يقوم العميل A بتشغيل peload، يتم بث رسالة تحتوي على جميع معلومات petable ذات الصلة؛ يقوم جميع العملاء بتحديث petables الخاصة بهم عن طريق تحليل رسائل سجل الأحداث المُبثّة هذه باستخدام خطاف "on Event_Action". يتم أيضًا إجراء تغييرات على بيانات Inline-Execute-PE عند انتهاء تنفيذ BOFs لكل من peload و peunload؛ يتم إبلاغ هذه التغييرات مرة أخرى بواسطة Beacon (على سبيل المثال، بعد تشغيل peload، يتصل Beacon مرة أخرى بموقع الذاكرة لهيكل pMemAddrs) وبالتالي فهي مرئية لجميع العملاء المتصلين، الذين يقومون بتحديث petables الخاصة بهم باستخدام خطاف "on Beacon_Output".

تؤدي هذه الجهود المنفصلة مجتمعة إلى قدرة Inline-Execute-PE على مزامنة البيانات الهامة بكفاءة وموثوقية بين عدة عملاء.

الإسهامات

لم يكن هذا المشروع ممكنًا لولا المشاريع والموارد التالية التي تم الرجوع إليها بشكل كبير والتي نشأت منها الأجزاء الأساسية لهذا المشروع. شكر كبير للمؤلفين على كودهم ورؤيتهم.

  1. RunPE-In-Memory
  2. Pezor
  3. الكثير من StackOverflow
تنزيل الأداة