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