
PoC para CVE-2021-39749, permitindo iniciar Activity arbitrária no Android 12L Beta
Este é um PoC para CVE-2021-39749, que permite iniciar atividades de outros aplicativos no Android 12L Beta, independentemente das configurações de permission e exported
No Android 12L, o acesso ao TaskFragmentOrganizer (intencionalmente) não requer mais a permissão MANAGE_ACTIVITY_TASKS
Usar o aplicativo fornecido aqui requer desabilitar as Hidden API Checks; você pode fazer isso através de adb shell settings put global hidden_api_policy 1. Estas não são uma fronteira de segurança e existem bypasses conhecidos baseados em aplicativos
Aqui estão os commits que corrigem este bug (e alguns relacionados mencionados no relatório original):
startActivityInTaskFragment não depende mais de Binder.getCallingUid()ResolverActivity agora tem relinquishTaskIdentity habilitadoSurfaceControl de TaskFragment não é mais fornecidoActivityRecord#appToken para TaskFragmentOrganizer agora é baseada em uid em vez de pidVocê pode fazer checkout de android-12.1.0_r4, reverter os primeiros 3 commits (ou os primeiros 2; o aplicativo ainda será capaz de desligar o dispositivo (iniciando ShutdownActivity), mas a caixa de seleção "Zoom and set alpha" não funcionará)
(O primeiro commit dessa lista terá conflitos de merge nos testes se você tentar revertê-lo, mas você pode ignorá-los)
Binder.getCallingUid() que sempre retorna uid do sistemaO método Binder.getCallingUid() retorna o uid do processo que enviou a transação Binder atualmente processada. Esse uid é armazenado em uma variável local de thread. O código que manipula a transação pode chamar Binder.clearCallingIdentity() para definir essa variável para o uid do próprio processo, indicando aos métodos chamados posteriormente durante o tratamento da transação que as verificações de permissão devem ser feitas contra si mesmo (código que manipula a transação) e não contra o chamador da transação Binder
Às vezes há chamadas Binder.getCallingUid() que são sempre chamadas após Binder.clearCallingIdentity(), portanto sempre retornam o uid do próprio processo. Às vezes isso acontece intencionalmente, por exemplo em ActivityTaskManagerService#startDreamActivity (embora seja uma maneira bastante complicada de fazer Process.myUid() ou Os.getuid())
Escrevi para mim mesmo uma ferramenta de análise estática (baseada em Soot) que relata tais chamadas Binder.getCallingUid() (e outras verificações de permissão) que só podem ocorrer após Binder.clearCallingIdentity(). (Tenho lógica personalizada para manipular o IR Jimple/Shimple fornecido pelo Soot, embora possa haver uma maneira melhor de fazer isso com Soot, mas é o que tenho agora)
No Android 12L Beta, essa ferramenta encontrou uma em ActivityStartController#startActivityInTaskFragment (Nota: o código-fonte não estava disponível na época, pois as versões Beta não são open source, mas Shimple é geralmente legível, então usei Soot também como decompilador Java)
startActivityInTaskFragmentComo parte do relatório de análise estática, obtive a hierarquia de chamadas da implementação de onTransact() (onde a chamada Binder começa) até startActivityInTaskFragment:
onTransact no código gerado por aidl de IWindowOrganizerControllerWindowOrganizerController#applyTransaction (sem o argumento CallerInfo)WindowOrganizerController#applyTransaction (com o argumento CallerInfo)WindowOrganizerController#applyHierarchyOpActivityStartController#startActivityInTaskFragmentDescobri que chamadas Binder para applyTransaction estão presentes na classe TaskFragmentOrganizer e decidi usá-la como um wrapper mais conveniente do que fazer todas as chamadas Binder diretamente (nenhuma é API pública, então tive que usar reflexão de qualquer maneira)
Primeiro de tudo, o método "2." chama enforceTaskPermission, que no Android 12.0 verificava a permissão MANAGE_ACTIVITY_TASKS somente-signature, que não podíamos obter; no entanto, no Android 12L as regras foram relaxadas para que certas transações pudessem ser feitas sem permissões. Descobriu-se que nenhuma das operações necessárias para fazer startActivityInTaskFragment exigia permissão (se a transação tivesse um TaskFragmentOrganizer associado)
Então queremos executar HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT. Para fazer isso, devemos ter nosso TaskFragment registrado em mLaunchTaskFragments; caso contrário, a exceção "Not allowed to operate with invalid fragment token" será relatada