CCSC 2022 Writeups — Glooties App

Christos Falas
3 min readMay 15, 2022

This was the only mobile chall on this CTF. We start by installing the APK and opening it. At first glance, there’s not much to be done, since there’s only a login screen, for which we have no credentials (yet).

We notice that there are 2 flavors of the application, app-debug and app-release. I originally used the debug version at first (we will later find out that it doesn’t contain the actual flags, only placeholders for them. The actual flag is present in the release flavor, which is a bit more obfuscated)

Since there’s not much we can do inside the application, we decompile the application (using JADX, or using http://www.javadecompilers.com/apk) to see the login logic (and everything else we need).

In the application java files, we have the following files (these are present in the src/com/example/ctf_challenge folder):

Broadcast$$ExternalSyntheticLambda0.java .java 510 Bytes
Broadcast.java
MainActivity.java
AirplaneModeChangeReceiver.java
C0644R.java
GotIn.java
BuildConfig.java
MainActivity$$ExternalSyntheticLambda0.java

For now, we are interested in the MainActivity file. This is the login screen we see upon launching the application (this is usually the case with MainActivity, but we can verify that through the AppManifest.xml file, by checking that the MainActivity tag contains the MAIN action).

We notice the following interesting function.

public static String getFlag() {
return "ccsc{flag1_";
}

This is used by the onClickListener attached to the login button.

try {
if (Integer.parseInt(this.passwordEditText.getText().toString()) == new SecureRandom().nextInt()) {
startActivity(new Intent(this, GotIn.class));
}
} catch (Exception e) {
Log.d("ERROR:", Arrays.toString(e.getStackTrace()) + " " + getFlag());
}

The text that we enter in the password field is converted to int , and when that fails, the first part of the flag is output in the Logcat.

In order to move to the second part of the flag, we need to move past this login screen. One way to do that, would be to find a way to “predict” the next random generated by SecureRandom, which is obviously quite hard. Another way is to completely skip the login, and start the GotIn activity ourselves.

To do this, we can use adb: adb shell am start -n com.example.ctf_challenge/.GotIn

Before we actually do that though, we can check what that does. Looking at the decompiled GotIn.java class, we notice that a BroadcastReceiver is registered. BroadcastReceivers are used in Android to send signals between applications whenever an event occurs.

registerReceiver(this.airplaneModeChangeReceiver, new IntentFilter("android.intent.action.AIRPLANE_MODE"));

This is a system broadcast, caused by setting the device in airplane mode.

In order to see what our application does whenever such a change is detected, we move on to the AirplaneModeChangeReceiver.class file. In that file, we notice that whenever the broadcast is received, if it matches some specific data, it will start a new activity. Moving on to Broadcast.java (tired of moving between files yet?)

We finally find the second part of the flag

Intent intent = new Intent();
intent.setAction("com.example.ctf_challenge.OUT");
intent.putExtra("flag", getFlag());
sendBroadcast(intent);

In fact, whenever we press the button in this activity, a broadcast is sent which includes the second part of the flag.

Recovering the flag

Now that we understand the flow of the application, we can try recovering the actual flag (and not flag1 and flag2) from the app-release flavor of the application.

First order of business, we install the application, and connect our device to logcat (either through Android Studio, or using adb logcat ). When we enter a non-integer password (eg random text) on the MainActivity, we will get the first part of the flag in the logcat window.

For the second part, we can skip to the part that’s actually useful for us. We use adb to start the Broadcast activity.

adb shell am start -n com.example.ctf_challenge/.Broadcast

After that, we just press the button. Now, we sent a broadcast containing the flag. Except there’s no way to see it.

For that, I made a new application, whose only job is to receive that broadcast. It only registers a broadcast receiver which whenever it received the specific broadcast dumps all its data to Logcat.

When we run that application in the background and press the button on the Broadcast activity, we get the second part of the flag in the Logcat as well!

Flag: ccsc{ch3ck_l0g5_aNd_l1st3n}

--

--