Post

HTB • APKrypt

APKrypt is an easy mobile challenge created by bertolis on Hack The Box that involves reverse-engineering an android app to find a key along with an encrypted string which we use to recover the flag.

Can you get the ticket without the VIP code?

Static Analysis

For this challenge, we’ll perform some static analysis on APKrypt.apk with APKTool and JD-GUI.

APKTool

We decompress and decode the APK file with the following command:

1
apktool decode "APKrypt.apk"

Dex2jar

We’ll use the d2j-smali utility from dex2jar to compile each SMALI into a single DEX file.

1
2
cd ./APKrypt/smali/com/example/apkrypt
d2j-smali *

This should produce out.dex, which we can then convert to a JAR archive using d2j-dex2jar.

1
d2j-dex2jar "./out.dex"

JD-GUI

Now we have out-dex2jar.jar, which we can open in JD-GUI.

1
jd-gui "./out-dex2jar.jar"

JAR disassembly The disassembly of out-dex2jar.jar in jd-gui

Within the onCreate method there is a click listener on a button that when clicked, takes the content of a text input field and compares its MD5 hash to 735c3628699822c4c1c09219f317a8e9. If they match, the string k+RLD5J86JRYnluaZLF3Zs/yJrVdVfGo1CQy5k0+tCZDJZTozBWPn2lExQYDHH1l gets decrypted and displayed. If they don’t match, we get the message Wrong VIP code!.

We also find the AES key used by the decrypt method in generateKey.

1
2
3
private static Key generateKey() throws Exception {
  	return new SecretKeySpec("Dgu8Trf6Ge4Ki9Lb".getBytes(), "AES");
}

Decryption

Now that we have the key, we’ll decrypt the data in the onCreate method with a simple python script using PyCryptodome. We can assume that the AES mode is ECB because there is no nonce or IV present in the program as far as we know.

1
2
3
4
5
6
7
8
9
10
from base64 import b64decode
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

KEY = b'Dgu8Trf6Ge4Ki9Lb'
ENC = b64decode('k+RLD5J86JRYnluaZLF3Zs/yJrVdVfGo1CQy5k0+tCZDJZTozBWPn2lExQYDHH1l')

cipher = AES.new(KEY, AES.MODE_ECB)
result = unpad(cipher.decrypt(ENC), 16)
print(result.decode())

Running the script produces the flag.

This post is licensed under CC BY 4.0 by the author.