Usa el árbol para saltar entre colecciones sin salir del lector.

archivo Seleccionar un writeup Abrir árbol
HackTheBox/Challenges/Challenge Apkey.md READ_ONLY

Challenge Apkey

Este reto consiste en eludir una validación de inicio de sesión y la solución consiste en descompilar el archivo APK, localizar la lógica de las credenciales, modificar el código Smali para omitir la comprobación del hash MD5, y finalmente reconstruir y firmar la aplicación para obtener la flag.

En este reto, el análisis inicial comienza trabajando con un archivo APK de Android. Al explorar la estructura de la aplicación utilizando la interfaz de JADX, se revela el archivo AndroidManifest.xml, el cual muestra que la etiqueta de la aplicación apunta a un recurso de cadena en lugar de un valor estático.

<?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>

Una revisión del archivo resources.arsc permite identificar el verdadero nombre de la aplicación dentro de las definiciones de cadenas de texto.

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

Al intentar instalar el APK original en un emulador de Android, se genera un error específico relacionado con la compresión del archivo resources.arsc. El gestor de paquetes de Android requiere que el paquete esté alineado en un límite de 4 bytes. Para solucionar esto, es necesario reestructurar los archivos internos mediante la herramienta zipalign.

$ 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

Con la aplicación correctamente alineada, se procede a generar un almacén de claves de depuración para firmar el APK, lo que permitirá su instalación en el emulador.

$ 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]

Esta nueva clave de depuración se utiliza para firmar el APK alineado mediante la herramienta 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 ...

El paquete ya está listo para ser desplegado en el dispositivo emulado.

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

Al abrir la aplicación se muestra un formulario de inicio de sesión sencillo que indica "Login to get a key". Dado que no se dispone de credenciales válidas, el siguiente paso lógico es analizar el código fuente de la aplicación. Tras reabrir el APK en la interfaz de JADX y examinar el código de MainActivity, se expone un nombre de usuario estático y un hash de contraseña en formato MD5.

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

Una revisión más profunda del código descompilado destaca algunas funciones altamente ofuscadas. Tras una autenticación exitosa, la aplicación realiza llamadas a métodos específicos para descifrar la clave y presentarla mediante un mensaje Toast de Android.

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)

Los intentos por descifrar el hash descubierto a2a3d412e92d896134d9c9126d756f utilizando bases de datos en línea resultan infructuosos. Una inspección más detallada del hash revela que solo cuenta con 30 caracteres en lugar de los 32 habituales en un resumen MD5. La causa subyacente reside en la forma en que la matriz de bytes se convierte a cadena dentro de la aplicación: el método Integer.toHexString() omite los ceros a la izquierda, corrompiendo la representación final del hash y haciéndolo imposible de descifrar.

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

Dado que no es posible recuperar la contraseña, se requiere un enfoque alternativo. El binario debe ser desensamblado, modificado y vuelto a ensamblar para eludir por completo la comprobación de autenticación. La utilidad apktool desensambla el APK y genera su representación en Smali.

$ 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...

El archivo MainActivity$a.smali contiene la lógica para la validación de la contraseña. Al modificar la condición de if-eqz (si es igual a cero) a if-nez (si no es igual a cero), se invierte efectivamente la comprobación, autenticando al usuario si se proporciona una contraseña incorrecta.

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

La modificación se verifica rápidamente para confirmar que la instrucción Smali ha sido reemplazada correctamente.

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

Con la lógica invertida, la aplicación debe reconstruirse en un archivo APK utilizando 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

Para preparar la aplicación modificada para su instalación, esta pasa nuevamente por el proceso de alineación.

$ 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

El APK alineado se firma utilizando el almacén de claves de depuración generado previamente.

$ 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 ...

La aplicación parcheada y firmada se despliega en el emulador, sobrescribiendo cualquier instalación anterior.

$ 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

Al ejecutar la aplicación e ingresar el usuario admin con una contraseña deliberadamente incorrecta, como a, se activa la validación invertida. La aplicación procesa la autenticación como exitosa y presenta la flag descifrada en un mensaje Toast, completando así el reto.

HTB{FLAG}