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/illintentions.apk
Install the apk with adb
adb install -r illintentions.apk
adb install -r illintentions.apk
apktool d illintentions.apk
And let’s check the source code with jadx (GUI version)
We can see that the package name is com.example.hellojni
So, after read the code some minutes, we have the MainActivity
public class MainActivity extends Activity {
@Override // android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(getApplicationContext());
tv.setText("Select the activity you wish to interact with.To-Do: Add buttons to select activity, for now use Send_to_Activity");
setContentView(tv);
IntentFilter filter = new IntentFilter();
filter.addAction("com.ctf.INCOMING_INTENT");
BroadcastReceiver receiver = new Send_to_Activity();
registerReceiver(receiver, filter, Manifest.permission._MSG, null);
}
}
Here we can see an intent.
We have a broadcast receiver in Send_to_Activity
public class Send_to_Activity extends BroadcastReceiver {
@Override // android.content.BroadcastReceiver
public void onReceive(Context context, Intent intent) {
String msgText = intent.getStringExtra("msg");
if (msgText.equalsIgnoreCase("ThisIsTheRealOne")) {
Intent outIntent = new Intent(context, (Class>) ThisIsTheRealOne.class);
context.startActivity(outIntent);
} else if (msgText.equalsIgnoreCase("IsThisTheRealOne")) {
Intent outIntent2 = new Intent(context, (Class>) IsThisTheRealOne.class);
context.startActivity(outIntent2);
} else if (msgText.equalsIgnoreCase("DefinitelyNotThisOne")) {
Intent outIntent3 = new Intent(context, (Class>) DefinitelyNotThisOne.class);
context.startActivity(outIntent3);
} else {
Toast.makeText(context, "Which Activity do you wish to interact with?", 1).show();
}
}
}
The ThisIsTheRealOne class
public class ThisIsTheRealOne 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);
@Override // android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("Activity - This Is The Real One");
Button button = new Button(this);
button.setText("Broadcast Intent");
setContentView(button);
button.setOnClickListener(new View.OnClickListener() { // from class: com.example.application.ThisIsTheRealOne.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.ctf.OUTGOING_INTENT");
String a = ThisIsTheRealOne.this.getResources().getString(R.string.str2) + "YSmks";
String b = Utilities.doBoth(ThisIsTheRealOne.this.getResources().getString(R.string.dev_name));
String c = Utilities.doBoth(getClass().getName());
intent.putExtra("msg", ThisIsTheRealOne.this.orThat(a, b, c));
ThisIsTheRealOne.this.sendBroadcast(intent, Manifest.permission._MSG);
}
});
}
static {
System.loadLibrary("hello-jni");
}
}
The IsThisTheRealOne
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);
@Override // android.app.Activity
public void onCreate(Bundle savedInstanceState) {
getApplicationContext();
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("Activity - Is_this_the_real_one");
Button button = new Button(this);
button.setText("Broadcast Intent");
setContentView(button);
button.setOnClickListener(new View.OnClickListener() { // from class: com.example.application.IsThisTheRealOne.1
@Override // android.view.View.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();
String c = Utilities.doBoth(name.substring(0, name.length() - 2));
intent.putExtra("msg", IsThisTheRealOne.this.perhapsThis(a, b, c));
IsThisTheRealOne.this.sendBroadcast(intent, Manifest.permission._MSG);
}
});
}
static {
System.loadLibrary("hello-jni");
}
}
And the DefinitelyNotThisOne
public class DefinitelyNotThisOne extends Activity {
public native String computeFlag(String str, String str2);
public native String definitelyNotThis(String str, String str2);
public native String orThat(String str, String str2, String str3);
public native String perhapsThis(String str, String str2, String str3);
@Override // android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("Activity - Is_this_the_real_one");
Button button = new Button(this);
button.setText("Broadcast Intent");
setContentView(button);
button.setOnClickListener(new View.OnClickListener() { // from class: com.example.application.DefinitelyNotThisOne.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.ctf.OUTGOING_INTENT");
DefinitelyNotThisOne.this.getResources().getString(R.string.str1);
String b = Utilities.doBoth(DefinitelyNotThisOne.this.getResources().getString(R.string.test));
String c = Utilities.doBoth("Test");
intent.putExtra("msg", DefinitelyNotThisOne.this.definitelyNotThis(b, c));
DefinitelyNotThisOne.this.sendBroadcast(intent, Manifest.permission._MSG);
}
});
}
static {
System.loadLibrary("hello-jni");
}
}
The Utilities class is for decrypt the strings in strings.xml
resource file
Msg permission for this app
SendAnIntentApplication
Leetdev
Qvq lbh guvax vg jbhyq or gung rnfl?
l33tdev42
`wTtqnVfxfLtxKB}YWFqqnXaOIck`
IIjsWa}iy
TRytfrgooq|F{i-JovFBungFk
H0l3kwjo1|+kdl^polr
Test String for debugging
I don’t want waste my time with the lib native libhello-jni.so
So, I decide create my own app that send the broadcast to the target app.
But, before, we need change this in the AndroidManifest.xml file of the illintentions.apk
We just can rename signature for normal (or just delete the permission)
Why? Because the is protected and if we don’t change this, the intent will not sent and our app will get a message like
W/BroadcastQueue( 544): Permission Denial: broadcasting Intent { act=com.ctf.INCOMING_INTENT flg=0x10 (has extras) } from illintentions.solve (pid=14364, uid=10095) requires ctf.permission._MSG due to registered receiver BroadcastFilter{265bee3c u0 ReceiverList{33c9b82f 14191 com.example.hellojni/10098/u0 remote:2317760e}}
So change signature to normal and save the AndroidManifest.xml file
Then, rebuild the apk with apktool
apktool b illintentions
Generate a key
keytool -genkey -v -keystore name.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias alias
Then, sign the apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore name.keystore illintentions/dist/illintentions.apk alias
Uninstall the original apk from the device and install the new apk
adb install -r illintentions/dist/illintentions.apk
So, now we need create our receiver.
The filesMainActivity.java
package illintentions.solve;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.xml
Create a java class for receive the intentReceiver.java
package illintentions.solve;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class Receiver extends BroadcastReceiver {
private static final String TAG = "Receiver";
@Override
public void onReceive(Context context, Intent intent ) {
String message = intent.getStringExtra("msg");
Log.d(TAG, "BROADCAST FOUND:");
Log.d(TAG, "Message: "+message);
}
}
And the AndroidManifest.xml
of our app looks like
So, compile our app. And wait until this is executed.
When is executed, we can call the activities with adb of the target app.
We can use am
(activity manager) for sent a broadcast with adb.
Run logcat for get the message logs
adb logcat -c && adb logcat
And in another terminal, run
adb shell am broadcast -a com.ctf.INCOMING_INTENT -e "msg" "DefinitelyNotThisOne"
Press the BROADCAST INTENT button in the target app and:
Output: Message: Told you so!
Let’s try with another activity
adb shell am broadcast -a com.ctf.INCOMING_INTENT -e "msg" "ThisIsTheRealOne"
Output: Message: KeepTryingThisIsNotTheActivityYouAreLookingForButHereHaveSomeInternetPoints!
So the last
adb shell am broadcast -a com.ctf.INCOMING_INTENT -e "msg" "IsThisTheRealOne"
Output: Message: Congratulation!YouFoundTheRightActivityHereYouGo-CTF{IDontHaveABadjokeSorry}
We get the flag CTF{IDontHaveABadjokeSorry}
I hope you found it useful (:
Leave a Reply