BSides San Francisco CTF FlagReceiver writeup
Flag Receiver – 200
Here is a simple mobile application that will hand you the flag.. if you ask for it the right way.*P.S, it is meant to have a blank landing activity Use string starting with Flag:
First of all, I decompiled apk code with apktool and enjarify:
➜ apktool d --no-src flagstore.apk
➜ enjarify flagstore/classes.dex -o classes.jar
Then I browsed application code using JD-GUI and found that
- It registers BroadcastReceiver called
Send_to_Activity
forcom.flagstore.ctf.INCOMING_INTENT
action:
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
TextView localTextView = new android/widget/TextView;
Context localContext = getApplicationContext();
localTextView.<init>(localContext);
localTextView.setText("To-do: UI pending");
setContentView(localTextView);
IntentFilter localIntentFilter = new android/content/IntentFilter;
localIntentFilter.<init>();
localIntentFilter.addAction("com.flagstore.ctf.INCOMING_INTENT");
Send_to_Activity localSend_to_Activity = new com/flagstore/ctf/flagstore/Send_to_Activity;
localSend_to_Activity.<init>();
registerReceiver(localSend_to_Activity, localIntentFilter, "ctf.permissions._MSG", null);
}
- After receiving
com.flagstore.ctf.INCOMING_INTENT
it checks thatmsg
parameter of this intent is equal toOpenSesame
and if it is true the application starts new activity calledCTFReceiver
:
public void onReceive(Context paramContext, Intent paramIntent)
{
String str1 = paramIntent.getStringExtra("msg");
Intent localIntent = null;
Object localObject = "OpenSesame";
int i = str1.equalsIgnoreCase((String)localObject);
if (i != 0)
{
String str2 = "Intent";
Log.d("Here", str2);
localIntent = new android/content/Intent;
localObject = CTFReceiver.class;
localIntent.<init>(paramContext, (Class)localObject);
paramContext.startActivity(localIntent);
}
for (;;)
{
return;
String str3 = "Ah, ah, ah, you didn't say the magic word!";
i = 1;
localObject = Toast.makeText(paramContext, str3, i);
((Toast)localObject).show();
}
}
- Then in
CTFReceiver
activity inOnClick
event handler it does weird things with some strings using the code from native library (libnative-lib.so) and broadcasts the result asmsg
parameter ofcom.flagstore.ctf.OUTGOING_INTENT
:
public void onClick(View paramView)
{
Intent localIntent = new android/content/Intent;
localIntent.<init>();
localIntent.setAction("com.flagstore.ctf.OUTGOING_INTENT");
StringBuilder localStringBuilder = new java/lang/StringBuilder;
localStringBuilder.<init>();
String str1 = this.this$0.getResources().getString(2131099686);
String str2 = str1 + "fpcMpwfFurWGlWu`uDlUge";
String str3 = Utilities.doBoth(this.this$0.getResources().getString(2131099683));
String str4 = getClass().getName().split("\\.")[4];
int i = str4.length() + -2;
String str5 = Utilities.doBoth(str4.substring(0, i));
String str6 = this.this$0.getPhrase(str2, str3, str5);
localIntent.putExtra("msg", str6);
this.this$0.sendBroadcast(localIntent);
}
So, to get flag we should:
- Send
com.flagstore.ctf.INCOMING_INTENT
with parametermsg="OpenSesame"
to the app. - Click the button in
CTFReciever
activity - Get
msg
parameter ofcom.flagstore.ctf.INCOMING_INTENT
I decieded to try something new, i.e. not to use debugger and solve this task by using android emulator, adb and tool called drozer. Let's start!
First of all, run an android emulator and install flagstore.apk to it:
➜ emulator -avd 24_x86_64
➜ adb install flagstore.apk
Then, install drozer client and its dependencites to your computer:
➜ wget https://github.com/mwrlabs/drozer/releases/download/2.4.2/drozer-2.4.2-py2.7.egg
➜ easy_install drozer-2.4.2-py2.7.egg
➜ pip install twisted
After that, generate drozer agent apk and install it to the emulator:
➜ drozer agent build
...
Done: /var/folders/s4/hf3pw66928v6qdhftl_53lkr0000gn/T/tmpAKONaf/agent.apk
➜ adb install /var/folders/s4/hf3pw66928v6qdhftl_53lkr0000gn/T/tmpAKONaf/agent.apk
Run drozer agent on the emulator and click the On button:
On your computer forward drozer's port and connect to it using the client:
➜ adb forward tcp:31415 tcp:31415
➜ drozer console connect
Selecting 83e5e2881cdf4d59 (unknown Android SDK built for x86_64 7.0)
.. ..:.
..o.. .r..
..a.. . ....... . ..nd
ro..idsnemesisand..pr
.otectorandroidsneme.
.,sisandprotectorandroids+.
..nemesisandprotectorandroidsn:.
.emesisandprotectorandroidsnemes..
..isandp,..,rotectorandro,..,idsnem.
.isisandp..rotectorandroid..snemisis.
,andprotectorandroidsnemisisandprotec.
.torandroidsnemesisandprotectorandroid.
.snemisisandprotectorandroidsnemesisan:
.dprotectorandroidsnemesisandprotector.
drozer Console (v2.4.2)
dz>
In drozer console start listening tocom.flagstore.ctf.OUTGOING_INTENT
action:
dz> run app.broadcast.sniff --action "com.flagstore.ctf.OUTGOING_INTENT"
[*] Broadcast receiver registered to sniff matching intents
[*] Output is updated once a second. Press Control+C to exit.
Then, run the flagstore application on the emulator:
Send com.flagstore.ctf.INCOMING_INTENT
with correct msg
parameter to the app using adb:
➜ adb shell
generic_x86_64:/ $ su
generic_x86_64:/ $ am broadcast -a "com.flagstore.ctf.INCOMING_INTENT" --es msg "OpenSesame"
Click appeared Broadcast button in the emulator:
Finally, in the drozer console you see:
Action: com.flagstore.ctf.OUTGOING_INTENT
Raw: Intent { act=com.flagstore.ctf.OUTGOING_INTENT flg=0x10 (has extras) }
Extra: msg=CongratsGoodWorkYouFoundItIHopeYouUsedADBFlag:TheseIntentsAreFunAndEasyToUse (java.lang.String)