لكنك أخبرتني أنك بخير: مهاجمة محرك عرض Mozilla Firefox (الجزء الأول)

غالبًا ما ترتبط الثغرات الأمنية وعمليات الاستغلال في الأهداف الشائعة مثل المتصفحات بمشكلات أمان الذاكرة. عادةً ما ينطوي هذا إما على خطأ مباشر في إدارة الذاكرة أو طريقة لإفساد الحالة الداخلية للكائن في محرك JavaScript. تتمثل إحدى طرق التخلص من مشكلات أمان الذاكرة هذه في استخدام لغة آمنة للذاكرة مثل Rust أو حتى JavaScript نفسها. في Pwn2Own Vancouver 2022 ، اخترق Manfred Paul متصفح Mozilla Firefox باستخدام ثغرة كاملة السلسلة التي كسرت القالب. على الرغم من أن استغلاله استخدم بعض تلف الذاكرة ، إلا أن الشفرة الضعيفة تمت كتابتها بلغة برمجة آمنة للذاكرة: JavaScript! في الواقع ، كانت الثغرات الأمنية المستخدمة في السلسلة مرتبطة بجانب سيئ السمعة إلى حد ما من لغة جافا سكريبت: النماذج الأولية. في هذه المدونة ، سوف نفحص أول ثغرة أمنية في السلسلة ، والتي تم استخدامها لخرق عملية عرض Mozilla Firefox. هذه الثغرة ، المعروفة باسم CVE-2022-1802 ، هي نموذج أولي لخطر التلوث في التنفيذ المعلق. يمكنك العثور على مزيد من المعلومات حول هذه الثغرة الأمنية على الصفحة الإرشادية لمبادرة Zero Day التي تم تعقبها كـ ZDI-22-799. عالجت Mozilla هذه الثغرة الأمنية في Firefox 100.0.2 عبر Mozilla Foundation Security Advisory 2022-19.

ملاحظة: تعتمد سلسلة المدونات هذه بشكل كبير على التفاصيل التي قدمها مانفريد بول أثناء مسابقة Pwn2Own.

المساومة في عملية العرض

تتميز JavaScript الحديثة ببنية الوحدة ، والتي تسمح للمطورين بتقسيم التعليمات البرمجية إلى ملفات فردية. الميزة الأحدث هي دعم الوحدات غير المتزامنة ، أو بشكل أكثر تحديدًا ، الميزة المعروفة باسم انتظار المستوى الأعلى. في محرك JavaScript في Firefox ، SpiderMonkey ، يتم تنفيذ الكثير من هذه الوظائف باستخدام كود JavaScript مدمج. ضع في اعتبارك الوظيفة التالية من قاعدة شفرة SpiderMonkey ، في /js/src/builtin/Module.js:

هناك ثلاث حقائق يجب أن نلاحظها في الكود أعلاه:

1 - تعمل هذه الوظيفة في نفس سياق JavaScript مثل كود المستخدم. هذا صحيح بالنسبة لمعظم الوظائف المستندة إلى JavaScript في Firefox. هذا يعني أن الحالة العالمية ، بما في ذلك النماذج الأولية للكائنات العالمية ، تتم مشاركتها بين كود التضمين هذا ورمز موقع الويب غير الموثوق به.

2 - تحتوي الدالة على وسيطة افتراضية هي execList = []. في الممارسة العملية ، يتم استدعاء الوظيفة دون تحديد هذه الوسيطة (باستثناء المكالمة العودية داخل الوظيفة نفسها). لذلك ، يتم إنشاء كائن صفيف فارغ جديد واستخدامه لهذه الوسيطة. مثل أي مصفوفة عادية أخرى ، يحتوي كائن المصفوفة هذا على كائن Array.prototype كنموذج أولي له.

3 - تستدعي الدالة std_Array_push على كائن المصفوفة هذا. تؤدي وظيفة std_Array_push إلى استدعاء طريقة JavaScript Array.prototype.push. أثناء استخدام وظيفة std_Array_push بدلاً من Array.prototype.push تتجنب الآثار الجانبية إلى حد ما ، لا يزال بإمكان الوظيفة التفاعل مع النموذج الأولي للكائن. (لاحظ أنه في أماكن أخرى مختلفة في نفس ملف JavaScript المدمج /js/src/builtin/Module.js ، يتم استخدام وظيفة مختلفة لتعيين قيم الصفيف: DefineDataProperty. على عكس std_Array_push ، فإن DefineDataProperty آمن ولن يتفاعل ليس في بأي شكل من الأشكال مع النموذج الأولي للكائن.)

دلالات Array.prototype.push مع وسيطة واحدة تكافئ تقريبًا ما يلي:

والجدير بالذكر أن التخصيص لا يقتصر فقط على تعيين خاصية بيانات على الكائن نفسه. بدلاً من ذلك ، يبحث في سلسلة النموذج الأولي للكائن عن الخصائص الموجودة وفقًا لدلالات JavaScript العادية. إذا حددت الوحدة النمطية التي تم استيرادها دالة getter / setter للخاصية 0 في النموذج الأولي للصفيف (Array.prototype) ، فستقوم عملية التعيين هذه بتشغيل وظيفة المحدد. هذا الاستدعاء ينتهك تقنيًا مواصفات ECMAScript التي تحدد GatherAsyncParentCompl ...

لكنك أخبرتني أنك بخير: مهاجمة محرك عرض Mozilla Firefox (الجزء الأول)

غالبًا ما ترتبط الثغرات الأمنية وعمليات الاستغلال في الأهداف الشائعة مثل المتصفحات بمشكلات أمان الذاكرة. عادةً ما ينطوي هذا إما على خطأ مباشر في إدارة الذاكرة أو طريقة لإفساد الحالة الداخلية للكائن في محرك JavaScript. تتمثل إحدى طرق التخلص من مشكلات أمان الذاكرة هذه في استخدام لغة آمنة للذاكرة مثل Rust أو حتى JavaScript نفسها. في Pwn2Own Vancouver 2022 ، اخترق Manfred Paul متصفح Mozilla Firefox باستخدام ثغرة كاملة السلسلة التي كسرت القالب. على الرغم من أن استغلاله استخدم بعض تلف الذاكرة ، إلا أن الشفرة الضعيفة تمت كتابتها بلغة برمجة آمنة للذاكرة: JavaScript! في الواقع ، كانت الثغرات الأمنية المستخدمة في السلسلة مرتبطة بجانب سيئ السمعة إلى حد ما من لغة جافا سكريبت: النماذج الأولية. في هذه المدونة ، سوف نفحص أول ثغرة أمنية في السلسلة ، والتي تم استخدامها لخرق عملية عرض Mozilla Firefox. هذه الثغرة ، المعروفة باسم CVE-2022-1802 ، هي نموذج أولي لخطر التلوث في التنفيذ المعلق. يمكنك العثور على مزيد من المعلومات حول هذه الثغرة الأمنية على الصفحة الإرشادية لمبادرة Zero Day التي تم تعقبها كـ ZDI-22-799. عالجت Mozilla هذه الثغرة الأمنية في Firefox 100.0.2 عبر Mozilla Foundation Security Advisory 2022-19.

ملاحظة: تعتمد سلسلة المدونات هذه بشكل كبير على التفاصيل التي قدمها مانفريد بول أثناء مسابقة Pwn2Own.

المساومة في عملية العرض

تتميز JavaScript الحديثة ببنية الوحدة ، والتي تسمح للمطورين بتقسيم التعليمات البرمجية إلى ملفات فردية. الميزة الأحدث هي دعم الوحدات غير المتزامنة ، أو بشكل أكثر تحديدًا ، الميزة المعروفة باسم انتظار المستوى الأعلى. في محرك JavaScript في Firefox ، SpiderMonkey ، يتم تنفيذ الكثير من هذه الوظائف باستخدام كود JavaScript مدمج. ضع في اعتبارك الوظيفة التالية من قاعدة شفرة SpiderMonkey ، في /js/src/builtin/Module.js:

هناك ثلاث حقائق يجب أن نلاحظها في الكود أعلاه:

1 - تعمل هذه الوظيفة في نفس سياق JavaScript مثل كود المستخدم. هذا صحيح بالنسبة لمعظم الوظائف المستندة إلى JavaScript في Firefox. هذا يعني أن الحالة العالمية ، بما في ذلك النماذج الأولية للكائنات العالمية ، تتم مشاركتها بين كود التضمين هذا ورمز موقع الويب غير الموثوق به.

2 - تحتوي الدالة على وسيطة افتراضية هي execList = []. في الممارسة العملية ، يتم استدعاء الوظيفة دون تحديد هذه الوسيطة (باستثناء المكالمة العودية داخل الوظيفة نفسها). لذلك ، يتم إنشاء كائن صفيف فارغ جديد واستخدامه لهذه الوسيطة. مثل أي مصفوفة عادية أخرى ، يحتوي كائن المصفوفة هذا على كائن Array.prototype كنموذج أولي له.

3 - تستدعي الدالة std_Array_push على كائن المصفوفة هذا. تؤدي وظيفة std_Array_push إلى استدعاء طريقة JavaScript Array.prototype.push. أثناء استخدام وظيفة std_Array_push بدلاً من Array.prototype.push تتجنب الآثار الجانبية إلى حد ما ، لا يزال بإمكان الوظيفة التفاعل مع النموذج الأولي للكائن. (لاحظ أنه في أماكن أخرى مختلفة في نفس ملف JavaScript المدمج /js/src/builtin/Module.js ، يتم استخدام وظيفة مختلفة لتعيين قيم الصفيف: DefineDataProperty. على عكس std_Array_push ، فإن DefineDataProperty آمن ولن يتفاعل ليس في بأي شكل من الأشكال مع النموذج الأولي للكائن.)

دلالات Array.prototype.push مع وسيطة واحدة تكافئ تقريبًا ما يلي:

والجدير بالذكر أن التخصيص لا يقتصر فقط على تعيين خاصية بيانات على الكائن نفسه. بدلاً من ذلك ، يبحث في سلسلة النموذج الأولي للكائن عن الخصائص الموجودة وفقًا لدلالات JavaScript العادية. إذا حددت الوحدة النمطية التي تم استيرادها دالة getter / setter للخاصية 0 في النموذج الأولي للصفيف (Array.prototype) ، فستقوم عملية التعيين هذه بتشغيل وظيفة المحدد. هذا الاستدعاء ينتهك تقنيًا مواصفات ECMAScript التي تحدد GatherAsyncParentCompl ...

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow