Hackeando aplicativos e suas APIs em versões modernas do Android com Burp Suite e Zed Attack Proxy
Posted on October 23, 2024 • 16 min read • 3,381 wordsTutorial básico para os primeiros passos de execução de engenharia reversa de aplicativos em versões modernas do Android, utilizando o Google Android Studio.
A internet é um lugar sensacional para encontrar dicas e tutoriais sobre qualquer coisa, como hackear aplicativos, APIs, etc. Mas infelizmente, muito do material que aparece nas buscas… está defasado.
Quando você começa a explorar sobre hacking de APIs utilizados em aplicativos, logo encontra diversas dicas como fazer no Android, geralmente usando um emulador. Até aí, beleza.
Só que a coisa desanda rápido quando você percebe que existem zilhões de versões do Android e uma infinidade de dispositivos rodando cada uma delas. A maioria dos tutoriais só funciona em versões super antigas do Android, o que não bate com os apps modernos que precisamos testar e já não estão mais disponíveis em versões mais antigas do Android.
A intenção aqui é mostrar como contornar as barreiras de segurança das versões mais recentes, como o Android 14 e 15, e fazer tudo rodar no BurpSuite ou o ZAProxy direitinho.
Desde que o Android 7.0 (Nougat) chegou em 2016, ele parou de aceitar certificados de Autoridade de Certificação (CA) instalados pelo usuário. Isso foi feito para aumentar a segurança e impedir que CAs instaladas manualmente bagunçassem a proteção dos apps que usam conexões seguras.
O lado ruim? Isso complicou a instalação do certificado de CA raiz autoassinado do Burp Suite e do ZAProxy, que é o que permite interceptar e fazer proxy do tráfego dos aplicativos.
É por isso que tantos vídeos e artigos mostram seus criadores usando celulares Android mais antigos. Costumam dizer que é porque “essas versões são mais estáveis”, mas talvez seja a dificuldade em injetar o certificado direto no armazenamento de sistema, em /system/etc/security/cacerts
.
E aí, tudo mudou…pra pior.
A partir do Android 10, o Google deu mais uma complicada na brincadeira. Eles introduziram uma separação ainda mais rígida no armazenamento de certificados. Usando o novo formato de contêiner Android Pony EXpress (APEX), eles basicamente jogaram a confiança dos certificados lá dentro, o que significa que não dá mais pra injetar direto no sistema de arquivos. Adeus, métodos fáceis de inserir certificado no armazenamento do sistema.
Pra facilitar sua vida, o que vem abaixo é uma série de passos que contornar o problema.
Para poder testar APIs de aplicativos em versões modernas do Android, será necessário instalar um punhado de coisas. Todo o laboratório criado nos passos abaixo foi feito em plataforma MacOS em processador M1.
Em muitos materiais, irão recomendar usar o Genymotion porque ele é super fácil de usar, mas acho melhor evitar. O emulador é bom, sim, mas se você quiser rodar versões modernas do Android (como bug bounty ou testes de segurança), vai ter que pagar a licença comercial — e essa brincadeira custa mais de US$ 400 por ano.
Mas calma, você não precisa gastar essa grana. O Google já oferece o Android Studio de graça para desenvolvedores, e ele serve muito bem pra isso. Na real, você vai acabar instalando o Android Studio pra pegar as ferramentas de linha de comando e os emuladores, mas não precisa nem abrir ou criar projetos no programa. O que você quer mesmo é o Virtual Device Manager, que vamos falar daqui a pouco.
Já com o Android Studio instalado, execute-o. Na tela inicial dará ênfase para a criação de um projeto, isso não é necessário.
Clique em “More Actions” e selecione “Virtual Device Manager”.
Agora você pode gerenciar os emuladores que você gostaria de provisionar. Geralmente já vem um emulador já pré configurado, mas vamos criar um novo.
Neste laboratório estou utilizando o “Pixel 8”. Ele já vem com o Google Play pré-instalado e uma versão mais moderna do Android, versão 15 (até o momento desta publicação).
Pressione “Next” e selecione a imagem de sistema. Por padrão vserá API 35 (Android 15), e selecionará o chipset do seu dispositivo. Nas imagens abaixo verá chipset arm64-v8a
, que nada mais é do que meu MacBook Pro M1, que utiliza Apple Silicon.
Pressione “Next” novamente e nomeie o seu Android Virtual Device (AVD).
Agora só precisamos ajustar as configurações do emulador para que sempre inicie em cold boot, sempre limpando a memória RAM a cada restart.
Vá em “Show Advanced Settings”, vá até a seção “Emulated Performance” e habilite a opção “Cold Boot” em “Boot Option”.
Agora clique em “Finish” e você terá sua imagem pronta para uso.
Opcionalmente, você pode fechar todas as janelas do Android Studio. Daqui para frente tudo será feito por linha de comando.
Por padrão, durante a instalação do Android Studio, ele instalará o Android SDK, que inclui suas ferramentas de plataforma e os emuladores. No entanto, essas ferramentas não são diretamente expostas a você até que você configure seus caminhos de binários corretamente.
Como isso será diferente entre Windows, Linux e Mac, não fornecerei instruções detalhadas. Apenas certifique-se de adicionar os diretórios Android/sdk/platform-tools e Android/sdk/emulator ao seu caminho.
Como exemplo, você pode adicionar a seguinte linha ao seu arquivo .zshrc
(no meu caso, Mac) ou executar diretamente no seu terminal apenas quando for utilizar o emulator.
export PATH="$PATH:/Users/$USER/Library/Android/sdk/platform-tools:/Users/$USER/Library/Android/sdk/emulator"
Caso tenha escolhido escrever no arquivo .zshrc
, não esqueça de recarregar o perfil com o comando source ˜/.zshrc
.
adb --help
e emulator --help
sem erros.
Com o emulador do Android instalado, podemos iniciá-lo. Primeiro, com o comando emulator
vamos verificar se nosso dispositivo aparece na lista.
emulator -list-avds
Você poderá observar o dispositivo criado.
Agora podemos iniciar nosso device passando o nome listado após o último comando.
emulator -avd "Pixel_8"
A partir deste momento, com o dispositivo já em execução, podemos utilizar o Android Debug Bridge (ADB) para obter acesso ao sistema operacional do dispositivo. Abra uma nova console e digite:
adb shell
Há diversos tutoriais na internet que te guiará para digitar su
e obter acesso de root e obter acesso total ao sistema operacional, mas você não pode fazer isso em versões modernas do Android. Essa permissão será negada.
Mas precisaremos do root para realizar nossas atividades de análise de aplicativos. Vamos trabalhar mais um pouco.
Como o Android não vem com acesso root de fábrica, a gente vai precisar dar uma “mexida” no dispositivo. Esse processo é conhecido como “rootear”, e antigamente envolvia umas gambiarras bem complicadas pra fazer.
Mas, hoje em dia, tá bem mais tranquilo, graças ao Magisk e a um script maneiro chamado rootAVD.
O Magisk é tipo a “máscara mágica” que cria um ambiente com acesso root no Android, além de oferecer módulos que permitem reconfigurar e modificar o sistema do jeito que você quiser. Já o rootAVD aproveita o Magisk pra fazer root num AVD (Android Virtual Device) baseado em QEMU em execução e te dar o acesso que você precisa.
Você pode baixar ou clonar o rootAVD direto do GitLab usando o Git:
git clone https://gitlab.com/newbit/rootAVD.git
Uma vez baixado, entre no diretório rootAVD
e você encontrará dois arquivos importantes, o rootAVD.sh
(Linux e Mac) e rootAVD.bat
(Windows). Execute de acordo com o sistema operacional do seu host. Novamente, no meu caso, está sendo executado em MacOS.
cd rootAVD
./rootAVD.sh
Por padrão, o script irá exibir exemplos de comandos específicos para o seu sistema (processador, versão de emulador, etc).
No meu caso, copiei o primeiro exemplo e reexecutei o script passando o exemplo como argumento.
./rootAVD.sh system-images/android-35/google_apis_playstore/arm64-v8a/ramdisk.img
E será exibido uma saída igual abaixo, onde o processo de root foi executado com sucesso.
[!] and we are NOT in an emulator shell
[*] Set Directorys
[-] source.properties file exist
[*] AVD system-image Pkg.Revision=8
[-] Test if ADB SHELL is working
[*] ADB connection possible
[-] In any AVD via ADB, you can execute code without root in /data/data/com.android.shell
[*] Cleaning up the ADB working space
[*] Creating the ADB working space
[-] Magisk installer Zip exists already
[*] Push Magisk.zip into /data/data/com.android.shell/Magisk
[-] ./Magisk.zip: 1 file pushed, 0 skipped. 191.9 MB/s (12526383 bytes in 0.062s)
[*] create Backup File of ramdisk.img
[*] Push ramdisk.img into /data/data/com.android.shell/Magisk/ramdisk.img
[-] /Users/tiago/Library/Android/sdk/system-images/android-35/google_apis_playstore/arm64-v8a/ramdisk.img: 1 file pushed, 0 skipped. 508.7 MB/s (1802082 bytes in 0.003s)
[*] Push rootAVD.sh into /data/data/com.android.shell/Magisk
[-] rootAVD.sh: 1 file pushed, 0 skipped. 172.8 MB/s (83326 bytes in 0.000s)
[-] run the actually Boot/Ramdisk/Kernel Image Patch Script
[*] from Magisk by topjohnwu and modded by NewBit XDA
[!] We are in a ranchu emulator shell
[-] Api Level Arch Detect
[-] Device Platform is arm64 only
[-] Device SDK API: 35
[-] First API Level: 35
[-] The AVD runs on Android 15
[-] Switch to the location of the script file
[*] Looking for an unzip binary
[-] unzip binary found
[*] Extracting busybox and Magisk.zip via unzip ...
[*] Finding a working Busybox Version
[*] Testing Busybox /data/data/com.android.shell/Magisk/lib/arm64-v8a/libbusybox.so
[!] Found a working Busybox Version
[!] BusyBox v1.36.1-Magisk (2023-09-02 05:30:11 PDT) multi-call binary.
[*] Move busybox from lib to workdir
[-] Checking AVDs Internet connection...
[!] AVD is online
[!] Checking available Magisk Versions
[?] Choose a Magisk Version to install and make it local
[s] (s)how all available Magisk Versions
[1] local stable '26.4' (ENTER)
[2] stable 27.0
[3] canary 070719db(28001)
[-] You choose Magisk local stable Version '26.4'
[*] Re-Run rootAVD in Magisk Busybox STANDALONE (D)ASH
[-] We are now in Magisk Busybox STANDALONE (D)ASH
[*] rootAVD with Magisk '26.4' Installer
[-] Get Flags
[*] System-as-root, keep dm/avb-verity
[-] Encrypted data, keep forceencrypt
[*] RECOVERYMODE=false
[-] KEEPVERITY=true
[*] KEEPFORCEENCRYPT=true
[-] copy all arm64-v8a files from /data/data/com.android.shell/Magisk/lib/arm64-v8a to /data/data/com.android.shell/Magisk
[-] copy 'stub.apk' from /data/data/com.android.shell/Magisk/assets to /data/data/com.android.shell/Magisk
[*] Detecting ramdisk.img compression
[!] Ramdisk.img uses lz4_legacy compression
[-] taken from shakalaca's MagiskOnEmulator/process.sh
[*] executing ramdisk splitting / extraction / repacking
[-] API level greater then 30
[*] Check if we need to repack ramdisk before patching ..
[-] Multiple cpio archives detected
[*] Unpacking ramdisk ..
[*] Searching for the real End of the 1st Archive
[-] Dumping from 0 to 1706139 ..
Detected format: [lz4_legacy]
[-] Dumping from 1706139 to 1802063 ..
Detected format: [lz4_legacy]
[*] Repacking ramdisk ..
[!] allowing MANAGE_EXTERNAL_STORAGE permissions to...
[-] Checking ramdisk STATUS=0
[-] Stock boot image detected
[*] Verifying Boot Image by its Kernel Release number:
[-] This AVD = 6.6.30-android15-7-gbb616d66d8a9-ab11968886-4k
[-] Ramdisk = 6.6.30-android15-7-gbb616d66d8a9-ab11968886-4k
[!] Ramdisk is probably from this AVD
[-] Patching ramdisk
[*] Pre-init storage partition: vdd1
[!] stub.apk is present, compress and add it to ramdisk
[*] adding overlay.d/sbin folders to ramdisk
Loading cpio: [ramdisk.cpio]
Create directory [overlay.d] (0750)
Create directory [overlay.d/sbin] (0750)
Dumping cpio: [ramdisk.cpio]
[!] patching the ramdisk with Magisk Init
Loading cpio: [ramdisk.cpio]
Add file [init] (100750)
Add file [overlay.d/sbin/magisk64.xz] (100644)
Add file [overlay.d/sbin/stub.xz] (100644)
Patch with flag KEEPVERITY=[true] KEEPFORCEENCRYPT=[true]
Loading cpio: [ramdisk.cpio.orig]
Backup [init] -> [.backup/init]
Record new entry: [overlay.d] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/magisk64.xz] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/stub.xz] -> [.backup/.rmlist]
Create directory [.backup] (0000)
Add file [.backup/.magisk] (100000)
Dumping cpio: [ramdisk.cpio]
[*] repacking back to ramdisk.img format
[!] Rename Magisk.zip to Magisk.apk
[*] Pull ramdiskpatched4AVD.img into ramdisk.img
[-] /data/data/com.android.shell/Magisk/ramdiskpatched4AVD.img: 1 file pulled, 0 skipped. 144.7 MB/s (2304277 bytes in 0.015s)
[*] Pull Magisk.apk into
[-] /data/data/com.android.shell/Magisk/Magisk.apk: 1 file pulled, 0 skipped. 192.8 MB/s (12526383 bytes in 0.062s)
[-] Clean up the ADB working space
[-] Install all APKs placed in the Apps folder
[*] Trying to install Apps/Magisk.apk
[*] Performing Streamed Install
[*] Success
[-] Shut-Down & Reboot (Cold Boot Now) the AVD and see if it worked
[-] Root and Su with Magisk for Android Studio AVDs
[-] Trying to shut down the AVD
[!] If the AVD doesn't shut down, try it manually!
[-] Modded by NewBit XDA - Jan. 2021
[!] Huge Credits and big Thanks to topjohnwu, shakalaca, vvb2060 and HuskyDG
Reinicie o emulador, acesso novamente o SO com o adb e digite novamente o su
. Na tela do emulador aparecerá uma janela solicitado autorização para garantir acesso total como root, basta clicar em GRANT.
Uma vez habilitado, basta digitar novamente no terminal no shell do Android o comando su
, e você terá acesso root ao dispositivo.
Agora sim, com acesso total, você poderá relizar todas as tarefas de análise de aplicativos e seguir qualquer tutorial na Internet. Abaixo iremos explorar apenas como configurar os proxies BurpSuite e Zed Attack Proxy (ZAProxy) para interceptar requisições de aplicativos.
Agora, precisamos fazer o Android confiar no certificado CA do Burp e do ZAProxy. Mas não podemos gravar no contêiner apex.
O que fazemos?
É aqui que o Magisk é útil. Como podemos carregar módulos personalizados na estrutura, podemos aproveitar um módulo especial que o pessoal da NCC Group construiu chamado ConscryptTrustUserCerts. Este módulo é executado como um serviço para copiar certificados de usuário confiável e colocá-los em todos os lugares que o Android precisa deles para confiança em nível de sistema… incluindo o contêiner seguro APEX.
Baixe o arquivo zip do módulo ConscryptTrustUserCerts
na guia Releases no Github:
curl -s -L https://github.com/nccgroup/ConscryptTrustUserCerts/releases/download/v0.1/ConscryptTrustUserCerts.zip -o ConscryptTrustUserCerts.zip
Envie via ADB o módulo para o diretório de Downloads do nosso dispositivo virtual.
adb push ConscryptTrustUserCerts.zip /sdcard/Download
O próximo passo será o que fará com que o certificado CA do Burp e ZAProxy instalados no armazenamento Trusted User, seja movidos para o armazenamento System. É aqui que o módulo Magisk do NCC Group entrará em ação. Para acessar a estrutura Magisk, precisamos simplesmente clicar em seu ícone disponível entre os aplicativos.
A partir de agora, todo novo certificado que instalarmos em contexto de “User”, após o reboot do dispositivo eles serão copiados para o contexto “System”.
O Burp Suite é uma ferramenta de teste de segurança web desenvolvida pela PortSwigger. Ela oferece uma série de funcionalidades, como interceptação de tráfego HTTP/S, análise de vulnerabilidades e automação de testes. Ela possui versões Community (Free), Professional e Enterprise.
Com o Burp Suite instalado, execute-o e já deixe o proxy configurado para receber requisições por todas as interfaces. Por padrão o BurpSuite já vem com a porta 8080
para receber as requisições.
Baixe o certificado do BurpSuite para adicionamos ao dispositivo e viabilizar a interceptação de tráfego TLS.
curl -s -L http://localhost:8080/cert -o burp_cert.der
Agora, para fins de demonstração, copie a série de comandos abaixo, cole e execute no terminal do seu host:
DER
para o formato PEM
;PEM
(9a5ba575) e grava na variável hash
;{hash}.0
, que ficará 9a5ba575.0
;openssl x509 -inform der -in burp_cert.der -out burp_cert.pem ;\
hash=$(openssl x509 -inform PEM -subject_hash_old -in burp_cert.pem |head -1) ; \
cp burp_cert.pem ${hash}.0 ; \
ls -lh ${hash}.0
Agora vem o problema, quando tentamos gravar o certificado diretamente dentro do diretório /system/etc/security/cacerts/
do Android, somos bloqueados!
adb root; \
adb remount ; \
adb push ${hash}.0 /system/etc/security/cacerts/
Agora que o ConscryptTrustUserCerts entrará em ação.
A partir do comando abaixo, copie o arquivo burp_cert.pem
gerado acima para o diretório /sdcard/Download
.
adb push burp_cert.pem /sdcard/Download
Agora, instale o certificado no contexto de usuários, em Settings-> Security & privacy -> More security & privacy -> Encryption & credentials -> Install a certificate -> CA Certificate, selecione a pasta de Downloads e selecione o certificado e instale.
Reinicie o Android, volte para Configurações e encontre a seção Trusted Credentials. Agora você pode ver o certificado Burp CA do Portswigger nos armazenamentos do Usuário e do Sistema.
Capturando tráfego de um app de academia ae…
ZAP (Zed Attack Proxy) evoluiu muito desde seus primeiros dias na OWASP. Agora, sob uma nova parceria com a Checkmarx, o ZAP poderá ficar ainda mais poderoso. Acredito que essa união trará melhorias no motor de análise de segurança, pois já está fazendo parte da plataforma Checkmarx One.
Continuando, abra o ZAProxy e vá em Settings -> Network -> Local Servers/Proxies e configure o Main Proxy com endereço 0.0.0.0
, que habilitará o proxy a receber requisicões de todas as interfaces, e a porta 8081
, para não gerar conflito com o Burp Suite.
Acesso o endereço http://localhost/8081
e baixe o certificado do ZAProxy.
Se observar o arquivo baixado, verá que ele já está no formato PEM
. Assim não precisamos realizar conversões.
Envie o certificado para o diretório Downloads do Android.
adb push ZAPCACert.cer /sdcard/Download
Agora, instale o certificado em Settings-> Security & privacy -> More security & privacy -> Encryption & credentials -> Install a certificate -> CA Certificate, selecione a pasta de Downloads e selecione o certificado do ZAProxy e instale.
Ao fim das configurações, verá que os certificados do Burp Suite e do ZAProxy estarão disponíveis no contexto de usuário, agora basta reiniciar o Android para que os certificados sejam enviados para o contexto de sistema pelo ConscryptTrustUserCerts.
Abaixo um resuminho dos passos mencionados acima, interceptando um aplicativo de uma empresa de ônibus rodoviários.
Tenho certeza de que esse artigo vai ficar ultrapassado em alguns anos, quando o Google adicionar mais barreiras de segurança para dificultar que os proxies interceptem o tráfego de apps móveis no Android. Mas, por enquanto, tudo funciona perfeitamente até o Android 15.
Espero que este material ajude se você está quebrando a cabeça para fazer a intercepção com proxies funcionar com versões mais recentes do Android e emuladores como o Pixel 8.
A partir daqui, a diferença entre hackear um app web que se conecta a uma API e hackear um app móvel que faz o mesmo é mínima. A única diferença que você pode encontrar está nos dados do payload ou até em endpoints completamente diferentes entre as versões.
E essa é a parte divertida! Dá uma olhada aí. Pode ser que você se surpreenda.
👾