Sunday, July 12, 2015

PoliCTF 2015: Crack Me If You Can - write-up

I worked on this challenge during the "PoliCTF 2015" as part of a CTF team called seven.

 We get an Android app called crack-me-if-you-can.apk, and are asked to extract the flag/password. First, I tried using apktool and APK Studio to decompile the application. Unfortunately, the APK seems to be corrupt, and the tools will not work!


 I opened the APK with 7Z (remember, APK is actually a ZIP file), and everything seemed to be in place. I tried the online version of the APK Decompiler, and luckily - it worked (thanks guys)!
Looking over the manifest, there does not seem to be anything special. We do however get a glimpse of the namespace (or package in Java) used: it.polictf2015.

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="it.polictf2015" platformBuildVersionCode="21" platformBuildVersionName="5.0.1-1624448">
    <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme">
        <activity android:label="@string/app_name" android:name="it.polictf2015.LoginActivity" android:windowSoftInputMode="stateVisible|adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
    </application>
</manifest>

The actual decompiled source code is in the src folder. Using the namespace above it is easy to navigate to the correct location with four files:
  • a.java - seems irrelevant, probably just a handler
  • b.java - a single class (called b) which has a bunch of methods which take a string and replace certain characters
  • c.java - same as b.java, but with fever methods
  • LoginActivity.java - this is the actual activity which presumably does all the work.
Looking over the source of the LoginActivity, we immediately see this string: flagging{It_cannot_be_easier_than_this}. Could it be this easy?!?!?!?

No... :)
This seems to be a red herring, and the fact that the string is being used as input to the replace function which changes "flagging" to "flag" does not help... :P
Actually, there are a bunch of methods that don't really seem to do much other then confuse use.

The only other method left is this one:

private boolean a(String s)
    {
        if (s.equals(c.a(it.polictf2015.b.a(it.polictf2015.b.b(it.polictf2015.b.c(it.polictf2015.b.d(it.polictf2015.b.g(it.polictf2015.b.h(it.polictf2015.b.e(it.polictf2015.b.f(it.polictf2015.b.i(c.c(c.b(c.d(getString(0x7f0c0038))))))))))))))))
        {
            Toast.makeText(getApplicationContext(), getString(0x7f0c003c), 1).show();
            return true;
        } else
        {
            return false;
        }
    }

This method seems to fetch a string from the resources, and then calls the replace methods embedded in the b and c classes. Even with all the duck typing, it's quite easy to follow the flow used to replace the string. The only thing missing is the actual string!
Looking at the extracted java files, there seems to be no R.java. So how do we get the string which is referenced with 0x7f0c0038?
I tried to search all the XML files in res folder for one of the strings being replaced - but that didn't work unfortunately!

Since apktool reported an error, that could mean some of the resources were not extracted. My last shot was to try and dig through the resources.arsc manually - which is what I did!
Opening the resources.arsc with a HEX editor and searching for the string "spdgj" got me this:


I extracted the whole string and ran the string replacement methods to get the flag: flag{Maybe_This_Obfuscation_Was_Not_That_Good_As_We_Thought}

Bellow it the python script I used for all the string replacements and its output.

eefla{g}{Maybe_This_Obfuscation_Was_Not_That_Good_As_We_Thought}.eeala{g}{Maspdggfdj_This_ObRuscatiot_That_budsgad_As_We_Thought}Te3

my_string = "ee[[c%l][c{g}[%{%Mc%spdgj=]T%aat%=O%bRu%sc]c%ti[o%n=Wcs%=No[t=T][hct%=buga[d=As%=W]e=T%ho[u%[%g]h%t[%}%.ee[[c%l][c{g}[%{%Mc%spdggfdj=]T%aat%=O%bRu%sc]c%ti[o[t=T][hct%=budsga[d=As%=W]e=T%ho[u%[%g]h%t[%}%T[]e3"

my_string = my_string.replace("spdgj", "yb%e")
my_string = my_string.replace("aat", "his")
my_string = my_string.replace("buga", "Goo")

my_string = my_string.replace("=", "_")
my_string = my_string.replace("\\}", "",1)
my_string = my_string.replace("\\{", "",1)
my_string = my_string.replace("R", "f",1)
my_string = my_string.replace("c", "f",1)
my_string = my_string.replace("]", "")
my_string = my_string.replace("[", "")
my_string = my_string.replace("%", "")
my_string = my_string.replace("c", "a")
my_string = my_string.replace("aa", "ca")

print my_stri