Uncrackable Level 1

OWASP Uncrackable Level 1

1. Introduction

This app holds a secret inside. Can you find it?

Objective: A secret string is hidden somewhere in this app. Find a way to extract it.
Author: Bernhard Mueller

2. Analysis and Source Code

Emulator Setup: Nexus 5 with Android 9.0

adb install Uncrackable-Level1.apk

After starting the app there’s a message:
Root detected!
This is unacceptable. The app is now going to exit.

Note: We need to find a way to bypass the root detection. If this is done we need a way to find the secret string!

I’ll unpack the android package

apktool d -f -r Uncrackable-Level1.apk

I’ll also unpack the classes.dex from from the Uncrackable-Level1.apk file

unzip -j Unrackable-Level1.apk classes.dex

Next I’ll use strings against the classes.dex file

There are several things here that catch my attention:

5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=

looks like base64 string

8d127684cbc37c17616d806cf50473cc

 looks like a HEX string

AES/ECB/PKCS7Padding

 gives me a hint about the encryption algorithm being used

For the further analysis of the source code I’ll open the android package with jadx-gui

Let’s check the AndroidManifest.xml first:
Package name is:
owasp.mstg.uncrackable1

Entrypoint is:

The MainActivity contains the onCreate method, and immediately performs on evaluation to check for root:

public void onCreate(Bundle bundle) {
       if (c.a() || c.b() || c.c()) {
           a("Root detected!");
       }

2.1 Root detection

If either c.a(), c.b(), or c.c() returns true, then the string “Root detected” is passed to the a() method, which looks like this:

private void a(String str) {
       AlertDialog create = new AlertDialog.Builder(this).create();
       create.setTitle(str);
       create.setMessage("This is unacceptable. The app is now going to exit.");
       create.setButton(-3, "OK", new DialogInterface.OnClickListener() { // from class: sg.vantagepoint.uncrackable1.MainActivity.1
           @Override // android.content.DialogInterface.OnClickListener
           public void onClick(DialogInterface dialogInterface, int i) {
               System.exit(0);
           }

We can try to patch the condition or hook it with frida.

2.2 Secret Key

The secret key is calculated somewhere around here:

public class a {
    public static boolean a(String str) {
        byte[] bArr;
        byte[] bArr2 = new byte[0];
        try {
            bArr = sg.vantagepoint.a.a.a(b("8d127684cbc37c17616d806cf50473cc"), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));
        } catch (Exception e) {
            Log.d("CodeCheck", "AES error:" + e.getMessage());
            bArr = bArr2;
        }
        return str.equals(new String(bArr));
    }
public class a {
    public static byte[] a(byte[] bArr, byte[] bArr2) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");
        Cipher instance = Cipher.getInstance("AES");
        instance.init(2, secretKeySpec);
        return instance.doFinal(bArr2);
    }
}

4. Decrypt Secret

I’ll use an online AES tool that help me with decryption:
https://the-x.cn/en-us/cryptography/Aes.aspx

Input is the BASE64 string

Options:

ECB
PKCS7
128bits
HEX KEY: 8d127684cbc37c17616d806cf50473cc

Output:

Alternative solution with python:

5. Hooking the root protection with Frida

Let’s try to hook the root protection with frida
This code will overload the exit function and print a string out „Exit called instead of closing the application“

hook.js

setImmediate(function() {
    console.log("[+] Starting hooker");

    Java.perform(function () {
        var system = Java.use("java.lang.System");
        system.exit.overload("int").implementation = function(var0) {
            console.log("[+] Exit called");
        };
    });
});

Let’s check the frida connection:

frida-ps -U

frida -U -f owasp.mstg.uncrackable1 -l hook1.js –no-pause

Let’s check the Secret from the decryption above:

I want to believe