LAB 001 / 00 · Introdução
Lendo dados de outro app pelo ContentProvider.
O primeiro lab do MobileSec LabNotes começou com uma pergunta: exigir uma permissão é suficiente para proteger os dados de um ContentProvider? Para investigar, usei o InsecureShop, um app Android feito para estudar vulnerabilidades.
O caminho foi analisar o APK no JADX, entender a permissão do provider e criar um app Kotlin para consultá-lo. Depois do login no InsecureShop, a PoC conseguiu ler o usuário e a senha armazenados.
O experimento foi feito em um emulador Android 17, sem root. Este guia registra o exercício em um alvo de treinamento; não é um relato de pentest em produção.
O ponto que vale entender
O provider exigia com.read, mas essa permissão era do tipo normal. Outro app podia solicitá-la no manifest. A presença de uma permissão, portanto, não criava a restrição de acesso que esses dados precisavam.
LAB 001 / 01 · ContentProviders e permissões
O que acontece quando um app faz a consulta?
Um ContentProvider é uma das formas de compartilhar dados entre apps Android. O cliente faz a consulta pelo ContentResolver e recebe um cursor com o resultado.
Neste lab, a URI é content://com.insecureshop.provider/insecure. A parte com.insecureshop.provider identifica o provider; /insecure é o caminho consultado.
Por que com.read não impediu a leitura?
Uma permissão normal é concedida na instalação quando o app a declara. Não há uma aprovação em runtime nem uma exigência de que os dois apps tenham a mesma assinatura. Esse é o detalhe que permite ao cliente do laboratório fazer a consulta.
Ao analisar um provider, confira também exported, as permissões de leitura e escrita e eventuais regras por caminho. É essa configuração, junto com o código do provider, que define quem consegue acessar o quê.
Referências: permissões Android e declaração de providers.
LAB 001 / 02 · Setup
Prepare o alvo e o app cliente.
Você vai precisar do Android Studio, de um emulador e do JADX. Os dois apps devem estar instalados no mesmo perfil do emulador.
- Obtenha o APK de treinamento a partir do projeto Optiv InsecureShop.
- Instale o APK no emulador e confirme que o app abre.
- Abra esse mesmo APK no JADX.
- No Android Studio, crie um projeto Kotlin separado para a PoC, com um application ID diferente do alvo.
O ambiente usado neste exercício foi um emulador Android 17 sem root. Para uma nova execução, registre também a versão e o hash do APK: eles ainda não constam nas notas deste lab e fazem diferença ao comparar resultados entre builds.
LAB 001 / 03 · Análise JADX
Comece pelo manifest, depois siga a consulta.
No JADX, procure a autoridade do provider no AndroidManifest.xml. Antes de olhar os dados retornados, entenda como o componente pode ser acessado.
- Localize
com.insecureshop.providere confira se o componente está exportado. - Veja qual permissão protege a leitura e encontre a declaração de
com.read. - Confira o protectionLevel. Quando ele não é declarado, o padrão é
normal. - Abra a classe do provider e siga o método
query, observando o tratamento do caminho/insecure. - Identifique de onde vêm os valores retornados e a relação deles com o login.
A pergunta aqui é bem específica: o app cliente consegue obter a permissão exigida e, com ela, ler dados que deveriam ficar restritos ao InsecureShop?
LAB 001 / 04 · PoC Kotlin
Faça a consulta com um app separado.
A PoC usa contentResolver.query para consultar a URI do InsecureShop. O cliente precisa declarar com.read no manifest.
Dentro do elemento manifest, adicione <uses-permission android:name="com.read" />. Instale o InsecureShop antes da PoC. Se a permissão ainda não existia quando o cliente foi instalado, reinstale o cliente.
// Educational reconstruction; not the original captured PoC.
// Add <uses-permission android:name="com.read" /> to the manifest.
val uri = android.net.Uri.parse("content://com.insecureshop.provider/insecure")
contentResolver.query(uri, null, null, null, null)?.use { cursor ->
while (cursor.moveToNext()) {
for (index in 0 until cursor.columnCount) {
val name = cursor.getColumnName(index)
val value = cursor.getString(index)
// Display only inside the controlled lab UI; avoid logging credentials.
}
}
}O trecho percorre as linhas e as colunas do cursor sem depender de nomes de campos presumidos. Em uma Activity, você pode ligar a consulta a um botão e mostrar o resultado em um TextView. Execute a consulta fora da thread principal e volte à thread de UI para atualizar a tela.
Trate três situações separadamente: cursor nulo, consulta sem linhas e erro de permissão. Elas apontam para problemas diferentes.
LAB 001 / 05 · Reprodução e evidência
Entre no alvo e execute a PoC.
Use a conta de treinamento do InsecureShop: shopuser / !ns3csh0p.
- Abra o InsecureShop e faça login com a conta do lab.
- Confirme que o login foi aceito.
- Abra a PoC no mesmo emulador e consulte
content://com.insecureshop.provider/insecure. - Compare o usuário e a senha retornados com os valores usados no login.

O resultado
A captura mostra a PoC exibindo shopuser e !ns3csh0p. Esse é o resultado registrado do exercício: outro app conseguiu ler as credenciais pelo provider.
A imagem foi preservada como enviada. O Android 17 e a ausência de root são informações do ambiente anotado; não podem ser verificados apenas pela captura. O experimento não foi reexecutado durante a montagem deste site.
LAB 001 / 06 · Troubleshooting
Se a consulta não trouxe o resultado esperado.
Antes de alterar o código, separe falha de permissão de ausência de dados.
A consulta pelo ADB deu erro de permissão
O shell do ADB e a PoC são clientes diferentes. A falha do shell não significa que um app declarando com.read terá o mesmo resultado. Confira a permissão no manifest do cliente e reinstale-o, se necessário.
O usuário e a senha vieram vazios
Confirme que o login no InsecureShop foi aceito antes de consultar. Verifique também se os dados do app foram apagados e se os dois apps estão no mesmo perfil do emulador. Um campo vazio é diferente de um cursor sem linhas.
O provider não foi encontrado ou houve SecurityException
Confira a URI caractere por caractere, a instalação do alvo e a permissão declarada pela PoC. Compare também o build do APK com o que você analisou no JADX. Se o código usa descoberta de pacotes, examine as regras de visibilidade separadamente da autorização de leitura.
LAB 001 / 07 · Mitigações
O que deveria mudar no provider?
A correção depende de uma decisão anterior: esse dado precisa mesmo ser compartilhado com outro app?
Se o provider só atende ao próprio InsecureShop, declare android:exported="false". Se existe um fluxo entre apps confiáveis com a mesma assinatura, uma permissão signature pode restringir esse acesso.
Em qualquer cenário, reveja o conteúdo retornado. Usuário e senha não deveriam fazer parte da resposta de uma consulta genérica. Limite os campos, os caminhos e as operações disponíveis ao que o fluxo realmente precisa.
Como verificar a correção
Repita a consulta com o app separado e confirme que ele deixou de receber os dados sensíveis. Se houver um cliente autorizado, teste também se seu fluxo continua funcionando.
Essas são propostas de correção. Este lab não inclui um build corrigido nem um resultado de teste após a mudança.