InsecureShop é um aplicativo Android projetado para ser intencionalmente vulnerável. O aplicativo serve como uma plataforma para testar suas habilidades de pentesting no Android.

O aplicativo do projeto pode ser encontrado no repositório do GitHub nesse endereço: https://github.com/hax0rgb/InsecureShop

Nessa postagem eu vou mostrar como resolvi os desafios presentes no app.

M7: Insufficient Binary Protection

Para iniciar o teste, foi realizado a engenharia reversa do aplicativo utilizando a ferramenta conhecida como “enjarify”.

Também foi utilizado a ferramenta “apktool” para extrair todos os arquivos presentes no apk.

Credential HardCoded

Analisando o código fonte do app, foi possível encontrar as credenciais utilizadas para acesso ao aplicativo.

Com as credenciais encontradas, foi possível acessar o app.

MASTG-TEST-0003 - Testing Logs for Sensitive Data

Analisando o código fonte da aplicação, foi possível identificar que o app realiza o log das informações passadas para login e senha no aplicativo.

Analisando os logs gerados pelo app, foi possível confirmar essa informação.

shopuser:!ns3csh0p

M9: Insecure Data Storage

Analisando o conteúdo da pasta “shared_prefs” do app, foi possível encontrar o arquivo “Prefs.xml” contendo o usuário e senha salvos em texto claro.

M8: Security Misconfiguration

Bypass Trust Manager

Com acesso ao aplicativo, foi realizado a tentativa de acesso aos produtos listados pelo app, porém as informações não foram carregadas.

Foi possível realizar o bypass da proteção utilizando o seguinte script frida público:

Java.perform(function() {

    // TrustManager (Android < 7) //
    ////////////////////////////////
    var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
    var SSLContext = Java.use('javax.net.ssl.SSLContext');
    var TrustManager = Java.registerClass({
        // Implement a custom TrustManager
        name: 'dev.asd.test.TrustManager',
        implements: [X509TrustManager],
        methods: {
            checkClientTrusted: function(chain, authType) {},
            checkServerTrusted: function(chain, authType) {},
            getAcceptedIssuers: function() {return []; }
        }
    });

    // Prepare the TrustManager array to pass to SSLContext.init()
    var TrustManagers = [TrustManager.$new()];
    // Get a handle on the init() on the SSLContext class
    var SSLContext_init = SSLContext.init.overload(
        '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
    try {
        // Override the init method, specifying the custom TrustManager
        SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {
            console.log('[+] Bypassing Trustmanager (Android < 7) pinner');
            SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
        };
    } catch (err) {
        console.log('[-] TrustManager (Android < 7) pinner not found');
        //console.log(err);
    }

    // TrustManagerImpl (Android > 7) //
    ////////////////////////////////////
    try {
        // Bypass TrustManagerImpl (Android > 7) {1}
        var array_list = Java.use("java.util.ArrayList");
        var TrustManagerImpl_Activity_1 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
        TrustManagerImpl_Activity_1.checkTrustedRecursive.implementation = function(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, trustAnchorChain, used) {
            console.log('[+] Bypassing TrustManagerImpl (Android > 7) checkTrustedRecursive check for: '+ host);
            return array_list.$new();
        };
    } catch (err) {
        console.log('[-] TrustManagerImpl (Android > 7) checkTrustedRecursive check not found');
        //console.log(err);
        errDict[err] = ['com.android.org.conscrypt.TrustManagerImpl', 'checkTrustedRecursive'];
    }  
    try {
        // Bypass TrustManagerImpl (Android > 7) {2} (probably no more necessary)
        var TrustManagerImpl_Activity_2 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
        TrustManagerImpl_Activity_2.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
            console.log('[+] Bypassing TrustManagerImpl (Android > 7) verifyChain check for: ' + host);
            return untrustedChain;
        };  
    } catch (err) {
        console.log('[-] TrustManagerImpl (Android > 7) verifyChain check not found');
        //console.log(err);
        errDict[err] = ['com.android.org.conscrypt.TrustManagerImpl', 'verifyChain'];  
    }
});

Dessa forma, foi possível realizar o bypass nessa proteção.

Também foi possível interceptar as requisições realizadas pelo aplicativo.

E assim, acessar o conteúdo dos produtos presentes no app.

Analisando as requisições geradas pelo aplicativo, foi possível notar que a comunicação realizada pelo app e o servidor não possuem criptografia.

Insufficient URL Validation

Analisando o conteúdo do arquivo “AndroidManifest.xml” foi possível identificar a classe responsável pelo webview.

Realizando a análise do código fonte dessa classe, é possível identificar que o app realiza uma verificação, porém acaba carregando a url passada como argumento.

Dessa forma, é possível carregar conteúdo de outros sites dentro do app.

AWS Cognito Misconfigurations

Analisando o arquivo “strings.xml” presente nos arquivos do apk, é possível encontrar o ID do Identity Pool da AWS.

Com a informação encontrada, é possível realizar uma consulta e descobrir o Identity ID da acesso a AWS.

Com o identity id, é possível descobrir mais informações