OWASP MSTG Crackme 1 writeup (Android)

by Davide Cioccia

Intro

The Uncrackable Apps are a collection of mobile reverse engineering challenges made available by the creator of the OWASP Mobile Security Testing Guide to practice reverse engineering skills. Our mobile security researchers had some fun cracking the apps during one of our R&D Friday afternoons.

You can find more info regarding the challenges here: CrackMe

Setup

The following setup will be used to solve the challenges

  • Genymotion (x86 device)

  • Android API 29 - 10.0

  • Objection

  • Frida

  • Ghidra

  • adb

Run the application

To install the application

adb install UnCrackable-Level1.apk

We should see the application in the list of apps

When we run it, we notice that the app detects rooted devices at startup. We will see how this is implemented in the next phase.

The application

Any mobile security assessment has very standard initial steps, and one of them is certainly the reverse engineering of the application and the extraction of the source code. Extracting the source code of a native Android application can be achieved in different ways, but to speed up our process we can rely on MobSF which automates the usage of tools like apktool and dex2jargiving us different formats that we can download for further analysis.

In case something fails, proceed manually using the tools mentioned above.

Once extracted the source code will be structured as the following:

.
├── owasp
   └── mstg
       └── uncrackable1
           └── R.java
└── sg
    └── vantagepoint
        ├── a
           ├── a.java
           ├── b.java
           └── c.java
        └── uncrackable1
            ├── MainActivity.java
            └── a.java

7 directories, 6 files

where the main code is located in the packages sg.vantagepoint.a and sg.vantagepoint.uncrackable1

Let's have a look

The class sg.vantagepoint.a.c contains the logic to identify rooted devices. The class implements 3 different techniques that are reflected in the functions a(), b() and c()

  • a(): check whether the binary su is available in the PATH

  • b(): Fabric Crashlitics method

  • c(): checks for well-known binaries to root Android devices

Now, we could bypass this root detection in a very easy way, just patching the functions to return always True, but the root detection does not influence our exploitation, because the app does not crash automatically, but only after the user click OK. So we ignore it for this challenge.

Now let's find our flag

If we look at the class sg.vantagepoint.uncrackable1.a, we find the function that verifies whether the secret provided by the user is the same as the one stored in the code.

Because the secret and the key are both stored in the code we can crack this app, by simply extracting the real key (using the function sg.vantagepoint.uncrackable1.a.b() and passing the two values to the decryption function located in sg.vantagepoint.a.a.a(key, secret), that will return a byte array, that we will need to convert to a String

Frida

Frida is a "dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers", that can be used to perform runtime analysis of applications, especially mobile.

The best way to start with it is via their website https://frida.re/.

In this writeup, we are not going into details on how to instrument the application, or run the Frida server on the device, but will limit the scope on the Frida API and how to use them to solve the Uncrackable challenge. What we want to do is:

  1. Extract the real key from the string 8d127684cbc37c17616d806cf50473cc

  2. Base64 decode the encrypted secret 5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=

  3. Pass the two values above to the decryption function sg.vantagepoint.a.a.a(key,secret) and print out the secret as String

Here is the script and the solution

setImmediate(function() {
    console.log("[*] Start");
    

    Java.perform(function() {
       
        console.log("[*] Loading Base64 class")
        var b64Def = Java.use('android.util.Base64');
       
        console.log("[*] Loading sg.vantagepoint.uncrackable1.a")
        var clazz_b = Java.use('sg.vantagepoint.uncrackable1.a');
        
        console.log("[*] Loading sg.vantagepoint.a.a")
        var clazz = Java.use('sg.vantagepoint.a.a');
        
        console.log("[*] Extracting the key ")
        var key = clazz_b.b("8d127684cbc37c17616d806cf50473cc")
        console.log("[*] Base64 decoding the secret ")
        var secret = b64Def.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0)
        console.log("[*] Decrypting the secret with the extracted key") 
        var buffer = clazz.a(key,secret)
        
        var result = ""
        for(var i = 0; i < buffer.length; ++i){
                result+= (String.fromCharCode(buffer[i]));
        }
        console.log()
        console.log("****** SECRET ******")
        console.log(result)
        console.log("****** SECRET ******")
        console.log()

    })
    
    console.log("[*] End");

})

that we can run using the command

frida -U -l hook.js owasp.mstg.uncrackable1

and voilà, we have the secret printed in the console

The full script can be downloaded from our GitHub repo

Last updated