Use the tree to jump between collections without leaving the reader.

archive Select writeup Open tree
HackTheBox/Challenges/Challenge Apkey.en.md READ_ONLY

Challenge Apkey

This challenge consists of bypassing a login validation and the solution consists of decompiling the APK, locating the credentials logic, modifying the Smali code to bypass the MD5 hash check, and finally rebuilding and signing the application to capture the flag.

In this challenge, the initial task involves working with an Android APK file. Exploring the application structure using JADX-UI reveals the AndroidManifest.xml, which points the application label to a string resource rather than a hardcoded value.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
    <application
        android:theme="@style/Theme.APKey"
        android:label="@string/app_name"
...
</manifest>

Investigating the resources.arsc file reveals the true name of the application within the strings definitions.

<string name="app_name">APKey</string>

Attempting to install the raw APK in an Android emulator results in a specific error regarding resources.arsc compression. The Android package manager expects the package to be aligned on a 4-byte boundary. To solve this, the internal files must be restructured using the zipalign tool.

$ zipalign -v -p 4 APKey.apk APKey-aligned.apk
Verifying alignment of APKey-aligned.apk (4)...
      50 META-INF/MANIFEST.MF (OK - compressed)
  30003 META-INF/JOHN.SF (OK - compressed)
...
  1754976 res/drawable-hdpi-v4/notification_bg_normal.9.png (OK)
Verification successful

With the application properly aligned, a debug keystore is generated to sign the APK, allowing for installation on the emulator.

$ keytool -genkey -v -keystore debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000
Enter the distinguished name. Provide a single dot (.) to leave a ...
What is your first and last name?
  [Unknown]:  Android Debug
What is the name of your organizational unit?
  [Unknown]:  Android
What is the name of your organization?
  [Unknown]:  Google
What is the name of your City or Locality?
  [Unknown]:  Mountain View
What is the name of your State or Province?
  [Unknown]:  California
What is the two-letter country code for this unit?
  [Unknown]:  CO
Is CN=Android Debug, OU=Android, O=Google, L=Mountain View... correct?
  [no]:  yes

Generating 2048-bit RSA key pair and self-signed certificate...
  for: CN=Android Debug, OU=Android, O=Google, L=Mountain View...
[Storing debug.keystore]

The newly created debug key is then used to sign the aligned APK with apksigner.

$ apksigner sign --ks debug.keystore --ks-pass pass:android APKey-aligned.apk
WARNING: A restricted method in java.lang.System has been called
WARNING: java.lang.System::loadLibrary has been called by org.conscrypt...
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning ...
WARNING: Restricted methods will be blocked in a future release ...

The package is now ready to be deployed to the emulated device.

$ adb install APKey-aligned.apk
Performing Incremental Install
Serving...
All files should be loaded. Notifying the device.
Success
Install command complete in 71 ms

Opening the application displays a simple login form prompting the user to "Login to get a key". Since there are no provided credentials, analyzing the application's source code is the next logical step. Reopening the APK in the JADX GUI and examining the MainActivity code exposes a hardcoded username and an MD5 password hash.

...
java.lang.String r0 = "admin"
...
java.lang.String r1 = "a2a3d412e92d896134d9c9126d756f"
...

Further review of the decompiled code highlights heavily obfuscated functions. Upon successful authentication, the application calls methods to decrypt the key and present it through an Android Toast message.

java.lang.String r0 = c.b.a.g.a()
java.lang.String r0 = c.b.a.b.a(r0)
r1 = 1
android.widget.Toast r5 = android.widget.Toast.makeText(r5, r0, r1)

Attempts to crack the discovered hash a2a3d412e92d896134d9c9126d756f using common online databases prove unsuccessful. A closer inspection of the hash reveals it is only 30 characters long instead of the standard 32 characters for an MD5 digest. The underlying cause lies in how the byte array is converted to a string within the application: Integer.toHexString() omits leading zeros, corrupting the final hash representation and making it uncrackable.

r3 = r5[r2]
r3 = r3 & 255
java.lang.String r3 = java.lang.Integer.toHexString(r3)
r1.append(r3)

Given that the password cannot be recovered, an alternative approach is required. The binary must be disassembled, modified, and reassembled to completely bypass the authentication check. The apktool utility disassembles the APK into its Smali representation.

$ apktool d APKey.apk -o APKey_source
I: Using Apktool 3.0.2-dirty on APKey.apk with 8 threads
I: Loading resource table...
...
I: Copying unknown files...

The MainActivity$a.smali file contains the logic for the password validation. Modifying the condition from if-eqz (if equal to zero) to if-nez (if not equal to zero) effectively inverses the check, authenticating the user if an incorrect password is provided.

$ sed -i 's/if-eqz p1, :cond_0/if-nez p1, :cond_1/' APKey_source/smali/com/htb/apkey/MainActivity\$a.smali

The modification is quickly verified to ensure the Smali instruction was properly replaced.

$ grep 'if-nez' APKey_source/smali/com/htb/apkey/MainActivity\$a.smali
if-nez p1, :cond_1

With the logic inverted, the application must be rebuilt into an APK using apktool.

$ apktool b APKey_source -o APKey-hacked.apk
I: Using Apktool 3.0.2-dirty on APKey.apk with 8 threads
I: Smaling smali folder into classes.dex...
I: Building resources with aapt2...
I: Building apk file...
I: Importing unknown files...
I: Built apk into: APKey-hacked.apk

To prepare the modified application for installation, it goes through the alignment process once again.

$ zipalign -v -p 4 APKey-hacked.apk APKey-hacked-aligned.apk
Verifying alignment of APKey-hacked-aligned.apk (4)...
      49 AndroidManifest.xml (OK - compressed)
    884 resources.arsc (OK)
  ...
  1694100 META-INF/androidx.vectordrawable_vectordrawable-animated.versio...
Verification successful

The aligned APK is signed with the previously generated debug keystore.

$ apksigner sign --ks debug.keystore --ks-pass pass:android APKey-hacked-aligned.apk
WARNING: A restricted method in java.lang.System has been called
WARNING: java.lang.System::loadLibrary has been called by org.conscrypt...
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning ...
WARNING: Restricted methods will be blocked in a future release ...

The patched and signed application is deployed to the emulator, overwriting any previous installations.

$ adb install -r APKey-hacked-aligned.apk
Performing Incremental Install
Serving...
All files should be loaded. Notifying the device.
Success
Install command complete in 48 ms

Launching the application and entering the username admin with a deliberately incorrect password, such as a, triggers the inverted validation check. The application processes the successful authentication and presents the decrypted flag in a Toast message, completing the challenge.

HTB{FLAG}