DIVA (Damn insecure and vulnerable App) é um aplicativo que foi projetado intencionalmente com vulnerabilidades para que profissionais de segurança e desenvolvedores pudessem testar e entender como as principais falhas acontecem em aplicativos Android. Nessa postagem eu vou mostrar como resolvi todos os desafios presentes no app.
Preparando o ambiente
O aplicativo do projeto pode ser encontrado no repositório do GitHub nesse endereço: https://github.com/payatu/diva-android
Primeiro, é necessário realizar o download do app, no meu caso eu clonei o repositório para a minha máquina usando o git clone
Depois disso, basta entrar no diretório clonado e instalar o apk no dispositivo
Se tudo ocorreu sem problemas, já é possível abrir o app e começar os testes
Fazendo a Engenharia Reversa
Para iniciar o teste, primeiramente é necessário realizar a engenharia reversa do apk para conseguir acesso ao código fonte da aplicação. Para esse fim vou utilizar a ferramenta “jadx”
jadx-gui [app.apk]
Como o aplicativo não possui nenhuma proteção, é possível ter acesso ao código fonte da aplicação em texto claro
Desafio 1 - Log Inseguro
O primeiro desafio é sobre Log Inseguro. É necessário descobrir que informação sensível está sendo logada
Como o desafio se trata de encontrar logs, vou iniciar o log cat
adb shell logcat
Com isso começo a visualizar todos os logs gerados pelo dispositivo
Ainda nessa aba da aplicação, existe um campo para informar o número do cartão de crédito
A fim de entender o comportamento do app, enviei um número qualquer como cartão de crédito
E analisando os logs gerados, foi possível identificar que ao gerar um erro na transação o app acaba mostrando nos logs o número do cartão de crédito dos usuários
Desafio 2 - Problemas na codificação
Para o segundo desafio é necessário encontrar o que e onde está sendo gerada essa vulnerabilidade “hardcoded”
Nessa mesma aba é necessário informar um “vendor key”, para ter acesso a funcionalidade do app
Para achar esse vendor key é preciso fazer a engenharia reversa desse app, o que já foi feito anteriormente com o jadx
jadx-gui [app.apk]
Analisando o código da aplicação é possível encontrar a Activity que possui a função de validação do código enviado e, no processo de comparação de valores, temos o valor que o app espera receber, em texto claro
Agora, basta retornar ao app e enviar a key encontrada
Desafio 3 - Armazenamento inseguro de dados (parte 1)
Para esse desafio o objetivo é encontrar onde e como as credenciais são armazenadas e o código onde acontece a vulnerabilidade
Analisando o código do app é possível identificar que o aplicativo armazena as credenciais informadas em um “shared preference”
Para visualizar esse arquivo, através do adb shell, fui até o diretório onde o app está armazenado
Acessando o diretório do app, é possível ver que a pasta “shared_prefs” ainda não existe
Isso acontece, provavelmente, por que o recurso ainda não foi utilizado no app. Então, enviei um usuário e uma senha para o aplicativo e novamente listei o conteúdo da pasta
Agora, é possível visualizar a pasta “shared_prefs”, e, dentro dela é possível encontrar um arquivo xml
Lendo o conteúdo desse arquivo, encontramos as credenciais informadas no app e armazenadas em texto claro
Desafio 4 - Armazenamento inseguro de dados (parte 2)
Assim como na primeira parte do desafio, o objetivo da parte 2 é encontrar os dados e o código vulnerável
Fazendo a analise do código fonte, é possível identificar que o app está usando SQLite e que a aplicação salva as credenciais dentro da tabela “myuser”
Então, fui até o diretório onde as informações do app estão salvas, e listei as bases de dados
Como visto no código fonte, a base de dados utilizada é a “ids2”. Utilizando o sqlite3 realizei a leitura da base de dados e consegui encontrar as credenciais armazenadas em texto claro
Desafio 5 - Armazenamento inseguro de dados (parte 3)
Essa é a terceira parte do desafio, e assim como as partes anteriores o objetivo é encontrar as credenciais armazenadas
Analisando o código fonte da aplicação, é possível identificar que a aplicação cria um arquivo temporário chamado “uinfo…”
Então, fui até o diretório onde o app está salvo e listei todo o conteúdo, porém, não existe nenhum arquivo com esse padrão de nome
Após isso, enviei minha credenciais no app e novamente realizei a listagem do diretório. Agora um arquivo “uinfo…” apareceu
Realizando a leitura do mesmo, é possível encontrar as credenciais enviadas armazenadas em texto claro
Desafio 6 - Armazenamento inseguro de dados (parte 4)
A última parte do desafio sobre armazenamento inseguro segue a mesma premissa das outras 3
Analisando o código fonte do app é possível identificar que o aplicativo salva as credenciais enviadas em um armazenamento externo dentro de um arquivo chamado “.uinfo.txt”
Então, fui até o diretório de armazenamento externo e realizei a listagem de arquivos
cd /mnt/sdcard
Dessa forma foi possível encontrar o arquivo “.uinfo.txt”, então, bastou realizar a leitura do arquivo para encontrar as credenciais
Desafio 7 - Problema na validação de inputs (parte 1)
Para o desafio 7 o objetivo é conseguir acessar informações de todos os usuários da base de dados sem saber o nome de nenhum deles
Para entender o comportamento do app, eu habilitei o logcat no dispositivo e enviei no campo de consulta uma “ ‘ “ (aspa simples). Analisando o log, foi possível encontrar um erro de sql onde se pode ver a query utilizada para consulta
Com essa informação, já é possível descobrir o tipo de consulta que pode ser realizado para listar todos os usuários, então em uma nova consulta enviei o payload e consegui resolver o desafio
Desafio 8 - Problema na validação de inputs (parte 2)
Para a segunda parte do desafio o objetivo é tentar acessar alguma informação sensível através do campo de url
Colocando um site qualquer, o app tenta mostrar o seu conteúdo logo abaixo do campo de pesquisa
Com isso, tentei realizar uma nova consulta, passando no lugar do protocolo o ‘file://’ e o caminho de um dos arquivos do desafio de armazenamento inseguro, e assim consegui ver o conteúdo
Desafio 9 - Controle de Acesso (parte 1)
Para o desafio 9 o objetivo é conseguir acesso as informações das credenciais de API sem clicar no botão
Para entender como a aplicação funciona, cliquei no botão e logo em seguida o app me mostra as credenciais de API
Então, para começar o desafio, fechei o app e fui olhar o código do apk. Dentro do Android Manifest foi possível encontrar essa activity
Como pode ser visto, essa activity possui a tag “itent-filter”, essa tag faz com que a activity seja exportada publicamente por padrão, e permite que ela seja usada diretamente ou por outros apps
Para utilizar essa activity diretamente vou usar o am e chamar ela direto pelo terminal
adb shell am start jakhar.aseem.diva/.APICredsActivity
Com o comando acima a activity foi iniciada, caso queira executar uma ação específica da activity pode-se usar outra sintaxe
adb shell am start -n [activity] -a [ação]
Desafio 10 - Controle de Acesso (parte 2)
Para resolver a segunda parte do desafio é necessário acessar as credenciais da API sem usar o botão de “já estou cadastrado”
Quando usamos a opção “Register Now” o app pede que você entre no site e realize o cadastro
Clicando na opção “Already Registered” o app mostra as credenciais
Então, assim como na primeira parte do desafio, realizei uma analise do código da aplicação, começando pelo Android Manifest, e da mesma forma foi possível encontrar a activity responsável por essa função
Como essa activity também possui a tag “intent-filter”, tentei utilizar o mesmo método do desafio anterior, porém, dessa vez o app abriu a página para se registrar
Após isso, analisei os logs do dispositivo para entender se o app utilizava activities diferentes para cada função, então descobri que a activity era a mesma nos dois casos. Imaginei então que no código deveria ter alguma validação para descobrir se o usuário já está cadastrado e analisando o código do apk encontrei essa validação
Foi possível identificar que o app verifica se o parâmetro “chk_pin” é “true”, se sim ele mostra a página para realizar o cadastro, então novamente tentei iniciar essa activity mas dessa vez passando esse parâmetro como argumento e setando ele como falso, para mudar a lógica da aplicação
Novamente o app abriu a página para realizar o cadastro
Isso acontece provavelmente porque o nome dessa variável “chk_pin” deve estar sendo passada de forma diferente pelo app
Para tentar descobrir qual nome estava sendo usado utilizei o apktool para extrair os arquivos presentes no apk
Dentro dos diretórios extraídos, existe um arquivo chamado “strings.xml”, com algumas informações de valores usados pelo app
Então realizei uma busca dentro desse arquivo e assim foi possível descobrir que o nome usado para essa variável era na verdade “check_pin”
Com essa informação, bastou somente iniciar novamente essa activity, mas dessa vez passando o nome correto da variável
Desafio 11 - Controle de Acesso (parte 3)
Para a última parte do desafio, o objetivo é conseguir acessar as notas salvas no app sem saber o pin
Na página inicial, o app pede pare que seja setado um número de pin, e, após isso, aparece uma opção para visualizar as notas privadas
Nessa opção, ao informar o número de pin correto é possível ver as notas salvas, se o pin estiver errado o app mostra uma mensagem de erro
Então, comecei realizando a analise do código da aplicação, começando pelo android manifest, nele foi possível identificar que o provider possui o atributo “android.exported” como “True”, o que permite que essa função seja acessada publicamente
Para conseguir acessar esse provider é preciso informar a uri. Através da analise do código, foi possível identificar o seu endereço
Com isso já é possível realizar a consulta
adb shell content query --uri content://jakhar.aseem.diva.provider.notesprovider/notes
Desafio 12 - Bibliotecas vulneráveis
O objetivo do desafio 12 é tentar encontrar o “vendor key” que está armazenado hardcoded
Fazendo a analise do código fonte, é possível identificar que a Activity responsável pela validação está utilizando uma função privada chamada “DivaJni”
O nome “Jni” é o nome de uma biblioteca do Java usada para fazer integração com outras linguagens de programação
Analisando a classe “DivaJni” é possível ver que o app carrega uma biblioteca chamada “divajni”
Nos arquivos extraídos com o apktool foi possível encontrar esse arquivo e descobrir que ele é um arquivo do tipo ELF
Então, utilizei o objdump para tentar ler algumas informações desse arquivo, na seção “.rodata” onde normalmente são armazenadas as constantes, encontrei uma string
objdump.exe -s .\libdivajni.so
Então, para validar copiei essa string e coloquei no app, e assim descobri que esse era o valor da vendor key
Desafio 13 - Memory Corruption
O objetivo do último desafio do app é conseguir fazer o app travar utilizando o campo para enviar strings
Analisando o código fonte é possível identificar que essa função do app utiliza o mesmo arquivo ELF do desafio anterior
Então, fui enviando alguns caracteres e quando chegou em 40 caracteres o app acabou travando
Analisando o log, é possível identificar que o que aconteceu com a aplicação foi um “buffer overflow”
Para entender o motivo da falha, fui até o github e fiz a leitura do código usado pelo ELF, e foi possível identificar que o app espera receber no máximo 20 caracteres, porém ele utiliza uma função vulnerável (strcpy) que acaba copiando a quantidade de caracteres que o usuário envia sem nenhum limite de tamanho