TL؛ DR
مجموعة من خمس حزم npmتم نشرها عبر حسابين، وتم شحنها postinstall خطاف يقرأ بيانات اعتماد السحابة من المضيف ويرسلها خارج الجهاز. تحمل الحزم أسماء وهمية وأسماء مستخدمين مقرصنين. coral-wraith, ecto-corsair-whisper-6f3b9, ecto-corsair-flag-x9m4, ecto-rust-read-f3a9c1, ecto-nightly-spirit — ويقومون بتحويل كل ما يجمعونه إلى سلسلة مزيفة ecto_module: نقوم بفحص ملف YAML قبل إرساله. ونتتبع أداء المجموعة كما يلي: الجبلة الخارجية.
لا يتم تشغيل الحمولة إلا عند اكتشاف بيئة محددة: مضيف اسمه a سلسلة سداسية عشرية مكونة من 12 حرفًا ودليل عمل تحت /app/node_modules — شكل عملية بناء مُحاوية أو عامل تكامل مستمر. عند اجتياز هذه البوابة، يستعلم الخطاف عن خدمة بيانات تعريف مثيل AWS (IMDSv2) بالنسبة لبيانات اعتماد دور إدارة الهوية والوصول، يتم تعدادها. مدير أسرار AWS عبر ثلاث مناطق، يقوم بتفريغ متغيرات البيئة، ويقرأ الملفات الموجودة تحت /appويقوم باستخراج سلاسل "التقاط العلم". ثم يقوم بتسريب النتيجة بطريقتين: منارة إلى webhook.site جامع وبيان PUT إلى نقطة نهاية عنوان IP الخام، مع قائمة بالخيارات الاحتياطية التي تبدأ بالمضيف المحلي.
تصف الحزم اللاحقة بأنها "حمولة CTF لاختبار سلسلة توريد Verdaccio". ونُبلغ عن هذا الوصف الذاتي كحقيقة قابلة للملاحظة. أما السلوك نفسه - اتصال مباشر بعنوان IP عام، وقراءة بيانات اعتماد IMDS حقيقية، واستدعاءات حقيقية لمدير الأسرار - فهو ما هو عليه بغض النظر عن التصنيف، وهو السبب في تصنيف هذه الإصدارات على أنها خبيثة.
اسم واحد في المجموعة، coral-wraithلم يتوقف الأمر عند إصدار واحد، بل أعيد نشره بسرعة عبر عشرات الإصدارات في غضون ساعات قليلة. 1.0.0 التسلق إلى 6.0.0 — وقد استخدمت نسخة سابقة تحمل نفس الاسم مصطلحات متضخمة 9999.0.x أرقام الإصدارات، الشكل الكلاسيكي لـ محاولة إرباك التبعية. خلال تلك العملية، نضجت الحمولة بشكل واضح: من منارة تعداد المضيف لمرة واحدة إلى محور بيانات اعتماد AWS كامل مغلف بفحوصات بيئية تحافظ على هدوئها خارج هدفها المقصود.
| الباقات | خمسة أسماء؛ coral-wraith أعيد نشرها وحدها عبر عشرات الإصدارات |
| النظام الإيكولوجي | الآلية الوقائية الوطنية |
| تثبيت المتجهات | postinstall نص دورة الحياة |
| الهدف الأساسي | بيانات اعتماد دور AWS IAM + قيم أسرار مدير الأسرار، ومتغيرات البيئة، /app ملفات |
| خروج | webhook.site إرسال إشارة + عنوان IP خام إلى خادم التحكم عن بعد |
| بوابة التشغيل | اسم المضيف المكون من 12 خانة سداسية عشرية + /app/node_modules دليل العمل الحالي، بالإضافة إلى فحص بيئي يمنع وصول البيانات خارج هذا السياق |
| خطورة | عالي — الكشف عن بيانات اعتماد السحابة والأسرار المُدارة من بيئات بناء وتشغيل معزولة في حاويات |
تشريح الهجوم
يتم بناء كل حزمة في المجموعة بنفس الطريقة: شبه فارغة index.js (module.exports = {}), سطر واحد package.json نص — "postinstall": "node postinstall.js" — والحمولة في postinstall.jsيكفي تثبيت الحزمة لتشغيل الخطاف؛ لا يلزم استيراد أو استدعاء.
بوابة الاستهداف. قبل القيام بأي شيء، تقوم حمولة عائلة إكتو بفحص محيطها:
function isAppWorker(): host = os.hostname() if host does NOT match /^[0-9a-f]{12}$/ -> exit if cwd does NOT contain "/app/node_modules" -> exit if cwd contains "/tmp/npm-safe" -> exit otherwise -> proceed اسم المضيف المكون من 12 سداسيًا عشريًا هو الشكل الافتراضي الذي يخصصه Docker للحاوية، و /app/node_modules هو مسار تثبيت تقليدي داخل الحاوية. يفشل الشرط الثالث إذا بدا المسار كدليل استخراج معزول. والنتيجة النهائية هي أن الحمولة تبقى خاملة على حاسوب مطور أو بيئة اختبار معزولة، ولا تُفعّل إلا داخل حاوية بناء أو عامل تشغيل - وهو نوع البيئة الأكثر احتمالاً لحمل بيانات اعتماد سحابية حقيقية. أول حزمة في المجموعة، شبح المرجان، ليس لديه مثل هذه البوابة ويقوم بتشغيل مجموعته (الأبسط) دون أي شروط.
التشكيلاتعند مرور البوابة، يخرج الخطاف من خلالها تنفيذ مزامنة الملفات("/ بن/ش"، ["-ج"، ...]) وينفذ أمراً مركباً واحداً يقوم بالترتيب التالي:
1. PUT /latest/api/token to 169.254.169.254 (IMDSv2 token request) 2. GET .../iam/security-credentials/ (IAM role name) 3. GET .../iam/security-credentials/<role> (temporary credentials) 4. dump env | sort (environment variables) 5. list /app (excl. node_modules) + cat first 15 (application files) 6. aws secretsmanager list-secrets (us-east-1, eu-west-1, eu-central-1) 7. scrape readable files for HTB{...} (capture-the-flag strings) الخطوات من 1 إلى 3 هي خطوات نموذجية لاسترجاع بيانات IMDSv2: اطلب رمز جلسة، ثم أرفقه كـ X-aws-ec2-metadata-token رأسية لسحب دور IAM الخاص بالمثيل ومفاتيح الوصول المؤقتة لهذا الدور. تم اختيار تطبيق IMDSv2 بدلاً من IMDSv1 الأبسط وغير المصادق عليه للحصول على تجدر الإشارة إلى أن هذا يعني أن الحمولة تعمل حتى على الخوادم المُهيأة لطلب الوصول إلى البيانات الوصفية باستخدام الرموز المميزة، وهو إجراء الأمان الذي توصي به AWS. بيانات الاعتماد التي تُرجعها الخطوة 3 قصيرة الأجل. AccessKeyId/مفتاح الوصول السري/رمز يتم تحديد نطاق الثلاثيات لدور المثيل؛ أيًا كان ما يمكن لهذا الدور فعله، يمكن لحامل تلك المفاتيح فعله طوال فترة صلاحية بيانات الاعتماد.
تعمل الخطوات من 4 إلى 6 على توسيع نطاق التناول. الحياة الفطرية يلتقط ملف التفريغ أي شيء ورثته عملية البناء أو التشغيل - عمليًا، هذا هو المكان الذي توجد فيه رموز التسجيل وسلاسل اتصال قاعدة البيانات ومفاتيح واجهة برمجة التطبيقات في أغلب الأحيان. / تطبيق يقرأ برنامج File Walk ما يصل إلى خمسة عشر ملفًا من ملفات التطبيق الخارجية node_modulesوالتي يمكنها تكوين السطح، .env الملفات، أو المصدر. الخطوة 6 تستدعي aws secretsmanager list-secrets في ثلاث مناطق؛ بيانات الاعتماد التي تم الحصول عليها في الخطوات من 1 إلى 3 هي بالضبط ما يُستخدم للتحقق من صحة هذه المكالمات، لذا فإن قراءة IMDS وسلسلة تعداد Secrets Manager تعملان معًا في تصعيد واحد: دور المثيل ← جرد الأسرار المُدارة. الخطوة 7 هي إشارة إلى إطار عمل "التقاط العلم" - عندما HTB{…} إذا تم العثور على العلم، يتم إرساله بمفرده، وإلا يتم تقسيم الكتلة الخام المجمعة إلى أربعة أجزاء وإرسالها.
تُواصل الإصدارات اللاحقة في المجموعة تصعيد العملية. فبدلاً من التوقف عند جرد البيانات، تقوم بتحليل استجابة IMDS، وتصدير المفاتيح المؤقتة كـ AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN متغيرات البيئة، تأكيد الهوية مع الحصول على هوية المتصل aws stsثم قم بتكرار العملية على كل سر تم إرجاعه بواسطة قائمة الأسرار دعوة aws secretsmanager get-secret-value في كل منها - استرجاع المحتويات السرية، وليس أسماءها فقط. تقرأ الإصدارات نفسها أيضًا الملفات الثنائية ذات العلامات المستبدلة بالعملية (/readflag (وأصدقاؤه) ويحاولون تشغيل الشحن ضد أي مشروع Rust موجود تحت / تطبيق، مما يوسع نطاق الحصاد ليشمل ما يتجاوز بيانات اعتماد السحابة إلى أي شيء تكشفه بيئة البناء.
كما أن هذه الإصدارات اللاحقة تفرض قيودًا أكثر صرامة على نفسها. بالإضافة إلى اسم المضيف المكون من 12 سداسيًا عشريًا و /app/node_modules يقوم البرنامج الخبيث، أثناء عمليات التحقق، بفحص إعدادات سجل الحزم النشط ومسار دليل العمل، ويتوقف بصمت عندما يشيران إلى سياق تحليل أو نسخة طبق الأصل بدلاً من هدف مباشر. والنتيجة هي برنامج خبيث لا يقوم بأي شيء ملحوظ في معظم بيئات الفحص، ولا يُجري عملية جمع البيانات الكاملة إلا عندما يعتبر نفسه على مضيف حاوية حقيقي.
exfiltrationتُرسل البيانات المُجمّعة من الجهاز المضيف عبر قناتين. أولاً، عبر منارة. سأعين إلى ثابت webhook.site جامع البيانات، الذي يحمل اسم المضيف، ومعرّف المستخدم الرقمي، ودليل العمل، وما يصل إلى 120 كيلوبايت من البيانات المجمعة. ثانيًا، تُدمج البيانات في "بيان وحدة" YAML وهمي. ضع إلى /api/modules/ على خادم مستهدف:
ecto_module: name: "<flag-or-chunk-0>" version: "1.0.0" power_level: "<chunk-1>" ship_deck: "<chunk-2>" cargo_hold: "<chunk-3>" أسماء حقول البيان (مستوى الطاقة, سطح السفينة, مخزن البضائعتُعدّ هذه العناصر مجرد زينة، إذ تُخزّن البيانات المسروقة داخل قيم السلاسل النصية، ولهذا السبب يرى مراقب الشبكة ما يبدو كتحميل بيان سجل الحزم بشكل طبيعي بدلاً من تفريغ بيانات واضح. تحمل قناة الإشارة المزيد: سأعين الجسم ل webhook.site يتضمن اسم المضيف، ومعرف المستخدم الرقمي، ودليل العمل، وما يصل إلى 120 كيلوبايت من البيانات المجمعة، لذلك حتى إشارة واحدة ناجحة توفر البيانات الكاملة. webhook.site هي خدمة فحص الطلبات مجانية؛ واستخدامها كجامع يعني أن المشغل لا يضطر أبدًا إلى إنشاء بنية تحتية خاصة به لاستقبال تلك القناة، وتستمر الطلبات المسجلة في سلة المهملات الخاصة بالخدمة.
البيان ضع يستعرض قائمة احتياطية تبدأ بعدة 127.0.0.1/مؤسسة الكوثر ثم ينتقل إلى ثلاثة عناوين عامة في154.57.164.0/24 نطاق، يتوقف عند أول نقطة نهاية تستجيب بحالة 2xx. يتوافق ترتيب localhost أولاً مع وصف "اختبار فيرداشيو" الذاتي (سجل محلي على حلقة الاسترجاع)، لكن استخدام عناوين IP العامة كبديل يعني أن البيانات تغادر المضيف عندما لا تستمع حلقة الاسترجاع - أي على أي جهاز ليس جهاز الاختبار الخاص بالمؤلف.
الخط الزمني
تُظهر المجموعة نموًا تدريجيًا في القدرات بدلًا من انخفاض مفاجئ. نرتبها وفقًا للسلوك المرصود، وليس وفقًا للوقت الفعلي المُعلن.
| المرحلة | الحزم / الإصدارات | سلوك |
|---|---|---|
| جولة مبكرة | coral-wraith 9999.0.x | أرقام إصدارات متضخمة تتوافق مع محاولة إحداث لبس في التبعيات؛ تعداد وقت التثبيت واستخراج الملفات |
| بذرة | coral-wraith 1.0.0 | يقوم الأمر postinstall بجمع ملفات id/env/flag؛ ثم يقوم بإرسال طلب PUT واحد إلى 154[.]57[.]164[.]71:30782علامة ECT-472839 |
| التكرار السريع | coral-wraith 1.0.1 → 6.0.0 | عشرات الإصدارات في غضون ساعات؛ الحمولة تكتسب isAppWorker() بوابة، سحب بيانات اعتماد IMDSv2، كامل get-secret-value المحور، وفحص بيئة التسجيل/المسار، وعلامات الوجهة المزدوجة |
| أسماء متوازية | ecto-corsair-whisper-6f3b9 1.0.14–1.0.18 | نفس الحمولة ذات البوابة؛ webhook.site قائمة احتياطية متعددة نقاط النهاية ومنارة |
| المتغيرات | ecto-rust-read-f3a9c1 1.0.1–1.0.2 | يضيف علامات إضافية للأحواض ECT-987654, ECT-654321, ECT-839201 |
| المتغيرات | ecto-corsair-flag-x9m4 1.0.0, ecto-nightly-spirit 1.1.0 | نفس الحمولة المحمية، ونفس وحدة التحكم والسيطرة، ونفس جهاز الإرسال. |
السمة المميزة لهذه المجموعة هي وتيرة النشر: فبدلاً من حزمة واحدة وإصدار واحد، يُعاد نشر نفس الاسم مرارًا وتكرارًا بتتابع سريع، حيث يمثل كل إصدار اختلافًا طفيفًا عن الإصدار السابق، إلى جانب عدد قليل من الإصدارات الشقيقة ذات الأسماء المختلفة التي تحمل نفس الحمولة. همسة انقسمت الشيفرة البرمجية إلى بصمتين متقاربتين - إحداهما تُفعّل اكتشافين حاسمين، والأخرى ثلاثة اكتشافات (مصدر إضافي لقراءة الملفات) - لكن كلتيهما تُشيران إلى نفس الحمولة؛ والفرق هو اختلاف في الشيفرة البرمجية، وليس تفرّعًا سلوكيًا. إصدارات من همسة تمت مراقبة القيم التي تتجاوز النطاق المُحلل (حتى 1.0.25 على الأقل وقت كتابة هذا التقرير) مباشرةً على السجل، و شبح المرجان استمر الاسم في الصعود على سلم نسخته الخاصة فوق نفس النافذة.
مؤشرات الحل الوسط
تم استخراج جميع المؤشرات أدناه من مصدر الحزمة على القرص. تم تعطيل مؤشرات الشبكة.
الانرنيت
| مؤشر | النوع |
|---|---|
hxxp://154[.]57[.]164[.]71:30782 | C2 PUT target (coral-wraith) |
hxxp://154[.]57[.]164[.]80:30543 | C2 PUT fallback (ecto-*) |
hxxp://154[.]57[.]164[.]82:31250 | C2 PUT fallback (ecto-*) |
hxxp://154[.]57[.]164[.]71:31289 | C2 PUT fallback (ecto-*) |
hxxps://webhook[.]site/602a4c72-7033-4e28-92ea-dc66e59206e5 | جامع الإشارات |
169[.]254[.]169[.]254/latest/... | قراءة بيانات اعتماد IMDSv2 (من جانب الهدف، بيانات تعريف AWS) |
ملف سلوكي
| مؤشر | النوع |
|---|---|
"postinstall": "node postinstall.js" | تثبيت المتجهات |
ecto_module: YAML مع power_level / ship_deck / cargo_hold مفاتيح | مخطط بيان Exfil |
علامات الحوض ECT-472839, ECT-987654, ECT-654321, ECT-839201 | مقطع المسار C2 /api/modules/<marker> |
isAppWorker() البوابة: المضيف /^[0-9a-f]{12}$/، يحتوي cwd /app/node_modules | شروط التفعيل |
aws secretsmanager list-secrets على مدى us-east-1, eu-west-1, eu-central-1 | تعداد الأسرار |
HTB{...} استخراج البيانات باستخدام التعبيرات النمطية | حصاد الاستيلاء على العلم |
تجزئات الملفات (sha256، تم التقاطها في وقت التحليل)
| قم بتقديم | sha256 |
|---|---|
coral-wraith/postinstall.js | ce5ff035cfdfed1d0015446424b352c27b66bcb77e9fdb0a51e4245199146824 |
ecto-corsair-whisper-6f3b9 1.0.18/postinstall.js | b58432acba376aa6976f0490d9a1c04257ccdbc856d8390260c50322d63e31c3 |
الإسناد والسلوك الملاحظ
تم نشر أسماء الحزم الخمس تحت اسمي حسابين في npm، لكنهما يشتركان في بنية تحتية كافية لمعاملتهما كمجموعة واحدة: نفس الشيء وحدة ecto مخطط البيان، نفسه إكت-472839 علامة الحوض الرئيسية، نفسها webhook.site معرّف المُجمِّع، ونقاط نهاية C2 في نفس كتلة 154.57.164.0/24. حزمة البذور (coral-wraith)(أبسط وغير مقيد) وبالتالي فإن عائلة ecto-family المقيدة تُقرأ على أنها تكرارات لمجموعة أدوات واحدة بدلاً من جهود مستقلة.
تصف الحزم نفسها، في الإصدارات اللاحقة، بأنها "حمولة CTF لاختبار سلسلة التوريد الخاصة بشركة verdaccio." نُبرز هذا التصنيف كحقيقة قابلة للملاحظة، ولا نعيد صياغته كاستنتاج يتعلق بالغرض. ما يفعله الكود واضح لا لبس فيه، ومستقل عن تصنيفه: فهو يقرأ بيانات اعتماد دور IAM من خدمة بيانات تعريف المثيل، ويُحصي الأسرار المُدارة عبر ثلاث مناطق AWS، ويرسل النتائج إلى عنوان IP عام وجامع Webhook تابع لجهة خارجية. لا يحتاج نظام اختبار حقيقي يعتمد على الاتصال الحلقي فقط إلى قائمة عناوين IP العامة الاحتياطية، أو قراءة بيانات اعتماد IMDS، أو استدعاءات Secrets Manager عبر المناطق. ولأن الوصول إلى بيانات الاعتماد والبيانات الصادرة حقيقيان، فقد صُنفت الإصدارات المقيدة على أنها خبيثة.
تُعدّ خاصية "البوابة المخصصة للحاويات" أبرز سمات هذه الخاصية من الناحية التشغيلية. فهي بمثابة إجراء للتهرب - حيث تبقى صامتة على أجهزة الكمبيوتر المحمولة وفي بيئات التحليل المعزولة - وإجراء استهدافي في آنٍ واحد، إذ لا تُفعّل إلا في الأماكن التي يُرجّح وجود دور IAM حقيقي وبيانات سرية نشطة فيها. لن يلاحظ المحللون الذين يُشغّلون هذه الحزم في بيئة معزولة عامة أي شيء؛ إذ لا يظهر هذا السلوك إلا تحت اسم مضيف على غرار Docker ومسار تثبيت داخل الحاوية.
التأثيرات والاتجاهات والتوجيهات للمدافعين
يكمن الخطر هنا في الكشف عن بيانات اعتماد السحابة والأسرار داخل حاويات البناء والتشغيل. تحمل بيانات اعتماد دور IAM المستخرجة من IMDS جميع الأذونات التي يمتلكها هذا الدور؛ مدير الأسرار: قائمة الأسرار (وأي شيء لاحق) GetSecretValueيُوسّع هذا النطاق ليشمل أسرار التطبيقات المخزنة. غالبًا ما تحتوي ملفات تفريغ متغيرات البيئة على رموز التسجيل وعناوين URL لقواعد البيانات ومفاتيح واجهة برمجة التطبيقات. في سياق التكامل المستمر أو الحاويات - وهو ما تحدده البوابة تحديدًا - يكفي تثبيت واحد غير مباشر لإحدى هذه الحزم لتسريب هذه البيانات.
يتوافق برنامج Ectoplasm مع نمط نلاحظه باستمرار: حمولات برمجية تُثبّت على السحابة وتستهدف البيانات الوصفية السحابية والأسرار المُدارة بدلاً من الملفات المحلية، وتُقيّد نفسها بحيث لا تُفعّل إلا في بيئات عالية القيمة. وفيما يلي ملاحظتان دفاعيتان.
- يمكن تحديد الشكل. خطاف تثبيت npm/PyPI الذي يصل مخطط استدعائه إلى واجهة برمجة تطبيقات أسرار السحابة (مدير أسرار AWS, أسرار جوجل كلاود, مستودع مفاتيح Azure) أو عنوان IMDS ومخرج الشبكة هو نمط ضيق وعالي الإشارة - نادرًا ما يحدث في نص دورة حياة شرعي. تحليل التدفق الساكن يمكن الإشارة إليه دون الاعتماد على أي نطاق أو عنوان IP محدد.
- يؤدي تصلب البيئة إلى إضعافه. يمنع تطبيق بروتوكول IMDSv2 بحد أقصى للقفزات يبلغ 1 أحمال عمل الحاويات من الوصول إلى بيانات تعريف المثيل؛ ويحد تحديد نطاق أدوار IAM بأقل امتيازات من نطاق انتشار أي بيانات اعتماد قد تتسرب؛ وتشغيل عمليات التثبيت مع - تجاهل النصوص في نظام التكامل المستمر، يتم إزالة متجه install-hook بالكامل للحزم التي لا تحتاج إليه.
بالنسبة للمدافعين، تتمثل الفحوصات العملية فيما يلي: التنبيه بشأن الاتصالات الصادرة من حاويات البناء/التكامل المستمر إلى عناوين IP العامة غير المدرجة في القائمة المسموح بها أثناء تركيب npm; راقب الوصول إلى IMDS الذي ينشأ من البرامج النصية لدورة حياة الحزمة؛ وتعامل مع أي خطاف تثبيت يقوم بالوصول إلى واجهة سطر الأوامر السحابية على أنه مشبوه حتى يثبت العكس.
هناك ملاحظتان إضافيتان خاصتان بهذه المجموعة. أولاً، نظرًا لأن التفعيل مقيد بالبيئات المعبأة في حاويات، فقد تظل الحزمة التي تبدو غير فعالة عند فحصها على محطة عمل قيد التشغيل في بيئة الإنتاج. يتطلب الفحص إعادة إنتاج اسم مضيف الحاوية ومسارها، أو قراءة المصدر مباشرةً، بدلاً من الاعتماد على "قمت بتثبيتها ولم يحدث شيء". ثانيًا، يعني استخدام خدمة فحص الطلبات العامة كجامع إشارات أن بعض البيانات المسربة قد تكون قابلة للاسترداد للاستجابة للحوادث: يمكن للمؤسسة التي تجد إحدى هذه الحزم في شجرة التبعيات الخاصة بها أن تستنتج محتوى الإشارة الناجحة من منطق جمع الحمولة، ويجب عليها تغيير أي بيانات اعتماد لدور إدارة الهوية والوصول، ورموز التسجيل، والأسرار المُدارة التي كان من الممكن الوصول إليها من بيئة الإنشاء أو التشغيل المتأثرة. تناوب الاعتماداتإن الحل العملي، وليس إزالة الحزمة، هو الحل الذي يتم تنفيذه بمجرد اكتمال عملية التثبيت.





