تجاوز جراب في Kubernetes من خلال سجلات متزايدة

تقريبا. العابرة. : تم كتابة هذه الملاحظة من قبل باحث أمن تكنولوجيا المعلومات في Aqua Security ، شركة DevSecOps. إنها مثال ممتاز على التفاصيل الدقيقة في تكوين Kubernetes ، وهو أمر مهم يجب مراعاته دائمًا عند تقديم التجمعات في الإنتاج. بالطبع ، إذا فكرت في سلامتهم ...



يتكون Kubernetes من العديد من المكونات ، وفي بعض الأحيان يؤدي دمجها بطريقة معينة إلى نتائج غير متوقعة. في هذه المقالة ، سأوضح كيف يمكن لقرنة تم إطلاقها بامتيازات الجذر ودليل /var/log للعقدة أن يوسع محتويات نظام الملفات المضيف بأكمله إلى مستخدم لديه حق الوصول إلى سجلاته. سنناقش أيضا حلول لهذه المشكلة.

كيف يرى Kubernetes السجلات


هل تساءلت kubectl logs <pod_name> كيف kubectl logs <pod_name> استخراج سجلات من جراب؟ من المسؤول عن جمع السجلات من الحاويات؟ وكيف يحصلون على جهاز الكمبيوتر الخاص بك؟

يوضح المخطط التالي العملية:



يقوم Kubelet بإنشاء بنية داخل الدليل /var/log على المضيف الذي يمثل القرون على المضيف. يوجد ملف 0.log (1) في الدليل الخاص ببرنامجنا ، ولكنه في الحقيقة رابط إلى سجل الحاوية الموجود في /var/lib/docker/containers . كل هذا من وجهة نظر المضيف.

يفتح Kubelet نقطة النهاية /logs/ (2) ، والتي تعمل ببساطة مع خادم ملفات HTTP في الدليل (3) ، مما يجعل السجلات متاحة للطلبات الواردة من خادم API.

الآن تخيل أننا نشرنا ملف pod مع hostPath مركب في /var/log . سوف تحصل هذه الأداة على إمكانية الوصول إلى جميع ملفات السجل على المضيف. على الرغم من أن هذا بحد ذاته يمثل مشكلة محتملة ، إلا أنه يمكننا اتخاذ الخطوة المنطقية التالية. ماذا لو استبدلنا موقع 0.log الارتباط إلى ... قل ، /etc/shadow ؟

 │ ├── var │ ├── logs │ │ ├── pods │ │ │ ├── default_mypod_e7869b14-abca-11e8-9888-42010a8e020e │ │ │ │ ├── mypod │ │ │ │ │ ├── 0.log -> /etc/shadow │ │ │ │ │ │ 

الآن ، في محاولة لتنزيل السجلات باستخدام kubectl logs على جهاز العميل ، نحصل على:

 $ kubectl logs mypod failed to get parse function: unsupported log format: "root:*:18033:0:99999:7:::\n" 

يتبع Kubelet الرابط ويقرأ محتويات الملف التي يشير إليها (يمكن أن يكون أي ملف على العقدة).

نظرًا لتوقع JSON ، تعطل kubectl بعد السطر الأول ، ومع ذلك ، يمكننا بسهولة قراءة الأسطر المحددة لملف shadow عن طريق تشغيل الأمر باستخدام –-tail=-<line_number> .

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

الهروب من جراب


دعنا نذهب أبعد من ذلك. نعلم أنه عند بدء تشغيل pod في Kubernetes ، يتم تثبيت رمز ServiceAccount فيه. وبالتالي ، إذا كان حساب الخدمة يسمح بالوصول إلى السجلات ، يمكننا الوصول مباشرة إلى امتيازات kubelet والجذر على المضيف.

كتبت دليلًا على المفهوم (POC) يوضح متجه الهجوم:

  • نشر جراب مع نقطة /var/log .
  • إنشاء رابط رمزي إلى الدليل الجذر للمضيف ؛
  • قراءة المفتاح الخاص بالمستخدم ssh على المضيف.

يُظهر الفيديو التالي أمرين خاصين يتم تشغيلهما داخل جراب:

  • lsh == ls (على نظام الملفات المضيف) ؛
  • cath == cat (على نظام الملفات المضيف).

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

يمكن العثور على جميع الملفات المشاركة في POC في مستودع جيثب المقابل . هناك برنامج نصي POC آخر يقوم تلقائيًا بجمع المفاتيح الخاصة ورموز ServiceAccount من نظام الملفات المضيف.

أدلة متزايدة يمكن أن تكون خطيرة


فهل هذه ثغرة أمنية أم مجرد ممارسة سيئة؟

نادرًا ما يكون نشر جراب مع hostPath مفتوح hostPath في /var/log hostPath نادرًا (بالإضافة إلى ذلك ، هناك طرق أخرى لإساءة استخدام الدلائل السرية للمضيف في pod). ولكن حتى لو كنت تعلم أن عملية التثبيت /var/log كانت ممارسة مشكوك فيها ، فربما لم تتوقع أن تسمح لك بالاستيلاء على العقدة بهذه السهولة.

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

تم اختبار هذه الطريقة على Kubernetes 1.15 و 1.13 ، ولكن على الأرجح تؤثر على الإصدارات الأخرى.

إزالة


مثل هذا "الهروب" لا يمكن تحقيقه إلا إذا كان الجراب يعمل كجذر. هذا ينبغي عموما تجنبها . يسمح لك Aqua CSP بتعيين سياسة بأقل قدر من الجهود التي تمنع الحاويات من العمل تحت الجذر أو تمنح أذونات فقط لمجموعة محددة من الصور التي تحتاج بالفعل إلى الجذر.

هناك طريقة أخرى هي ببساطة عدم نشر القرون مع hostPath مع أذونات الكتابة في /var/log . لم يتم تعيين هذا النهج افتراضيًا وليس ممارسة شائعة ، لذلك من الضروري تحديده بوعي (ومع ذلك ، لا يزال هناك احتمال). ولكن كيف تحقق؟

لقد أضفنا نصًا جديدًا (صيادًا) إلى kube-hunter - أداة Open Source الخفيفة الخاصة بنا لاختبار Kubernetes - والتي تقوم بفحص المجموعة بحثًا عن القرون باستخدام نقاط التثبيت الخطيرة هذه. ( ملاحظة : Kube-hunter كان حاضراً في مراجعة حديثة لأدوات المساعدة الأمنية K8s ، والتي نشرناها على مدونتنا.)

يمكن لمستخدمي Aqua حماية أنفسهم من هذا الخطر باستخدام سياسة وقت التشغيل لمنع تركيب وحدات تخزين معينة:



تقريبا. العابرة. : يمكن حل جزء من هذه المشكلة باستخدام سياسات تأمين Pod ، وهي AllowedHostPaths . ومع ذلك ، هذه ليست أيضًا حماية ضد الارتباطات. أخيرًا ، كما تشير التعليقات ، يمكننا ببساطة تقييد الإطلاق كجذر ، مرشدًا مرة أخرى بواسطة PSP .

يؤدي


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

PS من المترجم


اقرأ أيضًا في مدونتنا:

Source: https://habr.com/ru/post/ar466625/


All Articles