اكتشف مشروع Google Zero كيفية تجاوز Knox Hypervisor من سامسونج (تم إصلاحه في تصحيح يناير)

في أحدث منشور على مدونة Project Zero، اكتشف الفريق طريقة لتجاوز حماية kernel في الوقت الفعلي من سامسونج، تسمى Knox Hypervisor.

لقد تحقق فريق Google Project Zero من عدد من عمليات الاستغلال التي تتيح مهاجمة هواتف Samsung التي تشغل مجموعة أمان Samsung Knox التي يفترض أنها آمنة. تشير المدونة إلى أن جميع الثغرات الأمنية قد تم نقلها إلى شركة Samsung التي أصدرت بالفعل إصلاحات لها في تحديث البرنامج لشهر يناير.


خلفية

كجزء من مجموعة برامج الأمان Samsung Knox التي تقدمها شركة Samsung، يوجد برنامج يقع بين تطبيقات Android والنواة يسمى مراقب الأجهزة الافتراضية. يمكن استخدام هذا كطبقة إضافية لمزيد من الأمان لأجهزة Android. يُطلق على برنامج Samsung Knox Hypervisor اسم "حماية النواة في الوقت الحقيقي"أو RKP باختصار، كما سأشير إليه في بقية هذه المقالة.

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

تتعمق منشورات المدونة في كيفية عمل ذاكرة Android وRKP وأنظمة التشغيل بشكل عام، لذلك قمت بتكثيفها وتبسيطها لتقديم نظرة عامة سريعة على ما تم اكتشافه. أنا أشجعك على قراءة المقال كاملاً إذا كان لديك الوقت، لأنه مفيد للغاية.


استغلال رقم 1:

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

في حالة برنامج RKP، فإن القدرة على تجاوز KASLR هي في الواقع أبسط من البحث المشار إليه أعلاه. تتم الإشارة إلى ذاكرة جميع أجهزة Android بواسطة المؤشرات ومن أجل حماية الأجهزة من الهجوم، عندما تقوم أجهزة Android بالطباعة أو الإخراج (سواء للشاشة أو لتقديم السجلات أو تصحيح الأخطاء)، تكون مراجع المؤشرات مجهولة المصدر، - مما يجعل من المستحيل معرفة المكان الذي يشير إليه المؤشر فعليًا عند قراءة انتاج.

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

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


استغلال رقم 2:

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

  1. تم وضع علامة على جميع الصفحات (الكود الموجود في الذاكرة)، باستثناء كود kernel، على أنها "ممتازة التنفيذ مطلقًا" (بمعنى أنه لا يمكن تشغيل الكود هنا أبدًا)
  2. لا يتم وضع علامة على صفحات بيانات Kernel (البيانات التي يستخدمها البرنامج في الذاكرة) على أنها قابلة للتنفيذ (لذلك لا يمكن تشغيل التعليمات البرمجية هنا أبدًا)
  3. لا يتم وضع علامة على صفحات رموز Kernel (الكود الموجود في الذاكرة) على أنها قابلة للكتابة (لذلك لا يمكن لأي تعليمات برمجية ضارة تغييرها)
  4. تم وضع علامة على جميع صفحات kernel للقراءة فقط في جدول الترجمة للمرحلة الثانية (الجدول الموجود بين التطبيق والنواة لمنع التطبيقات من معرفة مواقع الذاكرة الحقيقية)
  5. يتم وضع علامة على كافة إدخالات ترجمة الذاكرة للقراءة فقط للتطبيقات.

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

_text و_etext يحددان النطاق المحمي

تمكن المؤلف من التأكد من أن الذاكرة التي تستخدمها النواة قد تم بالفعل تمييزها على أنها "للقراءة فقط"، إلا أن بقية تلك الكمية الكبيرة من الذاكرة المستخدمة لإخفاء النواة كانت لا تم وضع علامة "للقراءة فقط". وذلك لأن RKP يحمي المنطقة التي تحتوي على نص النواة فقط بعد تطبيق شريحة KASLR.


استغلال رقم 3

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

في هذا الاستغلال كان التحكم HCR لا تغطي سجلين والذي تبين أنه مهم جدًا. تعمق المؤلف في دليل ARM المرجعي واكتشف أن السجل الأول سمح له بإيقاف تشغيل RKP بشكل أساسي للتطبيقات. ال "يوفر سجل التحكم في النظام لـ EL1 (SCTLR_EL1) تحكمًا عالي المستوى في النظام، بما في ذلك نظام الذاكرة". في عالم مثالي، سيستخدم التطبيق الذاكرة التي تم تعيينها عبر RKP حتى يتمكن RKP من التحكم في ما يمكن للتطبيق الوصول إليه. ومع ذلك، فإن إيقاف تشغيل هذا السجل يسمح بـ سيتم تعطيل RKP من خلال إعادة الجهاز بشكل فعال إلى الطريقة التي كان يعمل بها قبل تثبيت RKP - مما يعني أنه تم تعيين الجهاز إلى الذاكرة الفعلية دون الأمان الإضافي الذي يوفره RKP. وهذا بدوره يعني أن المؤلف يمكنه القراءة والكتابة في الذاكرة التي تم حظرها في الأصل وبشكل صحيح بواسطة برنامج RKP.

السجل الثاني الذي تم تفويته كان له تأثير أكثر دقة، ولكنه في النهاية مدمر بنفس القدر للأمن. ال سجل مراقبة الترجمة لـ EL1 يرتبط السجل (TCR_EL1) بشكل مباشر بحجم الذاكرة التي يعمل بها التطبيق والتي تسمى الصفحة. تم ترميز RKP إلى حجم صفحة يبلغ 4 كيلو بايت لأن نوى Linux AARCH64 (مثل Android) تستخدم حجم ترجمة يبلغ 4 كيلو بايت. يقوم السجل المعني (TCR_EL1) بتعيين شرائح ARM على حجم الذاكرة التي سيتم إرجاعها. لقد أتضح أن هذا السجل غير محمي من قبل HCR وبالتالي يمكن للمهاجم تغييره كما قام المؤلف بتغييره إلى حجم صفحة يبلغ 64 كيلو بايت.

ما يعنيه هذا هو أنه عند استيفاء الطلب بواسطة RKP، يصبح المقدار الفعلي للذاكرة التي يمكن الوصول إليها الآن 64 كيلو بايت بدلاً من 4 كيلو بايت. والسبب هو أن مجموعة شرائح ARM لا تزال تتحكم في حجم الصفحة وتم ضبطها على 64 كيلو بايت بواسطة الاستغلال. نظرًا لأن RKP يحمي الذاكرة من الكتابة إليها، كجزء من القواعد المدرجة في الاستغلال رقم 2، فإن الذاكرة لا تزال محمية بالفعل. ولكن هنا تكمن المشكلة - نظرًا لأن RKP مشفر بدقة إلى 4 كيلو بايت، فإنه لا يتغير إلى حجم صفحة يبلغ 64 كيلو بايت عند تحديث السجل، لذلك تتم حماية أول 4 كيلو بايت فقط من الذاكرة السماح للمهاجم بالقيام بذلك كل ما يريد مع 60 كيلو بايت المتبقية.


استغلال رقم 4

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

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


خاتمة

واحدة من أكبر المشكلات المتعلقة بالثغرات الأربعة المذكورة أعلاه هي أن المؤلف يذكر مدى صعوبة تنفيذها بسبب نقص الوظائف في نواة Android الأساسية. ومن المفارقات أن برنامج RKP Hypervisor الآمن قدم جميع الأدوات المطلوبة لتنفيذ الهجمات. يظهر أحيانًا أن البرامج حسنة النية تسبب مشكلات أكثر من حلها، ونحن محظوظون لأن لدينا أشخاصًا مثل Gal Beniamini على استعداد لتسخير أيديهم واختبار مدى تطابق الوثائق مع ما هو موجود في البرنامج بالفعل يفعل.

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


المصدر: المشروع صفر