More
Сhoose
تواصل معناتحدث مع مساعدنا

هجوم PolinRider:
الاكتشاف والإزالة ومنع عودته

هجوم PolinRider: كيفية اكتشافه وإزالته ومنع عودته
الفئة:  تطوير المواقع
التاريخ:  
الكاتب:  إقبال
عن الكاتب

إقبال

يبني إقبال البنية الهندسية في Joyboy مع تركيز على الاعتمادية والأداء واختيار الأدوات الحديثة المناسبة لكل منتج.

هجوم PolinRider تهديد يستهدف سلسلة توريد npm ويستخدم حزماً خبيثة ومُحمّلات JavaScript مخفية لإيصال برمجيات وصول عن بُعد. يشرح هذا الدليل كيف يعمل PolinRider، وكيفية اكتشافه داخل مشاريع npm وسجل Git، وإزالته بأمان، وتحديد بيانات الاعتماد التي يجب تدويرها، وتطبيق الضوابط التي تمنع عودته.

الخلاصة السريعة
  • تعامل مع ملفات الإعداد ذات الحجم غير المعتاد أو الشيفرة المبهمة كحادث أمني قابل للتنفيذ.
  • لا تعتمد على npm audit وحده؛ فقد لا تظهر الشيفرة المحقونة في المستودع ضمن شجرة الاعتماديات.
  • افحص جميع الفروع المحلية والبعيدة والوسوم وسجلات reflog وكائنات Git.
  • افترض أن الأسرار المتاحة للعملية المتأثرة ربما انكشفت وقم بتدويرها.
  • أعد بناء الأجهزة والمشغلات المتأثرة من حالة موثوقة بدلاً من الاكتفاء بتنظيف الشيفرة المصدرية.
  • احمِ ملفات الإعداد عالية المخاطر وتغييرات الحزم بالمراجعة والسياسات الآلية ومراقبة وقت التشغيل.
ما هو PolinRider؟

يستخدم باحثو الأمن اسم PolinRider لوصف حملة ينشر فيها المهاجمون حزم npm خبيثة أو يستولون على حزم قائمة، ثم يستخدمون مُحمّلات JavaScript لجلب برمجيات ضارة في مراحل لاحقة. يشرح تحليل Socket عملية واسعة للحزم الخبيثة، بينما يوثق تقرير Sonatype محاولة حزمة مخترقة إيصال برمجية وصول عن بُعد مرتبطة بـ PolinRider.

ولا يقتصر الخطر على اسم حزمة بعينها. فبمجرد وصول الشيفرة الخبيثة إلى محطة عمل أو مستودع، يمكن وضعها داخل ملف تتوقع أدوات المطور تشغيله أصلاً، مثل إعدادات ESLint أو PostCSS أو Vite أو أدوات الاختبار والبناء. عندها يتغير سؤال التحقيق من «أي اعتماد يحتوي على ثغرة؟» إلى «ما الشيفرة التي نُفذت، وأين بقيت، وإلى ماذا استطاعت الوصول؟»

كيف يعمل هجوم PolinRider؟

استخدمت العينات التي حققنا فيها ملفات إعداد .mjs عادية كغطاء. ظهر إعداد صحيح صغير في بداية الملف، ثم ظهرت شيفرة مُبهمة بعد مساحة بيضاء كبيرة يصعب ملاحظتها في المراجعة السريعة. أجرت الشيفرة استكشافاً للشبكة، وفكّت حمولة مشفرة، وقيّمتها ديناميكياً، ثم شغّلت عملية Node.js منفصلة.

ينتج عن هذا النمط عدد من مؤشرات التحذير:

  • نمو ملف إعداد من بضع مئات من البايتات إلى عشرات الكيلوبايتات دون سبب واضح.
  • وجود سطر طويل بصورة استثنائية أو شيفرة فعلية بعد فجوة كبيرة من المسافات.
  • استيراد ملف إعداد lint أو CSS لوحدات child_process أو الشبكة أو تحميل الوحدات الديناميكي دون مبرر.
  • استخدام eval أو Function أو حلقات XOR أو مصفوفات بايت مشفرة أو تشغيل عمليات منفصلة.
  • اتصال الشيفرة بواجهات API لا علاقة لها بالمشروع أو نقاط RPC عامة أو خدمات لصق أو نطاقات غير مألوفة.
  • إضعاف حماية ملفات .env في .gitignore خلال الفترة نفسها.

قد يكون لكل مؤشر تفسير سليم منفرداً، لكن اجتماع عدة مؤشرات يتطلب احتواءً فورياً.

كيفية اكتشاف PolinRider في مشروع JavaScript

ابدأ بفحوصات للقراءة فقط. لا تشغّل المشروع أو تثبّت اعتمادياته أو تنفّذ ملفات إعداد غير مألوفة قبل اكتمال المراجعة الأولية.

تحقق مما إذا كانت ملفات الإعداد القابلة للتنفيذ كبيرة بصورة غير متوقعة:

bash
find . -type f \( -name "*.js" -o -name "*.mjs" -o -name "*.cjs" \) -size +20k -not -path "*/node_modules/*"

ابحث في الشيفرة عن سلوكيات نادراً ما تكون مبررة داخل إعدادات lint أو CSS أو البناء:

bash
rg -n "child_process|spawn\(|exec\(|eval\(|new Function|createRequire|https?://" \
  --glob '!node_modules/**' --glob '*.{js,mjs,cjs}'

راجع السجل الكامل للملفات عالية المخاطر بدلاً من الاكتفاء بمحتواها الحالي:

bash
git log --all --stat -- '*.config.js' '*.config.mjs' '*.config.cjs'
git log --all -p -- eslint.config.mjs postcss.config.mjs package.json

وفي النهاية، احصر جميع الفروع والوسوم، وقارن المراجع البعيدة، وافحص النسخ القديمة وذاكرة CI المؤقتة. تثبت نسخة العمل النظيفة أن الملفات المفتوحة نظيفة فقط؛ لكنها لا تثبت سلامة المستودع أو الجهاز.

دراسة حالة لهجوم PolinRider: ما الذي وجدناه؟

وجدنا خلال المراجعة مُحمّلات مدمجة مباشرة داخل ملفي إعداد JavaScript في مستودعين. اختبأ أحدهما في إعداد PostCSS والآخر في إعداد ESLint. وظلت فروع متعددة ووسوم إصدارات تشير إلى الكائنات الخبيثة حتى بعد تصحيح نسخة العمل الظاهرة.

كما وجدنا أكثر من جيل واحد للمُحمّل في السجل. وهذا مهم لأن تنظيف العينة الأحدث فقط كان سيُبقي إصداراً أقدم قابلاً للوصول. ولم تتضمن ملفات تعريف الاعتماديات وملفات القفل أسماء حزم PolinRider المعروفة التي فحصناها، وهو ما يؤكد أن تقرير ثغرات الحزم المعتاد لا يستطيع وصف الحادث بالكامل.

هل يستطيع npm audit اكتشاف PolinRider؟

يقارن npm audit شجرة الاعتماديات المثبتة بإرشادات الثغرات المعروفة. وهي أداة مفيدة، لكنها تجيب عن سؤال أضيق من السؤال الذي يحتاجه فريق الاستجابة للحوادث.

| الفحص الأمني | ما يستطيع اكتشافه | ما قد يفوته | | ---------------------------------- | ---------------------------------------- | ----------------------------------------------- | | npm audit | ثغرات معروفة في الحزم المثبتة | شيفرة خبيثة أضيفت مباشرة إلى المستودع | | مراجعة ملف القفل | الاعتماديات والمصادر الجديدة أو المتغيرة | حمولات مخفية داخل ملفات إعداد يملكها المشروع | | فحص الحزم المخصص للبرمجيات الخبيثة | حزم خبيثة معروفة وسلوك تثبيت مشبوه | كائنات Git التاريخية والأجهزة المخترقة سابقاً | | فحص الشيفرة والسجل | الإبهام والمُحمّلات والبقاء عبر المراجع | الأسرار التي نُسخت أو الأوامر التي نُفذت بالفعل | | مراقبة الأجهزة والشبكة | سلوك العمليات والاتصالات الصادرة | شيفرة خاملة لم تُشغّل بعد |

يجمع التقييم السليم بين هذه الزوايا الخمس.

كيفية إزالة PolinRider بأمان

1. الاحتواء قبل التعديل. أوقفنا تشغيل المشاريع المتأثرة وتعاملنا مع بيئات المطورين والأتمتة باعتبارها ربما تعرضت للخطر. حفظ نسخة من الأدلة قبل التنظيف مهم لفهم النطاق ودعم التحقيق اللاحق.

2. تحديد خط أساس موثوق. قارنا سجل الملفات وأحجامها وبصماتها والالتزامات لتحديد آخر إصدار سليم. وفحصنا قاعدة كائنات Git كاملة بدلاً من الثقة بالنسخة المفتوحة فقط.

3. استعادة الملفات النشطة. استبدلنا الإعداد المحقون بأقل إعداد صحيح، وأعدنا الضوابط التي تمنع دخول ملفات البيئة المحلية إلى Git.

4. فحص كل مرجع. فحصنا الفروع المحلية والبعيدة والوسوم وسجلات reflog والكائنات غير القابلة للوصول بحثاً عن نسختي المُحمّل المعروفتين وعن المؤشرات السلوكية. وكشف ذلك وسوم إصدارات متأثرة كان فحص الفرع الرئيسي وحده سيفوّتها.

5. إعادة كتابة السجل المتأثر. أعدنا بناء كل فرع ووسم متأثر انطلاقاً من الأصل الموثوق، مع الحفاظ على العمل الصحيح اللاحق واستبعاد التغييرات المحقونة. ثم أنهينا صلاحية المراجع القديمة وحذفنا الكائنات الخبيثة محلياً.

6. تحديث المستودع البعيد بأمان. لأن الالتزامات المعاد بناؤها تحمل معرفات جديدة، احتاجت المراجع المتأثرة إلى تحديثات قسرية منسقة. استخدمنا عمليات دفع محمية بـ --force-with-lease وتحققنا من المراجع البعيدة الناتجة بدلاً من استخدام دفع قسري غير مقيد.

7. تدوير بيانات الاعتماد. لا يستطيع تنظيف المصدر التراجع عن سرقة بيانات الاعتماد. ألغينا واستبدلنا الأسرار التي كانت متاحة لجلسات المطورين أو المشغلات المتأثرة، ومنها رموز التحكم بالمصدر وبيانات السحابة ومفاتيح النشر ورموز npm وأسرار التطبيقات ومفاتيح SSH ذات الصلة. كما راجعنا سجلات المصادقة والتدقيق بحثاً عن نشاط غير متوقع.

8. إعادة بناء بيئات التنفيذ. يمكن لحمولة منفصلة أن تستمر بعد حذف الملف الذي أطلقها. أعدنا بناء محطات العمل ومشغلات CI المتأثرة من صور موثوقة، ومسحنا الذاكرة المؤقتة، وثبتنا الاعتماديات من ملف قفل تمت مراجعته، ثم أعدنا فحص النتيجة النظيفة.

الفرق بين حذف ملف وإكمال المعالجة

| الإجراء | الفرع الحالي | الفروع والوسوم الأخرى | بيانات الاعتماد والأجهزة | استجابة كافية | | ---------------------------------------- | -----------: | --------------------: | -----------------------: | ------------- | | حذف الأسطر المشبوهة | نظيف | ما زالت مكشوفة | لم تُعالج | لا | | عكس الالتزام الخبيث | نظيف | قد تبقى مكشوفة | لم تُعالج | لا | | إعادة كتابة جميع مراجع Git المتأثرة | نظيف | نظيفة بعد التحقق | لم تُعالج | غير مكتملة | | إعادة الكتابة والتدوير والبناء والمراقبة | نظيف | نظيفة بعد التحقق | تمت معالجتها | نعم |

كيفية منع تكرار الإصابة بـ PolinRider

لا توجد أداة واحدة تمنع جميع هجمات سلسلة التوريد. الدفاع الأقوى هو مجموعة ضوابط صغيرة تجعل إدخال التغييرات المشبوهة صعباً واكتشافها سريعاً.

  • اطلب مراجعة ملفات تعريف الحزم وملفات القفل ومسارات CI وملفات الإعداد القابلة للتنفيذ.
  • أضف قواعد CODEOWNERS للملفات عالية المخاطر وامنع الدفع المباشر إلى الفروع المحمية.
  • اطلب مصادقة متعددة العوامل مقاومة للتصيد أو مفاتيح مرور، واستخدم رموز وصول قصيرة العمر وبأقل صلاحيات.
  • تحقق من مصدر الحزم وتغيرات الملكية، وحقق في المشرفين الجدد أو أنماط الإصدارات غير المتوقعة.
  • راجع سكربتات دورة الحياة، وفكر في تعطيل سكربتات الحزم في البيئات التي لا تحتاج إليها.
  • أطلق تنبيهاً عند التغير الكبير في حجم الملف أو طول الأسطر المفرط أو الإبهام أو التقييم الديناميكي أو تشغيل عمليات غير متوقعة من ملفات الإعداد.
  • استخدم مشغلات CI مؤقتة، واقصر الأسرار على بيئاتها، وقيّد الوصول الصادر إلى الشبكة.
  • اجمع بين فحص الأسرار والاعتماديات والشيفرة وحماية الأجهزة.
  • أنشئ قائمة مكونات برمجية (SBOM) للإصدارات واحتفظ بسجل لإصدارات الاعتماديات التي تمت مراجعتها.
  • تدرّب على تنظيف سجل المستودع وتدوير بيانات الاعتماد قبل أن يجعل الحادث ذلك أمراً عاجلاً.
قائمة تحقق عملية

قبل إعلان اكتمال الاستعادة، تأكد من الآتي:

  • نسخ العمل نظيفة وملفات الإعداد مطابقة لخطوط الأساس التي تمت مراجعتها.
  • تم فحص كل فرع ووسم بعد إعادة كتابة السجل.
  • البصمات الخبيثة المعروفة والمؤشرات السلوكية غائبة عن كائنات Git القابلة للوصول.
  • النسخ الجديدة من المستودع البعيد تعيد إنتاج النتيجة التي تم التحقق منها.
  • تُثبّت الاعتماديات من السجل المتوقع وملف القفل الذي تمت مراجعته.
  • لا توجد عمليات غير متوقعة بعد التثبيت أو اتصالات صادرة مشبوهة.
  • أُلغيت الأسرار ذات الصلة، ولم تُنسخ فقط إلى ملفات .env جديدة.
  • أُعيد بناء أجهزة المطورين ومشغلات البناء والذاكرة المؤقتة والمنتجات المبنية وبيئات النشر، أو تم التحقق من نظافتها بصورة مستقلة.
  • تمت مراجعة سجلات المصادقة ونشر الحزم والسحابة والنشر.
  • يعرف المتعاونون ضرورة التخلص من النسخ القديمة حتى لا يُدفع السجل الملوث مرة أخرى.
إزالة PolinRider: الخلاصة

يذكّرنا PolinRider بأن حادث اعتماد برمجي يمكن أن يتحول في خطوة واحدة إلى حادث يمس المستودع والهوية والأجهزة والبنية التحتية. الشيفرة الخبيثة الظاهرة دليل على وجود فرصة للتنفيذ، وليست الحد الكامل للاختراق.

لذلك تتجاوز الاستجابة الموثوقة إزالة الحزمة: احتواء الحادث، وحفظ الأدلة، واستعادة الشيفرة الموثوقة، وتنظيف كل مراجع Git، وتدوير بيانات الاعتماد، وإعادة بناء البيئات المتأثرة، والتحقق من نسخة جديدة. هذا هو الفرق بين إخفاء التحذير واستعادة الثقة فعلياً في سلسلة تسليم البرمجيات.

المصادر وقراءات إضافية