Sunday, May 8, 2016

Solution to Google CTF Mobile Challenge III Intentions

I do not usually play CTF challenges, but they are indeed a very good way to challenge your skills and and learn a lot.


A few days ago there was the Google Capture The Flag Challenge. I did not participate but a friend of mine asked me about the Mobile challenge as it was focused on Android.


I took a look to get an idea about the challenge and possible ways to find a solution to it.
The challenge consisted on an APK file with a few methods and a call to a native library. That native library contained the code to get the flag. But let's start from the beginning.

The first thing I did was to take a look to the AndroidManifest.xml, to get an idea of the activities, permissions needed, etc. There are several tools to check the AndroidManifest, since APK decompiler like jadx or other tools like 'apktool' to unzip the file and get the content. I used in this case jadx as I can see also the source code as well.

In this case, the content of the AndroidManifest.xml is as showed below:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:"http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.example.hellojni" platformBuildVersionCode="22" platformBuildVersionName="5.1.1-1819727">
    <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="23" />
    <permission android:name="ctf.permission._MSG" android:protectionLevel="signature|signatureOrSystem" android:description="@string/android_permission__msg" />
    <permission android:name="ctf.permission._SEND" android:description="@string/android_permission__msg" />
    <application android:label="CTF Application" android:icon="@mipmap/ic_launcher">
        <activity android:label="Main Activity" android:name="com.example.application.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:label="Activity: Is This The Real One" android:name="com.example.application.IsThisTheRealOne" />
        <activity android:label="This Is The Real One" android:name="com.example.application.ThisIsTheRealOne" />
        <activity android:label="Definitely Not This One" android:name="com.example.application.DefinitelyNotThisOne" />
        <receiver android:name="com.example.application.Send_to_Activity" android:exported="true" />
    </application>
</manifest>

Analysing the AndroidManifest.xml, the first I need to consider is that this APK will only run in devices or virtual devices with recent version of the OS, as it requires SDKversion 22 or 23. In my lab I have a physical Nexus 5 device with the latest version, Android 6.0.1 (hammerhead-mob30d), with a custom kernel which permits to load kernel modules, as I explained in this post. I use this device always for malware analysis so I can see the full memory in case I need it.




Continuing with the AndroidManifest.xml, the second significant point is that it only requieres 2 custom permissions: ctf.permissions._MSG and ctf.permissions._SEND.

The main activity is: com.example.application.MainActivity. But there are also some other activities: com.example.application.IsThisTheRealOne, com.example.application.ThisIsTheRealOne, com.example.application.DefinitelyNotThisOne. Moreover, there is a receiver com.example.application.Send_to_Activity


So, next step is to take a look to the code in order to understand all the activities and the receiver. 


MainActivity:




The Main activity performs a call to Send_To_Activity() when the intent is com.ctf.INCOMING_INTENT. 


Send_to_Activity



This Class is essentially an extended BroadcastReceiver, hence it waits to some specific event to happen in order to launch a specific activity. In this case, I can see that it depends on the content of the string 'msg' it will call a different method. The possible values of 'msg' can be:  ThisIsTheRealOne, DefinitelyNotThisOne, IsThisTheRealOne (or any other value which will show a default message).


The three classes ThisIsTheRealOne, DefinitelyNotThisOne, IsThisTheRealOne which implement the different activities are very similar in terms of code:






The code of one of the classes contains the following:



import com.example.hellojni.R;

public class IsThisTheRealOne extends Activity {
    public native String computeFlag(String str, String str2);

    public native String definitelyNotThis(String str, String str2, String str3);

    public native String orThat(String str, String str2, String str3);

    public native String perhapsThis(String str, String str2, String str3);

    public void onCreate(Bundle savedInstanceState) {
        Context context = getApplicationContext();
        super.onCreate(savedInstanceState);
        new TextView(this).setText("Activity - Is_this_the_real_one");
        Button button = new Button(this);
        button.setText("Broadcast Intent");
        setContentView(button);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.ctf.OUTGOING_INTENT");
                String a = IsThisTheRealOne.this.getResources().getString(R.string.str3) + "\\VlphgQbwvj~HuDgaeTzuSt.@Lex^~";
                String b = Utilities.doBoth(IsThisTheRealOne.this.getResources().getString(R.string.app_name));
                String name = getClass().getName();
                intent.putExtra("msg", IsThisTheRealOne.this.perhapsThis(a, b, Utilities.doBoth(name.substring(0, name.length() - 2))));
                IsThisTheRealOne.this.sendBroadcast(intent, permission._MSG);
            }
        });
    }

    static {
        System.loadLibrary("hello-jni");
    }
}




In the beginning of the code, there are 4 native methods: computeFlagdefinitelyNotThis, orThat,  perhapsThis. Those methods are part of a native library 'hello-jni' which is loaded at the end of each class.

When creating the object from the class IsThisTheRealOne, several things happens:

  • A display-text is created
  • A button with the test 'Broadcast Intent' is created
  • When the button is pushed, a new intent is created. That intent has the action 'com.ctf.OUTGOING_INTENT'  and contains some manipulated strings, which in the end are sent through a Broadcast.
  1. Modifying the code to include some debugging code to dump into the debug logs the content of the Intent. This could be done in the native smali code or creating again the Java code with that new debugging lines
  2. Creating a very small APK which it is able to receive the brocadcasted intent com.ctf.OUTGOING_INTENT and displaying it
  3. Using any kind of hooking tool, like xposed, to hook the calls to the interesting methods.
  4. Reversing the native library, try to understand the code and create some script to simulate.
  5. Dump the memory of the android device once the APK has been executed and the correct activity has been launched. 

So in essence, what it looks it is happening, is that once the correct activity is created, some calls to native methods included in a native library happens, which create/manipulated some strings. Those strings included in an intent are sent through a broadcast. Hopefully, that intent sent through the broadcast contains the flag we are looking for.

Some possible ways to gather the flag:

1,2,3,4 requires to create some custom code, rebuild the APK, sign the APK, etc. As I already had my Nexus device ready to dump the memory, I choose option 5.

The first thing is to install the APK, once done, it is time to send the broadcast with the correct string in the 'msg' and capture the memory.

To send a broadcast, it is possible to use drozer, or the Android framework. 
I did it directly with the Android framework





After that, I captured the memory with LiME as explained here.

Now, it is time to search across the full memory dump with an HEX editor or any tool like 'strings'. After some minutes and different tests, I finally manage to find through the strings 'CTF' the correct flag:

 






Here is your Reply: Congratulation!YouFoundTheRightActivityHereYouGo-CTF{IDontHaveABadjokeSorry}