Resolvendo OWASP crackme level 1 com Android Studio + bytecode viewer

Jeferson Oliveira
Android Dev BR
Published in
7 min readOct 22, 2022

--

Hoje vou iniciar uma série sobre o popular Framework de segurança da informação, OWASP; mais especificamente sobre os materiais públicos do MSTG ou Mobile Security Testing Guide.

Nessa série vamos focar nos desafios sugeridos (Crackme challenges) e suas peculiaridades.

Vamos lá?

Observe o escopo do desafio

Aplicativos móveis indecifráveis

Bem-vindo ao UnCrackable Apps para Android, uma coleção de desafios de engenharia reversa móvel. Esses desafios são usados ​​como exemplos em todo o Mobile Security Testing Guide. Claro, você também pode resolvê-los por diversão.Este aplicativo guarda um segredo dentro. Você pode encontrá-lo?

Objetivo: Uma string secreta está escondida em algum lugar neste aplicativo. Encontre uma maneira de extraí-lo.

Autor: Bernhard Mueller .

Mantido pelos líderes OWASP MSTG.

repositório: https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01

Fique à vontade para explorar o repositório depois de ler esse artigo e analisar outras soluções já publicadas por lá.

Basicamente temos um desafio do tipo “capture a bandeira”, algo bem interessante para compreender algumas estruturas de segurança no Android.

Será que vamos conseguir recuperar essa chave?

Antes de começarmos, algumas observações muito importantes:

Você deve ter um ambiente básico para análise de malware configurado, verifique como fazer isso:

Aqui: https://www.geeksforgeeks.org/virtual-machine-for-malware-analysis/

Aqui: https://loungefly84.medium.com/building-a-malware-analysis-lab-6e080f78211f

Softwares utilizados no artigo: Android Studio, Ubuntu, Bytecode-viewer

Ambiente pronto…

Vamos ao primeiro passo, baixar o arquivo apk, instalá-lo em um emulador e verificar seu comportamento.

Com o aplicativo instalado no emulador você verá algo como o apresentado abaixo:

Tela com um campo para preenchimento do segredo e um botão de validação

É possível observar que o aplicativo tem uma tela com um campo texto e um botão validador da dita palavra secreta.

Após entrar com um valor aleatório recebemos uma validação de tela com a informação de que o segredo está incorreto.

Já identificamos o ponto de entrada da nossa chave, agora vamos observar outros pontos importantes.

  • É possível identificar que a validação é iniciada pelo botão “verify”
  • É possível verificar que um dialog nativo do android é acionado em caso de falha na validação.
  • Identificamos que a validação ocorreu localmente, tendo em vista que estamos usando um ambiente sem conexão direta à internet.

Com o teste funcional realizado, vamos realizar uma análise estática no aplicativo, basicamente vamos inspecionar o arquivo apk a fim de obter informações úteis sobre os processos apresentados nos tópicos anteriores.

Android Studio Apk Analyzer

Para isso, vá até o local do arquivo .apk, em opções execute o mesmo com o Android Studio, algo como a tela abaixo deve aparecer.

Android Studio — App analyzer

Ao acessar o arquivo APK, no Android Studio analyzer conseguimos visualizar a estrutura básica do aplicativo compilado, com seus arquivos dex, manifest e resources.

Precisamos ter em mente algumas coisas para uma boa análise estática caixa preta de um app, escopo do problema, ciclo de vida do Android e ponto de entrada/saída de dados.

Sobre a analise proposta:
https://www.nowsecure.com/blog/2019/09/25/5-misconceptions-about-dynamic-application-security-testing-dast-for-mobile/

Sobre ciclo de vida dos apps android:
https://developer.android.com/guide/components/activities/activity-lifecycle?hl=pt-br

Para cada um desses passos vamos realizar verificações.

1 — Devemos identificar as principais activitys do APP e o comportamento de seus métodos do ciclo de vida como onCreate(), onStart(), onResume(), onPause(), onStop() e onDestroy() .

2 — Para o ponto de entrada, podemos identificar chamadas ao getText() do edittext por exemplo, esse trecho será um bom ponto de orientação.

3 — Para o ponto de saída devemos observar string de título do diálogo de erro, sua mensagem de retorno e suas menções ao diálogo nativo.

Faça uma verificação no manifest e veja suas respectivas atividades.

Para nossa sorte o manifest tem uma única activity, MainActivity como podemos verificar no print abaixo.

Analyzer com o arquivo AndroidManifest do app

Localizamos a activity sg.vantagepoint.uncrackable1.MainActivity

Com nossa atividade alvo em mãos, vamos inspecionar o arquivo dex para verificar o bytecode do mesmo.

No Bytecode Viewer

Para essa etapa utilizaremos o aplicativo bytecode viewer, vamos inspecionar e extrair o código fonte do dex file localizado acima.

Execute o comando abaixo para acessar o arquivo:

java -jar Bytecode-Viewer-X.X.X.jar

Uma GUI será exibida, com duas visualizações vazias, workspace e files. Algo como o print abaixo:

Acesse o menu files, em seguida, vá até o menu add e adicione o arquivo Uncrackable-level1.apk

Após o passo acima, novamente no menu file, vá em “decompile and save all classes”, conforme abaixo:

Salve o arquivo zip em um local de fácil acesso, encerre o bytecode Viewer e acesse novamente o Android Studio.

De volta ao Android Studio

No Android Studio, crie um novo projeto de teste, faça a extração dos arquivos gerados pelo bytecode Viewer e adicione no projeto teste.

Observe abaixo:

Agora que temos os arquivos do app importados, vamos localizar a classe MainActivity.

No trecho acima podemos identificar algumas informações importantes sobre o funcionamento do APP.

Na linha 16 é possível identificar uma função com identificador a que recebe um parâmetro string.

É possível verificar na linha 17 a criação de um Alert Builders com mensagens de validação

Após uma análise rápida do código acima verificamos que se trata de um método de validação com chamadas System.exit(), por esse motivo vamos remover esse trecho de código.

Após remover o código da função a() é possível identificar o onCreate da atividade.

Agora na linha 17 é possível identificar que o app realiza 3 verificações dentro da classe C com suas funções a, b, c. Pela mensagem retornada dentro da função a que removemos no passo anterior podemos inferir que se trata de 3 verificações anti root.

Vamos remover o trecho de código em questão.

Partindo para a linha 20 até a linha 22 podemos identificar nova verificação, dessa vez uma defesa contra repackaging, podemos identificar uma possível ativação da depuração pelo arquivo androidmanifest.

Vamos remover o trecho de código em questão.

Ao observar o restante do código verificamos que existe uma chamada ao super.onCreate e setContentView.

Após o trecho de código on create é possível identificar outra função nomeada com “verify”

Função Verify — MainActivity

Pela análise das strings das linhas 33 e 37 podemos criar a hipótese de que os fluxos de validação da secret estão dentro da classe a.

Observe as strings de feedback no app

Verificamos que a validação acontece na linha 31 na classe a com função de mesmo nome (a) que recebe a chave do Edittext exibido na tela.

Classe A — Função de Validação

Agora vamos explorar as classes A existentes no projeto, podemos identificar duas classes a, uma no pacote vantagepoint e outra no pacote uncrackable1.

No pacote vantagepoint vamos renomear a única função para vantagepointA e incorporá-la a classe a do pacote uncrackable1 para facilitar a análise.

Agora vamos remover a classe remanescente. Com isso podemos identificar um uso da classe no pacote uncrackable, conforme print abaixo:

Vamos substituir pelo novo método em vantagepointA. O resultado final será algo como:

Agora sim podemos analisar o método em questão, essa é a função que retorna a secret para validação, conforme vimos nas etapas anteriores, basicamente temos algumas operações de criptografia e codificação.

O primeiro processo na linha 11 é um tipo de codificação base64.

Saiba mais sobre o processo base64 aqui:

https://en.wikipedia.org/wiki/Encoder

https://developer.mozilla.org/en-US/docs/Glossary/Base64

Na linha 14 temos o processo de criação da chave que utiliza a função importada da outra classe a, vantagepointA

Na linha 22 vamos adicionar um Log.d para exibir a chave gerada pelo processamento através do Logcat.

Sem erros de compilação vamos mover a estrutura toda para o pacote de teste. Teremos algo como o apresentado abaixo:

Após este passo, podemos declarar uma chamada qualquer a classe a no OnCreate da MainActivity e ver a chave correspondente.

Chamada na MainActivity

Após a execução chegamos ao log com o segredo abaixo:

Validando no emulador temos um retorno de sucesso ao inserir “I want to believe”.

Dessa forma conseguimos recuperar o segredo ;]

--

--