Skip to content

Trend Micro CTF 2015 Offensive 200

Note: For this challenge, we need install some things into our Android 5.1 device with Genymotion. For example, an ARM Translator. https://github.com/m9rco/Genymotion_ARM_Translation

Download APK: https://lautarovculic.com/my_files/VirusClicker.apk

Install the apk with adb

adb install -r VirusClicker.apk

And decompile with apktool

apktool d VirusClicker.apk

We can notice that the app isn't responding. So I need install this app into an Android API29 Let's inspect the source code with jadx (GUI version) We have the SplashActivity, MainActivity, and some other Activities. Launching the app, we can see an button and a counter until 10.000.000

So, we need a way for get the flag that we'll receive when we reach this number. We can see in the XML file MainPreferences.xml saved into /data/data/com.tm.ctf.clickerfolder in the device

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="DATA">Q</string>
    <int name="COUNT" value="1" />
</map>

I try override the file, but I don't have success. So, maybe we can modify the CongratulationsActivity

package com.tm.ctf.clicker.activity;  

import android.app.Activity;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.os.Bundle;  
import android.util.Log;  
import com.tm.ctf.clicker.p004a.C0238a;  
import java.io.IOException;  
import java.io.InputStream;  
import java.nio.ByteBuffer;  

/* loaded from: classes.dex */  
public class CongraturationsActivity extends Activity {  

    /* renamed from: b */  
    private static final String f563b = CongraturationsActivity.class.getSimpleName();  

    /* renamed from: c */  
    private static final byte[] f564c = {-119, 80, 78, 71, 13, 10, 26, 10};  

    /* renamed from: a */  
    SurfaceHolderCallbackC0240b f565a = null;  

    /* renamed from: a */  
    private Bitmap m921a() {  
        try {  
            InputStream open = getResources().getAssets().open("f.png");  
            byte[] bArr = new byte[open.available()];  
            open.read(bArr);  
            ByteBuffer allocate = ByteBuffer.allocate(bArr.length + 8);  
            allocate.put(f564c);  
            allocate.put(bArr);  
            return BitmapFactory.decodeByteArray(allocate.array(), 0, bArr.length + 8);  
        } catch (IOException e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  

    @Override // android.app.Activity  
    protected void onCreate(Bundle bundle) {  
        super.onCreate(bundle);  
        getActionBar().hide();  
        if (10000000 != C0238a.m918c()) {  
            finish();  
        }  
        this.f565a = new SurfaceHolderCallbackC0240b(this, String.valueOf(getIntent().getStringExtra("data")) + "Nf");  
        Bitmap m921a = m921a();  
        setContentView(this.f565a);  
        Log.i("VirusClicker", "width=" + m921a.getWidth() + ", height=" + m921a.getHeight());  
    }  
}

In this code we can see that the flag is showed. The flag is created in the method m924a

private void m924a(Canvas canvas, Paint paint) {  
        canvas.drawText("Conguraturations!", (this.f572c - ((int) paint.measureText("Conguraturations!"))) / 2, (this.f573d / 6) * 2, paint);  
        canvas.drawText("The flag is ...", (this.f572c - ((int) paint.measureText("The flag is ..."))) / 2, (this.f573d / 6) * 3, paint);  
        m925a();  
        String obj = C0246b.m933b(this.f575f.getBytes(), "click_machine").toString();  
        canvas.drawText("TMCTF{" + this.f575f + "}", (this.f572c - ((int) paint.measureText(r1))) / 2, (this.f573d / 6) * 4, paint);  
        Log.i("VirusClicker", "length=" + obj.length());  
    }
But there aren't nothing that we can do.

So, I found this code in ScoreBroadcastReceiver

public class ScoreBroadcastReceiver extends BroadcastReceiver {  
    @Override // android.content.BroadcastReceiver  
    public void onReceive(Context context, Intent intent) {  
        int intExtra = intent.getIntExtra("SCORE", 0);  
        String str = "";  
        if (3769 == intExtra) {  
            str = "2";  
        } else if (10007 == intExtra) {  
            str = "x";  
        } else if (59239 == intExtra) {  
            str = "p";  
        } else if (100003 == intExtra) {  
            str = "Y";  
        } else if (495221 == intExtra) {  
            str = "2";  
        } else if (1000003 == intExtra) {  
            str = "t";  
        } else if (9999999 == intExtra) {  
            str = "z";  
        }  
        C0238a.m916a(str);  
    }  
}
This code send the data score for some checks to the app. So, get again the previous code of the Congratulations activity
if (10000000 != C0238a.m918c()) {  
            finish();  
} 
Where compare with the Intent that is sent to the Broadcast. So, we can modify the smali code. The CongraturationsActivity.smali file is in /VirusClicker/smali/com/tm/ctf/clicker/activity directory. In the line 150 we can see the line if-eq v0, v1, :cond_0.

So, changing the if-eq statement to if-ne Must look like this if-ne v0, v1, :cond_0 Save the smali file.

I notice that here (in the c.class) are an method that register every touch screen. And we have the intent that is sent to the broadcast receiver.

public boolean onTouchEvent(final MotionEvent motionEvent) {
    switch (motionEvent.getAction()) {
        case 0: {
            return this.h = true;
        }
        case 1: {
            this.h = false;
            ++this.g;
            com.tm.ctf.clicker.a.a.b();
            if (3763 == this.g || 10007 == this.g || 59239 == this.g || 100003 == this.g || 495221 == this.g) {
                final Intent intent = new Intent("com.tm.ctf.clicker.SCORE");
                intent.putExtra("SCORE", this.g);
                this.a.sendBroadcast(intent);
            }
            if (10000000 <= this.g) {
                final Message obtain = Message.obtain();
                obtain.obj = String.valueOf(this.g) + "\n";
                this.b.sendMessage(obtain);
                return true;
            }
            break;
        }
    }
    return true;
}
And we need reach the last if condition f (10000000 <= this.g) For get the "final message". Then, we need modify again the smali file for c.smali file in /VirusClicker/smali/com/tm/ctf/clicker/activity We can see in the line 845 if-gt v0, v1, :cond_0 You need change if-gt (if greater than) to if-lt (if less-than).

The line must look like if-lt v0, v1, :cond_0 Save the file and now is time for rebuild the apk.

Build the apk

apktool b VirusClicker

Generate a key

keytool -genkey -v -keystore name.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias alias

Sign the apk

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore name.keystore VirusClicker/dist/VirusClicker.apk alias

Uninstall the app in the device and reinstall the new apk

adb install -r VirusClicker/dist/VirusClicker.apk

So now, launch the app. Do not touch the app. We can complete the challenge with adb. Sending the intents via broadcast the value of SCORE like the code do.

Send this chain of broadcast with adb

adb shell am broadcast -a com.tm.ctf.clicker.SCORE -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver --ei SCORE 3769
adb shell am broadcast -a com.tm.ctf.clicker.SCORE -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver --ei SCORE 10007
adb shell am broadcast -a com.tm.ctf.clicker.SCORE -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver --ei SCORE 59239
adb shell am broadcast -a com.tm.ctf.clicker.SCORE -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver --ei SCORE 100003
adb shell am broadcast -a com.tm.ctf.clicker.SCORE -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver --ei SCORE 495221
adb shell am broadcast -a com.tm.ctf.clicker.SCORE -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver --ei SCORE 1000003
adb shell am broadcast -a com.tm.ctf.clicker.SCORE -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver --ei SCORE 9999999

Let's explain the params of the adb command: - adb shell: Start a shell session with the device. - am broadcast: Sent the Broadcast Intent. - -a com.tm.ctf.clicker.SCORE: Set the intent action. - -n com.tm.ctf.clicker/.receiver.ScoreBroadcastReceiver: Specify the component. - --ei SCORE <valor>: Add the extra integer with the SCORE key and the value.

So, just make a click and get the flag. A black screen with white chars must be printed. The flag is TMCTF{Congrats_10MClicks}

I hope you found it useful (: