MASTG walkthrough - OWASP MSTG UnCrackable Level 1

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

There are several ways to complete this challenge but for the sake of simplicity I’m going to show how to do it by only patching the smali code of the application.

Let’s install the application via adb and run it.

adb install UnCrackable-Level1.apk

uncrackable1

It seems like there’s some kind of root detection in place.

Bypassing root detection Let’s take a look at the source code in jadx-gui.

uncrackable2

The code is obfuscated but we can see that during the initialization of the MainActivity function c.a(), c.b() and c.c() are called. Let’s take a closer look.

uncrackable3

Functions of Class C are responsible for checking if the application is running in a rooted environment or not.

uncrackable4

Function c.a() checks for the existence of “su“ binaries on the device and returns a boolean.

uncrackable5

"Check for 'su' binary: Su binary check is to identify the superuser in the device. This binary is installed when you try to root your phone using apps like kinguser or via fastboot in Android. These files are necessary so that one can root their phone and become the superuser. The existence of this binary can be checked from the following paths." source

Function c.b() checks for the existence of “test-keys” on the device and returns a boolean.

uncrackable6

"Check for Test-Keys: Test-Keys has to do with how the kernel is signed when it is compiled. By default, stock Android ROMs from Google are built with release-keys tags. Test-Keys means it is signed with a custom key generated by a third-party developer. Specifically, it will check in build properties('android.os.Build.TAGS') for test-keys." source

Function c.c() checks for various file paths which indicate if a device is rooted or not and returns a boolean.

uncrackable7

/system/app/Superuser.apk, /system/xbin/daemonsu, /system/etc/init.d/99SuperSUDaemon, /system/bin/.ext/.su, /system/etc/.has_su_daemon, /system/etc/.installed_su_daemon, /dev/com.koushikdutta.superuser.daemon/

If any of these 3 functions return true a popup message would appear saying “This is unacceptable. The App is now going to exit.”. When we click OK the function a() would terminate the activity by calling System.exit(0).

uncrackable8

The simplest solution is:

  1. Unpack the apk
  2. Remove the line responsible for the termination
  3. Repackage the apk with apktool.

Unpacking the .apk file

apktool d UnCrackable-Level1.apk

Remove the corresponding line of smali code

  1. Open /UnCrackable-Level1/smali/sg/vantagepoint/uncrackable1/'MainActivity$1.smali' in any text editor
  2. Remove line 41 and save it

uncrackable9

uncrackable10

Repackage the apk

apktool b UnCrackable-Level1 -o UnCrackable-Level1.modified.apk

uncrackable11

uncrackable12

Sign it before installing, in this case I’m going to use objection’s keystore.

objection patchapk --source UnCrackable-Level1.modified.apk
adb uninstall owasp.mstg.uncrackable1
adb install UnCrackable-Level1.modified.objection.apk

Root detection is successfully bypassed.

uncrackable13

Finding the secret

In a nutshell: In the main activity there’s a textbox which takes some input and after clicking “Verify” it compares the entered value to the secret value. If we didn’t supply the correct value we’ll get an error message.

uncrackable14

Take a look at the source code

uncrackable15

I wonder what function a.a() is about?

uncrackable16

uncrackable17

The hex encoded value (8d127684cbc37c17616d806cf50473cc) is converted to bytes (b()) and passed to sg.vantagepoint.a.a.a along with a base64 encoded value (5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=). The str argument (the user’s input) is compared with the string in bArr variable using str.equals. It returns true if there’s a match and false if there isn’t.

Take a look at a.a.a()

uncrackable18

This method has 2 arguments, bArr and bArr2. bArr is used as the key in new SecretKeySpec with AES/ECB/PKCS7Padding cipher mode. After the cipher gets created with the encryption key a byte array is returned using the cipher to decrypt bArr2 (return instance.doFInal(bArr2)).

Let’s hook onto method a.a.a() with objection and capture the return value.

objection -g owasp.mstg.uncrackable1 explore
android hooking watch class_method sg.vantagepoint.a.a.a --dump-args --dump-return

Enter some test string and monitor the results

uncrackable19

uncrackable20

a.a.a()’s return value is: 73,32,119,97,110,116,32,116,111,32,98,101,108,105,101,118,101

Let’s convert this byte array into a string with Java

uncrackable21

javac ByteArraytoString.java && java ByteArraytoString

uncrackable22

uncrackable23

Tools used

Thoughts? Leave a comment