Skip to content

Instantly share code, notes, and snippets.

@Zachinio
Last active August 26, 2020 17:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zachinio/7ac122f5cd073f6a54fb08b247c5f18f to your computer and use it in GitHub Desktop.
Save Zachinio/7ac122f5cd073f6a54fb08b247c5f18f to your computer and use it in GitHub Desktop.

Google-CTF 2020 Write-up -Android Challenge

In this write-up I will describe how I managed to solve the Android challenge of the Google-CTF 2020 event.

The Solution

The challenge is basically an APK to download with a flag inside it. First thing I like to do is to install and run the APK in an emulator using the AVD manager (Android virtual device) of Android Studio. So after I launched the app a simple activity showed up which looks like this:

Webp net-resizeimage

A Quick Over-View

I started to play with by entering different texts and all that showed is a big red "X". Usually after that part, I try to decompile the APK and analyze its code and resources, so I used Jadx to decompile the dex code of the APK ( you can use any other dex decompiler). By looking at the activity source code in Jadx, I could see only parts of the code and some weird errors about decompile failures of specific parts. One of the missing parts was the "OnClick" method of the Button that is used to submit the flag:

Screenshot from 2020-08-25 20-53-41

I understood I would have to find another way to find the flag.

Start Getting My Hands Dirty

I decided to look deeper at this APK, so I used apktool to decompile the dex code and unpack the resources. I started to examine the smali code that apktool generated from the dex file and I found that the activity name is a special character:ő. After spending some time looking at the smali code of the activity,all I understood was:

  1. The flag length must be 48
  2. There is a loop which takes a single character from the flag,cast it to long and shift it.
  3. The final check is a comparison of 2 longs, not 2 strings
  4. There is a weird methon in R.java that returns an array of longs that is used at the final comparison
I tried to hook some methods of String and StringBuilder using Frida framework,but it didn't really advance me. I also ran jdb to debug the application,I found that there is a field of array of longs that used at the final comparison. After the techniques mentioned above didn't really advance me, I decided to try to patch the smali so I could "split out" the flag.

The Re-Compilation

In order to patch the smali code, I needed to recompile the apk using apktool with my patch but firstly I wanted to check I can just recompile the APK without any modifications. At my first try, apktool successfully builds the APK ,BUT there is this warning:

  /ctf/google-2020/android/reverse/AndroidManifest.xml:3: Tag <activity> attribute name has invalid character 'Q'.Ignoring...

This is optional, but I prefered to replace this special character with 'M'. apktool might fail to recompile your apk due to illegal resource name - '$ic_launcher_foreground__0.xml', what I did was to remove it, then I had to remove it also from the public.xml at 'res/values/public.xml', and remove the 'android:fillColor="@drawable/$ic_launcher_foreground__0' from 'ic_launcher_foreground.xml.

Now we can patch the smali and recompile the APK without any problems. So after examine the Jadx decompile error (look at the image above) and examine the smali for a prettly long time I found that there are some extra catch blocks with a bad type: ő.smali:line 17 - catches I = int which is not possible so I deleted it.

    .catch I {:try_start_0 .. :try_end_0} :catch_1

ő$1.smali:line 56 - catches J = long which is not possible so I deleted it.

    .catch J {:try_start_0 .. :try_end_0} :catch_0

ő$1.smali:line 83 - this try scope doesn't have a catch handler so I deleted it.

    .catch Ljava/lang/Exception; {:try_start_1 .. :try_end_1} :catch_0

recompile again the APK after patching the smali files and Voila - we can finally see the code of the "onClick" method.

Screenshot from 2020-08-26 00-28-54

Copy the code of the onClick method into a new fresh project and debug it easly. At first, I really tried to track this code , and even look at the function in R.smali, but I couldn't really follow all these maths operations. The code takes 4 characters at a time and run this math operations, so I decided to brut-force using 4 loops to try all the possiblities from 33 to 127 (ascii). Every computed value is compared to a long in value in a 12 length long array,so all I had to do is to run this code in another loop of 12 iterations to compare each long in the array:

final int i = 0;
                for (char j = 32; j < 127; j++) {
                    for (char j1 = 32; j1 < 127; j1++) {
                        for (char j2 = 32; j2 < 127; j2++) {
                            for (char j3 = 32; j3 < 127; j3++) {


                                f0M[i] = j3 << 24;
                                long[] jArr = f0M;
                                jArr[i] = jArr[i] | (j2 << 16);
                                long[] jArr2 = f0M;
                                jArr2[i] = jArr2[i] | (j1 << 8);
                                long[] jArr3 = f0M;
                                jArr3[i] = jArr3[i] | j;

                                if (((fun(f0M[count], 4294967296L)[0] % 4294967296L) + 4294967296L) % 4294967296L != f1class[count]) {
                                } else {
                                    Log.d("zachinio", "" + j + j1 + j2 + j3);
                                    return;
                                }
                            }
                        }
                    }
                }

After some time the brut-force worked and the flag revealed in the logcat :
CTF{y0u_c4n_k3ep_y0u?_m4gic_1_h4Ue_laser_b3ams!}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment