Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

الخلاصاتاتصالالخصوصية© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
TheLastBundleMismatch — كتابة وتحليل واستغلال لثغرة CVE-2023-45777، تجاوز للتحقق من Intent داخل AccountManagerService على أندرويد 13 على الرغم من تخفيف "Lazy Bundle" | Kitploit
أدوات/GitHubGitHub/michalbednarski/thelastbundlemismatch
أمان أندرويدتحليل الثغرات الأمنيةالاستغلالتحليل الملفات الثنائيةالأوراق والأبحاث
GitHubmichalbednarski/thelastbundlemismatch

TheLastBundleMismatch

كتابة وتحليل واستغلال لثغرة CVE-2023-45777، تجاوز للتحقق من Intent داخل AccountManagerService على أندرويد 13 على الرغم من تخفيف "Lazy Bundle"

عرض المستودع

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
1011468منذ 2 سنواتتمت المراجعة من قبل Kitploit

التصحيح الغامض

لنبدأ هذه المرة بالتصحيح الذي ظهر كإصلاح لـ CVE-2023-45777 في نشرة أمان أندرويد:```diff diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 7a19d034c2c8..5238595fe2a2 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4923,7 +4923,7 @@ public class AccountManagerService p.setDataPosition(0); Bundle simulateBundle = p.readBundle(); p.recycle();

  •        Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
    
  •        Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
           if (intent != null && intent.getClass() != Intent.class) {
               return false;
           }
    
قليل من الناس كانوا محتارين بشأنها بما يكفي لسؤالي، وقد ردّيت عليهم سابقًا ببعض التلميحات، والآن أنشر الشرح الكامل لهذه المشكلة

لكن أولًا دعونا نوفر بعض السياق حول ما يحدث في هذا التصحيح

هذا تغيير في [`checkKeyIntent()` method](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/accounts/AccountManagerService.java;l=4938-4954;drc=47de64a38aa1799cb41f41b2ea0c539ee61de64d). تقوم هذه الطريقة بإجراء عدة فحوصات للتأكد من أن `Intent` المقدَّم من التطبيق آمن للنظام لإطلاقه (باستخدام صلاحيات النظام)

أولًا، تستخدم هذه الطريقة `checkKeyIntentParceledCorrectly()` التي تقوم بتسلسل وإعادة تسلسل `Bundle` الذي نفحصه وتتحقق مما إذا كان `Intent` المأخوذ من `Bundle` قبل ذلك يطابق `Intent` من `Bundle` بعد هذه الدورة. نظرًا لأن إطلاق `Intent` يحدث في عمليات تطبيقات نظام أخرى غير تلك التي تقوم بالتحقق، كان [من الممكن سابقًا إنشاء `Bundle`-s تبدو آمنة أثناء التحقق داخل `AccountManagerService`، ولكنها تحتوي على `Intent` مختلف بعد إرسالها إلى العملية التالية](https://github.com/michalbednarski/IntentsLab/issues/2#issuecomment-344365482). هذا يحاكي إرسال `Bundle` إلى العملية التالية من أجل اكتشاف مثل هذه الحالات.

بعد `checkKeyIntentParceledCorrectly()` لدينا استدعاء `bundle.getParcelable()`، وهذا التصحيح يحوّله من الإصدار القديم الذي كان يمكنه إنشاء أي كائن إلى إصدار يتحقق من أن الكائن الذي سيتم إلغاء تسلسله هو من النوع المحدد في المعامل الثاني

هذا الإصدار مع معامل النوع تم تقديمه في Android 13، كجزء من تعزيز أكبر لـ `Parcel`/`Bundle`. على وجه الخصوص، قبل Android 13 عندما كان يتم إرسال `Bundle` بين العمليات، كان يحتفظ بنسخة خام من كامل البيانات المسلسلة حتى يتم الوصول إلى أي عنصر، وعندها يتم إلغاء تسلسل كل قيمة. الآن عندما يتم الوصول إلى أي قيمة لأول مرة بعد استلام `Bundle`، يتم إلغاء تسلسل مفاتيح `String` وقيم الأنواع البدائية فقط، بينما تُترك القيم غير البدائية كـ `LazyValue`-s، التي يتم تخزين طولها كجزء من البيانات المسلسلة لضمان أنه حتى عندما يكون منطق التسلسل/إلغاء التسلسل غير متطابق، فإن هذه الاختلافات لن تؤثر على الإدخالات الأخرى

قبل أن نتعمق، دعونا نلقي نظرة على `LazyValue`: في الكود المصدري الخاص به [لدينا تعليق جميل يشرح بنية بياناته](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Parcel.java;l=4392-4399;drc=03c34f57c05feecfb090de3917787f049cb5f804)```
                     |   4B   |   4B   |
mSource = Parcel{... |  type  | length | object | ...}
                     a        b        c        d
length = d - c
mPosition = a
mLength = d - a

mPosition وmLength يصفان موقع بيانات LazyValue كاملة في Parcel الأصلية، بما في ذلك type وlength. تشير "length" (بدون "m" في البداية) إلى قيمة الطول كما كُتبت في Parcel وتستثني الترويسة (type وlength)

إذا تم إعادة توجيه Bundle الذي يحتوي على LazyValue إلى عملية أخرى، يتم نسخ LazyValue كاملة بما في ذلك حقلي type وlength حرفياً من Bundle.mParcelledData إلى Parcel الوجهة

عند الوصول إلى عنصر Bundle الممثل بواسطة LazyValue، يتم إرجاع Parcel إلى mPosition ويتم استدعاء readValue(). إذا تم تمرير وسيط نوع إلى bundle.getParcelable()، فسيتم تمريره إلى readValue() الذي سيضمن أن النوع الذي سيتم إلغاء تسلسله هو النوع المتوقع وكذلك التحقق بعد إلغاء التسلسل من أن نوع القيمة المُلغى تسلسلها هو النوع المتوقع. بعد إلغاء التسلسل، يتم استبدال LazyValue بحيث في المرة القادمة التي يُكتب فيها Bundle إلى Parcel، سيتم تسلسل القيمة عبر writeValue() مرة أخرى

استخدام وسيط النوع في Bundle.get*()/Parcel.read*() ذو صلة بشكل أساسي بطرق مثل Parcel.readParcelableList()، والتي تُرجع ArrayList وبسبب محو النوع في جافا (Java Type Erasure) حتى لو قمت بشيء مثل List<SomeParcelableType> field = parcel.readParcelableList();، فإن الجزء <SomeParcelableType> لم يكن مفروضاً في وقت التشغيل ويمكن لمثل هذه List أن تحتوي على أي فئات Parcelable متاحة في النظام وبالتالي يمكن استخدام جميع createFromParcel/writeToParcel المتاحة في النظام كجزء من التسلسل/إلغاء التسلسل للنوع الذي يحتوي على مثل هذه List

قد ترغب أيضاً في الاطلاع على عرض تقديمي من فريق أمان وخصوصية أندرويد حول تقديم هذه الآليات (الشرائح، الفيديو)

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

الآثار الجانبية

ألقِ نظرة على التصحيح من البداية مرة أخرى

  • إذا كانت القيمة المُلغى تسلسلها تحت مفتاح "intent" هي Intent
    • سيتم التحقق من أنها تشير إلى مكوّن آمن للنظام تشغيله
    • إذا كان من الممكن إحداث عدم تطابق من كائن Intent فسنواجه مشكلة أكبر بكثير
  • إذا كانت القيمة المُلغى تسلسلها ليست Intent
    • من أجل القيام بأي شيء ضار، سنحتاج إلى وجود Intent داخل Bundle بعد إرساله إلى عملية أخرى، لكن نوع Parcelable يُحفظ في إزاحة أبكر من أي عدم تطابق محتمل ويمنعنا تحديد طول LazyValue من تعديل أزواج المفاتيح-القيم التالية في حالة عدم تطابق writeToParcel/createFromParcel

إذن، ما الشيء الخطير الذي يمكن أن يفعله استدعاء bundle.getParcelable(AccountManager.KEY_INTENT) بدون وسيط نوع هنا؟

[الإجابة في الفقرة التالية، حاول التخمين قبل المتابعة. إذا كان لدي شخصية حيوانية (fursona) لكان هذا مكاناً لبعض الفنون]

الإجابة هي استدعاء createFromParcel() غير ذي صلة الذي يعدّل فعلياً البيانات الخام لـ LazyValue المخزنة تحت مفتاح مختلف والتي سيتم تمريرها حرفياً إلى العملية التالية

لدينا تنفيذ createFromParcel() يمكنه فعلياً استدعاء writeInt() على Parcel المقدمة

تنزيل الأداة