
PoC para CVE-2021-39749, que permite iniciar una Activity arbitraria en Android 12L Beta
Este es un PoC para CVE-2021-39749, que permite iniciar actividades de otras aplicaciones en Android 12L Beta independientemente de su configuración de permission y exported
En Android 12L, el acceso a TaskFragmentOrganizer (intencionalmente) ya no requiere el permiso MANAGE_ACTIVITY_TASKS
Usar la aplicación proporcionada aquí requiere deshabilitar Hidden API Checks, puedes hacerlo mediante adb shell settings put global hidden_api_policy 1. Estos no son un límite de seguridad y existen bypasses conocidos basados en aplicaciones
Aquí están los commits que corrigen este error (y algunos relacionados mencionados en el informe original):
startActivityInTaskFragment ya no depende de Binder.getCallingUid()ResolverActivity ahora tiene relinquishTaskIdentity habilitadoSurfaceControl de TaskFragment ya no se proporcionaActivityRecord#appToken a TaskFragmentOrganizer ahora se basa en uid en lugar de pidPuedes hacer checkout de android-12.1.0_r4, revertir los primeros 3 commits (o los primeros 2, la aplicación aún podrá apagar el dispositivo (iniciando ShutdownActivity), pero la casilla "Zoom and set alpha" no funcionará)
(El primer commit de esa lista tendrá conflictos de fusión en las pruebas si intentas revertirlo, pero puedes ignorarlos)
Binder.getCallingUid() que siempre devuelve el uid del sistemaEl método Binder.getCallingUid() devuelve el uid del proceso que envió la transacción Binder que se está procesando actualmente. Ese uid se almacena en una variable local al hilo. El código que maneja la transacción puede llamar a Binder.clearCallingIdentity() para establecer esa variable al uid de su propio proceso, indicando así a los métodos llamados posteriormente durante el manejo de la transacción que las comprobaciones de permisos deben realizarse contra sí mismo (el código que maneja la transacción) y no contra el llamador de la transacción Binder
A veces hay llamadas a Binder.getCallingUid() que siempre se ejecutan después de Binder.clearCallingIdentity(), por lo tanto siempre devuelven el uid del propio proceso. A veces esto ocurre intencionalmente, por ejemplo en ActivityTaskManagerService#startDreamActivity (aunque esa es una forma bastante enrevesada de hacer Process.myUid() o Os.getuid())
He escrito para mí mismo una herramienta de análisis estático (basada en Soot) que reporta dichas llamadas a Binder.getCallingUid() (y otras comprobaciones de permisos) que solo pueden ocurrir después de Binder.clearCallingIdentity(). (Tengo lógica personalizada para manejar el IR Jimple/Shimple proporcionado por Soot, aunque podría haber una mejor manera de hacerlo con Soot, pero es lo que tengo ahora)
En Android 12L Beta, esa herramienta encontró una en ActivityStartController#startActivityInTaskFragment (Nota: el código fuente no estaba disponible entonces ya que las versiones Beta no son de código abierto, pero Shimple es generalmente legible, así que he estado usando Soot también como descompilador de Java)
startActivityInTaskFragmentComo parte del informe de análisis estático, obtuve la jerarquía de llamadas desde la implementación de onTransact() (donde comienza la llamada Binder) hasta startActivityInTaskFragment:
onTransact en el código generado por aidl de IWindowOrganizerControllerWindowOrganizerController#applyTransaction (sin el argumento CallerInfo)WindowOrganizerController#applyTransaction (con el argumento CallerInfo)WindowOrganizerController#applyHierarchyOpActivityStartController#startActivityInTaskFragmentDescubrí que las llamadas Binder a applyTransaction están presentes en la clase TaskFragmentOrganizer y decidí usarla como un envoltorio más conveniente que hacer todas las llamadas Binder directamente (ninguna es API pública, así que tuve que usar reflexión de todos modos)
En primer lugar, el método "2." llama a enforceTaskPermission, que en Android 12.0 comprobaba el permiso MANAGE_ACTIVITY_TASKS solo de signature, que no podíamos obtener. Sin embargo, en Android 12L las reglas se relajaron para que ciertas transacciones puedan realizarse sin permisos. Resultó que ninguna de las operaciones necesarias para realizar startActivityInTaskFragment requería un permiso (si la transacción tenía un TaskFragmentOrganizer asociado)
Así que queremos realizar HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT. Para hacerlo, debemos tener nuestro TaskFragment registrado en mLaunchTaskFragments; de lo contrario, se reportará la excepción "Not allowed to operate with invalid fragment token"