Avatar

memst

Practising computer addict

[C2C CTF 2023] Boring Old Default

Description

Just you're stock-standard AndroidStudio starter application. Or is it? 0.0

Solution

Identify the file as an Android apk, therefore, we need to decompile it. I used the one on javadecompilers.com, but downloading and using JADX locally has the same result.

The first thing I did was run grep to find a flag, which quickly narrowed down the search space to one file of interest:

$ grep -r "FLAG{" .
Binary file ./resources/classes3.dex matches
./sources/com/example/boring_old_default/WeirdActivity.java:                newString.append("FLAG{");
./sources/com/example/boring_old_default/WeirdActivity.java:                newString.append("FLAG{a");
./sources/com/example/boring_old_default/WeirdActivity.java:                newString.append("FLAG{a3");
./sources/com/example/boring_old_default/WeirdActivity.java:                newString.append("FLAG{a3b");
./sources/com/example/boring_old_default/WeirdActivity.java:                newString.append("FLAG{a3b... Awwwwh so close!");

Looking at WeirdActivity.java, there were a few things of interest:

public class WeirdActivity extends AppCompatActivity {
    ...
    static {
        System.loadLibrary("images-lib");
    }
    ...
    private String handleFirstHalf() {
        int[] nums = firstHalf();
        StringBuilder firstHalfStr = new StringBuilder();
        for (int i = 0; i < 9; i++) {
            firstHalfStr.append((char) (nums[i] - 42));
        }
        return firstHalfStr.toString();
    }

    /* access modifiers changed from: private */
    public String handleButtonPress() {
        StringBuilder newString = new StringBuilder();
        switch (this.counter) {
            ...
            case 100:
                newString.append(handleFirstHalf());
                this.beepAccessed = 1;
                break;
            ...
        }
        newString.append("F");
        return newString.toString();
    }

    /* access modifiers changed from: private */
    public String handleSecondHalf() {
        if (this.beepAccessed != 0) {
            return secondHalf(new Random().nextInt(10066329));
        }
        return "Not that easy pal... " + somethingSpecial();
    }

It seems like the app imports a library images-lib, which has

  1. firstHalf() that returns an array of ints that are to be decoded as characters.
  2. secondHalf() that returns a string with the 2nd half of the flag.

Let’s pop the [apk dir]/resources/lib/x86/libimages-lib.so into Ghidra.

First Half

firsthalf in ghidra

In ghidra we navigate to firstHalf function, and can see that

  1. Some memory gets copied into local_5c
  2. local_5c gets copied to local_38
  3. I can assume that loca_38 gets converted to an int array and put into local_60
  4. local_60 gets returned.

Let’s look at the memory region that is copied in step 1.:

memory region

We can see that it’s 9 ints, all of which are less than 255. Put them into Python and copy what handleFirstHalf() function does in Java:

firstHalf = [0x70, 0x76, 0x6B, 0x71, 0xA5, 0x8B, 0x5D, 0x8C, 0x90]
firstHalfStr = ""
for i in firstHalf:
  firstHalfStr += chr(i-42)
print(firstHalfStr)

We get the 1st part of the flag: FLAG{a3bf

Second Half

secondhalf in ghidra

We look at the 2nd half in ghidra and find that it does operations on a certain string "=0HMmJ2MxADZ. It took me a while to figure out that the decompiled pseudocode is a bit wrong (as often happens with ghidra), so you must look at assembly if you want to understand the function. But you don’t need to! The string has an = at the beginning, so it looks like a reversed base64 encoded string. So run the following in python:

import base64
print(base64.b64decode("=0HMmJ2MxADZ"[::-1]))

and you get the 2nd half of the flag: d013bf0}

Flag

FLAG{a3bfd013bf0}
Written on May 18, 2023