TL؛ DR
قطعة أثرية من مافن سنترال نُشرت باسم io.github.davidtimur:c2-lab تم إصدار تسعة إصدارات، ثمانية منها نفذت حمولة وصول عن بُعد أثناء تجميع أي مشروع لاحق وضع ملف JAR في مسار معالج التعليقات التوضيحية الخاص به. لم يكن مطلوبًا من أي كود تطبيق استيراده، ولم يكن مطلوبًا من أي سطر من التعليمات البرمجية الإشارة إليه. لم يكن هناك برنامج نصي للتثبيت، ولا ما يعادله بعد التثبيت، ولا أي نوع من أنواع خطافات دورة الحياة التي يمكن للأدوات فحصها.
متجه التنفيذ عبارة عن ملف واحد بحجم 46 بايت داخل ملف jar: وهو عبارة عن تسجيل لموفر خدمة Java يحدد اسم فئة تُنفذ javax.annotation.processing.Processorيكتشف مُصرّف جافا هذه التسجيلات تلقائيًا. بمجرد العثور عليها، javac يقوم بإنشاء وتشغيل الفئة كجزء طبيعي من عملية التجميع. هذا يعني أن بيئة تشغيل الحمولة هي جهاز البناء، وفي الوقت الحالي يقوم جهاز البناء بالمهمة الوحيدة التي وُجد من أجلها.
على مدار الإصدارات التسعة، أُعيد بناء قناة التحكم والتوجيه ثلاث مرات: عنوان URL للردّ المُقدّم من المُشغّل، ثم جلسة تحكم عكسية عبر نفق TCP من نوع ngrok، ثم قناة استطلاع HTTP التي تغيّرت مساراتها مرتين إضافيتين. وقد قام الإصدار الأخير بتثبيت مدير ثقة TLS لا يقوم بأي عمليات كإعداد افتراضي لـ JVM. قبول أي شهادة طوال مدة التجميع.
احتوت الأداة على عبارة "حمولة مختبر التحكم والسيطرة" في ملف POM الخاص بها، بالإضافة إلى ترخيص MIT. وكانت متاحة على Maven Central طوال فترة مراقبتنا لها. تمت إزالته منذ ذلك الحين، إلى جانب كامل محتواه. io.github.davidtimur المجموعة.
التشريح: المترجم كمحرك تنفيذ
يُتيح إطار معالجة التعليقات التوضيحية في جافا للمكتبات إمكانية توليد التعليمات البرمجية أثناء وقت الترجمة - وهي الآلية التي تقوم عليها أدوات مثل Lombok وDagger، بالإضافة إلى قائمة طويلة من أدوات ORM وأدوات التسلسل. يُعلن المعالج عن نفسه من خلال ملف نصي عادي داخل ملف JAR.
META-INF/services/javax.annotation.processing.Processor
محتويات ذلك الملف في كل إصدار متأثر، حرفياً وكاملاً:
io.github.davidtimur.c2lab.C2Processor
الملف متطابق تمامًا من حيث البايتات عبر الإصدارات من 1.0.1 إلى 1.0.8، md5 7d2a08a5c8869a47eea9fa62487dfbe4. الإصدار 1.0.0 لا يحتوي عليه.
متى جافاك عند تشغيله، يقوم بفحص مسار معالج التعليقات التوضيحية بحثًا عن مدخلات الخدمة هذه، ثم يقوم بتحميل ما يجده. لا يحتاج أي جزء من المشروع الذي يتم تجميعه إلى ذكر المعالج، أو إضافة أي تعليقات توضيحية، أو تهيئة أي شيء. يكفي وجوده في المسار. هذه هي الخاصية التي تميز JavacDoor عن أنماط سلسلة التوريد التي تُبنى عليها معظم الأدوات.
| نمط | تحفيز عملية | مرئي كـ |
|---|---|---|
| npm install hook | npm install | scripts.postinstall في البيان |
| حمولة وقت الاستيراد في بايثون | أول استيراد للوحدة | بيان على مستوى الوحدة في المصدر |
| جافاكدور | javac في أي مشروع لاحق | اسم ملف تسجيل الخدمة |
خطاف التثبيت هو تعريف في ملف البيان، وملف البيان هو أول ما يقرأه المستخدم. على الأقل، توجد حمولة وقت الاستيراد في مصدر قابل للقراءة. أما تسجيل الخدمة فليس كذلك: إنه اسم ملف بالإضافة إلى سطر واحد يُسمي فئة، ويوجد سلوكها في بايت كود مُجمَّع في مجلد آخر.
تقوم فئة الحمولة نفسها باستطلاع المضيف عن طريق إرسال أوامر خارجية. تحتوي مجموعات الثوابت للفئات المُجمَّعة على / بن / ش, whoami, uname -a, الأشخاص ذوي الإعاقة على مسار يونكس و قائمة المهام في مسار ويندوز، بالإضافة إلى إعادة توجيه دفق الخطأ لدمج مخرجات أخطاء العملية الفرعية في التدفق الملتقط. ينقل نموذجان من JSON النتائج من المضيف - منارة تسجيل:
{"host":"%s","os":"%s","user":"%s","dir":"%s"}
مأهول من اسم المضيف القيادة و اسم النظام, user.nameو دليل المستخدم خصائص النظام، ودالة رد الاتصال بالنتيجة:
{"version":"%s","host":"%s","time":"%s","output":"%s"}
تتميز علامات التقدم الموجودة في مخرجات المترجم بصراحتها غير المعتادة: [C2] اكتمل التنفيذ في وقت الترجمة, [C2] تم إرسال رد الاتصال → HTTP , [C2] تم الاتصال بالصدفة .
تسعة إصدارات، ثلاثة أجيال من C2
لا تمثل عمليات الإصدار تسع نسخ من حمولة واحدة. إنها سجل تكراري، وقراءتها بالترتيب تُظهر إعادة بناء القناة بينما ظل متجه التسليم ثابتًا.
| الإفراج عن | يتم التنفيذ تلقائيًا عند التجميع | قناة |
|---|---|---|
1.0.0 | لا (لا يوجد ملف خدمة) | عنوان URL لإعادة التوجيه المقدم من المشغل فقط |
1.0.1 | نعم (تم إدخال المتجه) | عنوان URL لإعادة التوجيه المقدم من المشغل |
1.0.2 | نعم | غلاف عكسي، نفق TCP من نوع ngrok |
1.0.3 | نعم | قناة HTTP، /register /cmd /out |
1.0.4 | نعم | قناة HTTP، /register /cmd /out |
1.0.5 | نعم | قناة HTTP، /register /poll /out |
1.0.6 | نعم | قناة HTTP، /register /poll /out |
1.0.7 | نعم | قناة HTTP، /register /cmd |
1.0.8 | نعم | تم تعطيل التحقق من صحة قناة HTTP وTLS |
ثلاثة تفاصيل في ذلك الجدول تستحق التوضيح، لأن كل منها يغير كيفية قراءة مجموعة القطع الأثرية.
يصل المتجه إلى 1.0.1، وليس 1.0.2. يحتوي الإصدار 1.0.0 على نفس منطق الاستطلاع والاستدعاء، ولكنه لا يحتوي على ملف خدمة ولا استيراد لمعالجة التعليقات التوضيحية؛ فهو يعمل فقط عند استدعائه. بدءًا من الإصدار 1.0.1، أصبح ملف الخدمة موجودًا، ويتم استيراد الفئات المُجمَّعة. javax.annotation.processing.SupportedSourceVersionإن أي تقييم يقارن بين الإصدارين المدفوعين - 1.0.0 و 1.0.2 - يخلص بشكل صحيح إلى أن شيئًا ما قد تغير، لكنه يخطئ في تحديد مكانه.
توجد خاصية الصدفة العكسية في إصدار واحد فقط. يحتوي الإصدار 1.0.2 على 0.tcp.ngrok[.]io، سطر السجل [C2] تم الاتصال بالصدفة على 0.tcp.ngrok[.]io:19823، لافتة تفاعلية c2-shellوفاصل إطار __نهاية__لا تحتوي الإصدارات من 1.0.3 فصاعدًا على أي من هذه الميزات، بل تتصل بخادم HTTPS. كان من شأن طلب إزالة الخدمة الذي يقتصر على ذكر الإصدارات المُعلَن عنها فقط أن يشير إلى نقطة نهاية TCP معطلة، بينما يتجاهل قناة HTTP النشطة، الموجودة في ستة إصدارات لاحقة.
الإصدار النهائي يزيل التحقق من النقل. يُضيف الإصدار 1.0.8 فئةً تُنفّذ javax.net.ssl.X509TrustManager لا تفعل طرق التحقق من الشهادات الخاصة بها شيئًا، وهو مدقق اسم مضيف صحيح دائمًا مسجل من خلال setDefaultHostnameVerifier، و ثقة الجميع روتين يقوم بتثبيت كليهما كإعدادات افتراضية لآلة جافا الافتراضية. والنتيجة هي أنه خلال ما تبقى من عملية التجميع، تقبل آلة جافا الافتراضية أي شهادة من أي مضيف - ليس فقط لحركة مرور الحمولة نفسها، ولكن لأي شيء آخر يقوم به البناء عبر بروتوكول TLS لاحقًا.
قناة HTTP، في جميع الإصدارات الستة التي تستخدمها، تتم إدارتها بواسطة مضيف واحد: tableful-fervor-crazed.ngrok-free[.]devكل طلب يحمل رأس الطلب ngrok-skip-browser-warningوهذا ما يمنع ظهور الصفحة الوسيطة التي توفرها أنفاق ngrok المجانية للمتصفحات. وتختلف مسارات الملفات بين الإصدارات. /خارج يختفي عند الإصدار 1.0.7، و / كمد يتناوب مع /استطلاع لكن المضيف لا يتغير أبداً.
علامة الاستبعاد الذاتي
كل ملف POM بدءًا من الإصدار 1.0.1 فصاعدًا يحدد وسيطة للمترجم لبناء العنصر الخاص به:
-proc:none
يؤدي هذا الخيار إلى تعطيل معالجة التعليقات التوضيحية. تأثيره هنا هو ما قبلcisهـ: عندما يتم تجميع المشروع الذي يحتوي على المعالج نفسه، فإن المعالج لا يعمل.
لهذا الخيار استخدامات عادية تمامًا. غالبًا ما يحتاج المشروع الذي يتضمن معالجًا للتعليقات التوضيحية إلى تجنب تطبيق هذا المعالج على نفسه أثناء عملية التهيئة، وتوصي وثائق أدوات البناء بذلك تحديدًا. لكن استخدامه بمفرده لا يُثبت شيئًا.
مع ذلك، وبالنظر إلى وظيفة المعالج، يتضح وجود خلل محدد: يُنفذ الكود على أجهزة كل من يقوم بتجميع البرنامج باستخدام هذا العنصر، وليس على الجهاز الذي يُنشئه. يظهر هذا الخيار في الإصدار نفسه الذي يُقدم ملف الخدمة - 1.0.1 - وفي كل إصدار لاحق. يُعد الارتباط بين "الإصدار الذي يبدأ فيه تنفيذ وقت التجميع" و"الإصدار الذي يُعطل فيه تنفيذ وقت التجميع محليًا" أهم مؤشر تحليلي في مجموعة العناصر، ويمكن رؤيته في ملف POM نصي عادي دون الحاجة إلى فك تجميع أي شيء.
نلاحظ التأثير ونتوقف عند هذا الحد. لا يوجد في القطع الأثرية ما يشير إلى سبب وضع العلم.
هناك معلومة وصفية أخرى جديرة بالذكر، وإن كان ذلك للتخلص منها في الغالب. يُطلق على المشروع اسم "حمولة مختبر القيادة والسيطرة"، ويصفه بأنه "منتج من حمولات مختبر القيادة والسيطرة"، ويرخصه بموجب ترخيص MIT. يُستخدم هذا النوع من التسمية الذاتية أحيانًا كدليل على أن الحزمة عبارة عن تمرين بحثي.cisبدلاً من أن يكون تهديدًا حقيقيًا، وأحيانًا يكون هذا التفسير صحيحًا - فبرنامج تجريبي مُعلن عنه بدون بنية تحتية قابلة للوصول يختلف عن هذا. لا ينطبق هذا هنا. إن برنامجًا برمجيًا وظيفيًا منشورًا في مستودع عام، يمكن لأي مستخدم الوصول إليه، مع بنية تحتية خارجية أُعيد بناؤها ثلاث مرات عبر تسعة إصدارات، يُعدّ قدرةً حقيقية بغض النظر عما تُسميه بياناته الوصفية. لا يُغيّر الاسم في ملف POM شيئًا مما يحدث على الجهاز الذي يُجمّع البرنامج ضده.
مؤشرات لآلات البناء
إذا قام مضيف البناء بالتجميع مقابل هذه القطعة الأثرية، فإن الدليل موجود في سجلات البناء وقياسات الشبكة بدلاً من زرع دائم على القرص - يتم تشغيل الحمولة داخل عملية التجميع وتخرج معها.
في ملف jar أو ذاكرة التخزين المؤقت للمستودع المحلي
META-INF/services/javax.annotation.processing.Processorتسميةio.github.davidtimur.c2lab.C2Processor- ملف الخدمة md5
7d2a08a5c8869a47eea9fa62487dfbe4 - الفئات التابعة
io/github/davidtimur/c2lab/:C2Processor,C2Task,Taskوفي الإصدار 1.0.8 الفئة الداخليةTask$1
في مخرجات البناء
[C2] compile-time execution complete[C2] callback sent → HTTP[C2] callback failed:[C2] shell connected to- لافتة تفاعلية
c2-shellفاصل الإطار__END__
القياس عن بعد أثناء العملية
javacبصفته أحد الوالدين لـ/bin/sh -c(يونكس) أو مترجم أوامر ويندوز- أوامر الطفل
whoami,uname -a,pwd(يونكس) أوtasklist(ويندوز) تابع لخطوة تجميع
في مجال قياس بيانات الشبكة
- TCP الصادر إلى
0.tcp.ngrok[.]io:19823(الإصدار 1.0.2) - HTTPS إلى
tableful-fervor-crazed.ngrok-free[.]devالمسارات/register,/cmd,/poll,/out(الإصدارات من 1.0.3 إلى 1.0.8) - رأس الطلب
ngrok-skip-browser-warning: true - جهات الطلب المطابقة
{"host":...,"os":...,"user":...,"dir":...}or{"version":...,"host":...,"time":...,"output":...}
في التكوين
- متغيرات البيئة
CALLBACK,CALLBACK_URLخاصية النظامcallback.url
بيانات تعريف الناشر
- تجمع
io.github.davidtimurعنوان الناشرdavudboi999@gmail[.]comمفتاح التوقيعE520C345EF94423D
يتطلب الإصدار الذي تم تشغيله باستخدام الإصدار 1.0.8 فحصًا إضافيًا. نظرًا لأن هذا الإصدار يُثبّت مدير ثقة متساهلًا كإعداد افتراضي على مستوى JVM، فإن أي اتصال TLS يتم لاحقًا في نفس JVM - مثل حل التبعيات، أو تحميل الملفات، أو خطوة النشر - يتم دون التحقق من صحة الشهادة. لذا، لا ينبغي افتراض أن حركة البيانات من تلك النافذة مُصادق عليها.
لماذا تحتاج القطع الأثرية المجمعة إلى مسح ضوئي مختلف
يُعد JavacDoor حالة اختبار مفيدة لأنه يهزم افتراضين شائعين في آن واحد، ولا يرتبط أي من الفشل بأدوات أي بائع معين.
الافتراض الأول هو أن الكود الخطير يعلن عن نفسه في ملف البيان. يتم تنظيم قدر كبير من أدوات سلسلة التوريد وفقًا لدورة الحياة hooksلأنّ هذا هو المكان الذي تجري فيه العمليات عادةً في npm وPyPI. لا يحتوي JavacDoor على خطاف. مُشغّله هو ملف تسجيل خدمة، اسمه واجهة Java ومحتواه اسم فئة. لالتقاط ذلك بشكل ثابت، عليك التعامل معه META-INF/services/javax.annotation.processing.Processor باعتبارها نقطة دخول تنفيذية بحد ذاتها، على قدم المساواة مع بعد التثبيت ثم تتبع الفئة المسماة إلى رمز البايت. تمتلك الأنظمة البيئية آليات اكتشاف تلقائي خاصة بها بهذا الشكل، وكل منها يمثل نقطة دخول سواء أكانت الأدوات تُدرجها على هذا النحو أم لا.
الافتراض الثاني هو أن السلاسل النصية موجودة في ملفات المصدر. بالنسبة لملف JAR، فإن نقاط النهاية، وأوامر الصدفة، وقوالب JSON، وعلامات السجل كلها موجودة في مجموعات الثوابت الخاصة بـ .صف دراسي الملفات. لا تجد أدوات البحث عن النصوص أي شيء - ليس لأن السلاسل مشفرة، بل لأنها موجودة في حاوية ثنائية منظمة لا يمكن لمسح النصوص تحليلها. كل مؤشر شبكة في هذه المقالة ناتج عن تحليل مجموعة الثوابت. أحدها عبارة عن ملف كامل التكوين https:// عنوان URL موجود بشكل واضح داخل ملف فئة؛ حتى عند فحص محتوى ملف JAR القابل للقراءة، لن يظهر. لا توجد عملية تشفير هنا، بل مجرد تنسيق حاوية للقراءة.
تتشابه الثغرتان في الشكل: فقد تم التعامل مع تنسيق العنصر البرمجي كمجموعة من الملفات بدلاً من كونه بنية ذات دلالات محددة. والحل بسيط وغير جذاب - تحليل الحاوية، وحصر نقاط الدخول للاكتشاف التلقائي للنظام البيئي، وتتبعها إلى الكود المُجمَّع. بالنسبة لمتجهات وقت الإنشاء تحديدًا، يُعد الفحص الثالث بسيطًا وتشخيصيًا بشكلٍ مدهش: مقارنة ما يفعله العنصر البرمجي للمستخدمين بما يستثنيه من ذلك. فالعنصر البرمجي الذي يُسجِّل معالج وقت الإنشاء ويُعطِّل في الوقت نفسه معالجة وقت الإنشاء لبنائه الخاص، يُخبرك بشيءٍ ما عن نفسه في سطرين من ملف POM النصي.
بالنسبة للفرق التي تستخدم مكونات Maven اليوم، إليكم ثلاثة إجراءات عملية:
- تعامل مع مسار معالج التعليقات التوضيحية كحدود تنفيذ. تُشغّل التبعيات الموجودة هناك التعليمات البرمجية في عملية البناء. في الحالات التي لا تتطلب فيها عملية البناء معالجة التعليقات التوضيحية، -proc:none وهو مفيد دفاعيًا كما كان على ما يبدو محليًا هنا؛ وعندما يكون كذلك، قم بتثبيت مجموعة المعالج بشكل صريح بدلاً من وراثتها من مسار فئة التجميع.
- عمليات فرعية لمترجم السجلات. تعتبر خطوة التجميع التي تؤدي إلى إنشاء shell أمرًا شاذًا في معظم المشاريع ويمكن تنبيهها بسهولة.
- لا تتعامل مع البيانات الوصفية كشهادة. إنّ كلمات "المختبر" و"الاختبار" و"الحمولة" و"إثبات المفهوم" في اسم الحزمة أو وصفها لا تُعدّ حدوداً لنطاقها، بل إنّ إمكانية الوصول إليها وسلوكها هما الحدود.
تم إزالة القطعة الأثرية ومجموعتها بالكامل من مخضرم بعد تقريرنا، أصبح كل من مسار العنصر ومسار المجموعة يُرجعان الآن رمز الخطأ 404، ولا يُشير فهرس المركز إلى أي إحداثيات مطابقة. هذا يُغلق هذا العنصر. لكنه لا يُغلق المتجه، وهي ميزة موثقة في مُترجم جافا ومتاحة لأي شخص ينشر ملف JAR.
مراجع حسابات
لا يستند هذا المنشور إلى أي مصادر خارجية. جميع النتائج عبارة عن تحليل ثابت مباشر للملفات التسعة المنشورة، والتي تم استرجاعها من مستودع Maven المركزي قبل حذفها. لم يتم تنفيذ أي كود من هذه الملفات في أي مرحلة.







