
إثبات المفهوم (PoC) لـ CVE-2021-39749، والذي يسمح بتشغيل أي نشاط (Activity) على Android 12L Beta
هذا هو PoC لـ CVE-2021-39749، والذي يسمح بتشغيل أنشطة تطبيقات أخرى على Android 12L Beta بغض النظر عن إعدادات permission و exported الخاصة بها
في Android 12L، الوصول إلى TaskFragmentOrganizer (عن قصد) لم يعد يتطلب صلاحية MANAGE_ACTIVITY_TASKS
يتطلب استخدام التطبيق المقدم هنا تعطيل فحوصات واجهات برمجة التطبيقات المخفية، يمكنك القيام بذلك عبر adb shell settings put global hidden_api_policy 1. هذه ليست حدودًا أمنية وهناك تجاوزات معروفة قائمة على التطبيقات
فيما يلي الالتزامات (commits) التي تصلح هذا الخطأ (وبعض الأخطاء ذات الصلة المذكورة في التقرير الأصلي):
startActivityInTaskFragment لم يعد يعتمد على Binder.getCallingUid()ResolverActivity الآن لديها relinquishTaskIdentity مفعّلةSurfaceControl الخاص بـ TaskFragment لم يعد متاحًاActivityRecord#appToken إلى TaskFragmentOrganizer أصبح الآن يعتمد على uid بدلاً من pidيمكنك التحقق من android-12.1.0_r4، وعكس أول 3 التزامات (أو أول 2، سيظل التطبيق قادرًا على إيقاف تشغيل الجهاز (عن طريق تشغيل ShutdownActivity)، لكن خانة الاختيار "Zoom and set alpha" لن تعمل)
(سيكون للالتزام الأول من تلك القائمة تعارضات دمج في الاختبارات إذا حاولت عكسه، ولكن يمكنك تجاهلها)
Binder.getCallingUid() الذي يعيد دائمًا uid النظامطريقة Binder.getCallingUid() تعيد uid العملية التي أرسلت معاملة Binder التي تتم معالجتها حاليًا. يتم تخزين هذا uid في متغير محلي للخيط. يمكن للكود الذي يعالج المعاملة استدعاء Binder.clearCallingIdentity() لتعيين هذا المتغير إلى uid العملية الخاصة به للإشارة إلى الطرق التي سيتم استدعاؤها لاحقًا أثناء معالجة المعاملة بأنه يجب إجراء فحوصات الصلاحيات ضد نفسه (الكود الذي يعالج المعاملة) وليس ضد مستدعي معاملة Binder
في بعض الأحيان توجد استدعاءات Binder.getCallingUid() التي يتم استدعاؤها دائمًا بعد Binder.clearCallingIdentity()، وبالتالي تعيد دائمًا uid العملية الخاصة. في بعض الأحيان يحدث هذا عن قصد، على سبيل المثال في ActivityTaskManagerService#startDreamActivity (على الرغم من أن هذه طريقة ملتوية إلى حد ما للقيام بـ Process.myUid() أو Os.getuid())
لقد كتبت لنفسي أداة تحليل ثابتة (قائمة على Soot) تبلغ عن استدعاءات Binder.getCallingUid() هذه (وفحوصات صلاحيات أخرى) التي يمكن أن تحدث فقط بعد Binder.clearCallingIdentity(). (لدي منطق مخصص للتعامل مع Jimple/Shimple IR المقدم من Soot، على الرغم من أنه قد تكون هناك طريقة أفضل للقيام بذلك مع Soot، لكن هذا ما لدي الآن)
في Android 12L Beta وجدت تلك الأداة واحدًا في ActivityStartController#startActivityInTaskFragment (ملاحظة: الكود المصدري لم يكن متاحًا آنذاك لأن إصدارات Beta ليست مفتوحة المصدر، لكن Shimple قابل للقراءة بشكل عام لذلك كنت أستخدم Soot أيضًا كمفكك شفرة Java)
startActivityInTaskFragmentكجزء من تقرير التحليل الثابت حصلت على تسلسل الاستدعاءات من تنفيذ onTransact() (حيث تبدأ استدعاءات Binder) إلى startActivityInTaskFragment:
onTransact في الكود المولد بواسطة aidl لـ IWindowOrganizerControllerWindowOrganizerController#applyTransaction (بدون وسيط CallerInfo)WindowOrganizerController#applyTransaction (مع وسيط CallerInfo)WindowOrganizerController#applyHierarchyOpActivityStartController#startActivityInTaskFragmentلقد وجدت أن استدعاءات Binder إلى applyTransaction موجودة في فئة TaskFragmentOrganizer وقررت استخدامها كغلاف أكثر ملاءمة من القيام بجميع استدعاءات Binder مباشرة (لا يعتبر أي منهما واجهة برمجة تطبيقات عامة لذا كان علي استخدام الانعكاس على أي حال)
أولاً وقبل كل شيء، الطريقة "2." تستدعي enforceTaskPermission، والتي في Android 12.0 كانت تتحقق من صلاحية MANAGE_ACTIVITY_TASKS المقتصرة على signature والتي لم نتمكن من الحصول عليها، ومع ذلك في Android 12L تم تخفيف القواعد بحيث يمكن إجراء معاملات معينة دون صلاحيات. اتضح أن أياً من العمليات المطلوبة للقيام بـ startActivityInTaskFragment لم تتطلب صلاحية (إذا كانت المعاملة مرتبطة بـ TaskFragmentOrganizer)
لذلك نريد تنفيذ HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT. للقيام بذلك يجب أن يكون لدينا TaskFragment مسجل في mLaunchTaskFragments وإلا سيتم الإبلاغ عن استثناء "Not allowed to operate with invalid fragment token"
يمكننا تسجيل مثل هذا TaskFragment من خلال HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT، والذي يستدعي createTaskFragment()