NcN PreQuals 2013: Reto 2

Ayer veíamos la solución al reto 1 de las prequals del CTF de la NocONName de 2013, así que hoy vamos a ir con la solución del reto 2. Este reto consistía en una aplicación para Android (APK) de la que no se nos daba mucha más información.

Lo primero que intenté fue instalarla en el emulador, pero esta se cerraba nada más intentar arrancarla. Intenté lo mismo con un par de dispositivos físicos pero obtuve el mismo resultado. Tras intentar hacer cambios en el código a nivel smali (eso para otro post) para intentar arreglar los errores, pensando que era parte del reto, al final pensé en pegarle un vistazo al código antes de seguir por ese camino, no fuera que sea un código no ofuscado y sencillo de leer y no esté haciendo más que perder tiempo intentando ejecutarlo. Así que vamos a ello, a desempaquetar:

$ apktool d level.apk levelapk_apktool

Este comando, si tenemos instaladas las apktools, nos creará un directorio "levelapk_apktool" con todo el contenido del APK. Vamos a pegarle un vistazo al AndroidManifest.xml a ver cual es la MainActivity para ver por donde tenemos que empezar a buscar:

$ cat levelapk_apktool/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1" android:versionName="1.0" package="com.facebook_ctf.challenge"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />
    <application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@drawable/ic_launcher">
        <activity android:label="@string/title_activity_main" android:name="com.facebook_ctf.challenge.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:label="@string/title_activity_main" android:name="com.facebook_ctf.challenge.MainActivity" />
    </application>
</manifest>

Ya sabemos que el inicio de todo se encuentra en "com.facebook_ctf.challenge.MainActivity". Ahora podríamos irnos al directorio "smali" y bucear hasta esa función, pero a mi me resulta más sencillo extraer el dex y decompilarlo con alguna herramienta como jd-gui. Para ello tendremos que extraer el APK de otra forma, simplemente haciendo un unzip:

$ mkdir levelapk_unzip
$ cp level.apk levelapk_unzip/
$ cd levelapk_unzip
$ unzip level.apk

Tras hacer el unzip veremos que tenemos un fichero classes.dex . Este fichero no puede ser abierto directamente con jd-gui, pero podemos transformarlo en un JAR de forma sencilla con la herramienta dex2jar:

$ d2j-dex2jar.sh classes.dex 
dex2jar classes.dex -> classes-dex2jar.jar
$ mv classes-dex2jar.jar classes.jar

Ahora ya podemos irnos a JD-GUI y buscar "com.facebook_ctf.challenge.MainActivity" y sus funciones, particularmente el constructor y onCreate(), que es donde generalmente se inician las acciones:



Como podemos ver, el onCreate() realiza una serie de acciones y acaba llamando a una función de su propia clase llamada yaaaay(), que vamos a ver que pinta tiene:




En la función yaaaay(), se comienza instanciando un montón de Bitmaps que se sacan de los recursos de la aplicación (todavía no sabemos que son). Luego se elige uno de ellos de forma aleatoria y se muestra. Por en medio de todo eso, aparece una función makeMeHappyAgain() a la que se le están pasando el resultado de otras funciones makeMeHappy() a las que a su vez se les pasa los Bitmaps que comentamos anteriormente. La llamada sería una cosa así:

makeMeHappyAgain(
        makeMeHappy( localBitmap1, localBitmap2, localBitmap3, localBitmap4 ),
        makeMeHappy( localBitmap5, localBitmap6, localBitmap7, localBitmap8 ),
        makeMeHappy( localBitmap9, localBitmap10, localBitmap11, localBitmap12 ),
        makeMeHappy( localBitmap13, localBitmap14, localBitmap15, localBitmap16 )
);

Vamos a ver entonces que hacen estas funciones que nos van a hacer tan felices :)


Las funciones, como podéis ver, son casi iguales, ambas crean un nuevo bitmap y van pegando en él los otros bitmaps uno a continuación del otro. La única diferencia entre ambas funciones es que una lo hace en horizontal y la otra en vertical. Si volvemos a pensar en la llamada original, veremos que lo que está haciendo es coger todos los Bitmaps que había cargarlo y juntarlos todos en un solo Bitmap 4x4. Ese bitmap resultado... no va a ningún sitio!! La aplicación no hace nada con él, pero llegados a este punto seguro que la solución del reto iba por ahí, así que... vamos a ver, viendo que recurso estaba cargado en cada variable, como quedaría ese bitmap 4x4:


Pero... ¿cuales son estos recursos? Para saberlo tenemos que irnos a los ficheros de recursos de la aplicación a ver si encontramos estos mismos números, a ver que son:

$ cat levelapk-apktool/res/values/public.xml
[...]
    <public type="raw" name="a" id="0x7f040000" />
    <public type="raw" name="b" id="0x7f040001" />
    <public type="raw" name="c" id="0x7f040002" />
    <public type="raw" name="d" id="0x7f040003" />
    <public type="raw" name="e" id="0x7f040004" />
    <public type="raw" name="f" id="0x7f040005" />
    <public type="raw" name="g" id="0x7f040006" />
    <public type="raw" name="h" id="0x7f040007" />
    <public type="raw" name="i" id="0x7f040008" />
    <public type="raw" name="ic_secret" id="0x7f040009" />
    <public type="raw" name="j" id="0x7f04000a" />
    <public type="raw" name="k" id="0x7f04000b" />
    <public type="raw" name="l" id="0x7f04000c" />
    <public type="raw" name="m" id="0x7f04000d" />
    <public type="raw" name="n" id="0x7f04000e" />
    <public type="raw" name="o" id="0x7f04000f" />
    <public type="raw" name="p" id="0x7f040010" />
[...]

Como veis, los números aparecen, pero en su forma hexadecimal, y aparecen referenciados a elementos de tipo "raw", que si miramos en la carpeta "raw" a ver que pinta tienen, veremos algo así:


Está claro que al final de la jugada vamos a obtener un código QR donde seguramente estará el flag que buscamos. Ahora solo nos falta rehacer nuestro cuadro anterior pero esta vez poniendo ya el nombre de las imágenes:


La composición de la imagen quedaría tal que así, y la podríamos hacer con un script, con algunas herramientas que directamente juntan imágenes, o completamente a mano. En mi caso, como son pocas imágenes y no sabía de memoria como manejar imágenes (no es algo que suela programar), me pareció más rápido a mano. Veréis que he marcado dos bitmaps en amarillo, eso es porque, al montar la imagen, veréis de repente que el bitmap que estáis poniendo no encaja con los demás, pero no resulta muy complicado colocarlo "a ojo" en su sitio adecuado. Después de juntar todo y ver que el código QR resultante parece tener sentido, tenemos algo así:


Hay herramientas de linea de comandos para leer estos código, herramientas on-line, o directamente podéis apuntar con vuestro móvil a la pantalla y leerlo si tenéis la aplicación adecuada. Yo opté por hacerlo con una herramienta on-line. La primera que probé no me funcionó, pero la segunda que probé ya me sacó el resultado esperado:


Ya tenemos el segundo :)

Comentarios