This is a write up of an open source CTF practice challenge. The aim of this CTF is to learn how to reverse engineer an Android Application. You can find the CTF link here.

Note: This was originally written on Medium and has been converted to markdown using mediumexporter

Tools used

Installing the application

Make sure to connect the android phone with debugging mode enabled and then install the application.

adb install kgb-messenger.apk

Decoding using Apktool

Decode the APK using Apktool and output it into kgb-smali folder.

Converting the apk in .jar format using dex2jar

We convert to jar because then we can use JD-GUI to see Java code.

Using JD-GUI, we open the kgb-jar.jar created by the dex2jar (previous command).

Note: I downloaded JD-GUI and created a directory called tools and move it to that directory Note: I downloaded JD-GUI and created a directory called tools and move it to that directory

Launching the app now

As soon as we launch the app we get this error.

To see what is causing this error, we need to see which Activity is being launched first. So we open AndroidManifest.xml which can be found inside kgb-smali (Files created by apktool)

Using vim editor, we open AndroidManifest.xml

Snippet of part of AndroidManifest.xml Snippet of part of AndroidManifest.xml

MainActivity is the activity that is launched first. So use JD-GUI to view MainActivity.class

We can see, when the activity is created, two string values are checked. First str1 is checked if it equals to Russia. Similarly, str2 is checked if it equals to getResources().getString(2131558400). **The number is numerical representation for the value of string stored in strings.xml file.

Since we also have the .smali** **files inside smali folder created by Apktool, we open MainActivity.smali and locate this particular line getResources().getString(2131558400)

Before that we need to represent 2131558400 in hex format so that it becomes easier for us to find the value inside of smali code.

So we open MainActivity.smali file using Vim editor.

Now, we try to locate the String resource which has the id 0x7f0d0000 and is being compared to str2.

We go to the **res/values directory and search where does 0x7f0d0000 **occurs

We see that the name is “User” and type is “string”. So we search for **“User” **and in strings.xml file the name=”User” has value encoded using Base64. We docode it.

Capturing the Second Flag

To capture the second flag we need to go to the next activity, that is LoginActivity.

onCreate method of MainActivity onCreate method of MainActivity

In order to get to LoginActivity, we need to find a way to get through both if conditions or we could just remove them.

Let’s open the .smali version of MainActivity.class to remove the code responsible for both if conditions.

Smali version of first condition Smali version of first condition

Smali version of second condition Smali version of second condition

Getting rid of both conditions

Selecting the code for removal Selecting the code for removal

After removal After removal

Note: Make sure after removing your code looks this and ends with goto :go_to_0

Building the apk

After making the changes we need to build the apk. So we build the apk using Apktool.

Signing the apk

We cannot directly install the apk. We need to sign them first. However, since we are not the original developers of this app, we will Uber Apk Signer for this purpose.

Note: I downloaded Uber Apk Signer and created a directory called tools and move it to that directory Note: I downloaded Uber Apk Signer and created a directory called tools and move it to that directory

Installing and running the modified apk

Now when we launch, we are directly taken to LoginActivity.

Now we have to find out what the username and password is. Let’s take a look at the source code again but this time for LoginActivity using JD-GUI

Inside onLogin method, we have two edit text who are converted to string. EditText1 is converted to string n and EditText2 is converted to string o. Right now we do not know which EditText corresponds to username and password.

Finding username

We look at the first nested if condition, string n is being compared to a resource with id 2131158450. So we convert it to hex code again and check if we can find the corresponding string name.

Finding the username value by using id which is found using hex code of 2131158450 Finding the username value by using id which is found using hex code of 2131158450

So the username is codenameduchess.

Finding password

Let’s try to find the password using the same method used for username.

We go through the code again, and can see that function j should return false.

Here, the string o is hashed using MD5 and then compared with string resource id 2131558446.

We try to find the value of hash from strings.xml and would use findmyhashto find its original value.

We get hash value in the strings.xml, but when we try to use findmyhash to find the hash’s original value, we do not get any results. The question did say that we would have to use social engineering to get the password. So we try googling codenameduchess.

Google result for codenameduchess Google result for codenameduchess

The name of account ‘Sterling Archer’ also checks out with the first flag. So we take a look at it’s twitter account.

Twitter page for codenameduchess (Sterling Archer) Twitter page for codenameduchess (Sterling Archer)

It looks like it is a character of a TV show. We now try to Google for codename duchess password.

Google result for codename duchess password Google result for codename duchess password

We open the PDF, and search through it for password.

According to this, the password is Guest. So we input the password as ‘guest’ (all lowercase).

And..we are in. The Flag is G00G13_PR0.

Checking the value of hash

Just for fun, let’s see why could we not find the hash. So when we calculate the MD5 hash of guest, we get

So the reason we were not able to find the result was the hash we had was incomplete (did not have the zero at the start).

Capturing the third flag

After logging in, we are taken to MessageActivity. There’s where we will find our third flag.

So we open MessageActivity using JD-GUI, we take a look at the source code.

Function onSendMessage from MessageActivity Function onSendMessage from MessageActivity

Whenever we send the message, onSendMessage function is called, and the text entered using EditText is converted to String str.

Now if we look closely, the string str is passed to a function named **a **on which equals function is called to check if it is equal to p.

The value of p is:

Now, let’s take a look at function a

Function a** **returns string. In this function, the value of string passed as an argument obtained by:

Visual representation of the function a Visual representation of the function a

So, the value of p equals to the parameter string passed to this function a. So, we can reverse engineer the original value of p by doing these steps in reverse. As we know (A XOR B) XOR B = A, we can use this to find the original value of the string:

Visual representation of function where we XOR again Visual representation of function where we XOR again

We recreate this above algorithm using Python:

p = "V@]EAASB\022WZF\022e,a$7(&am2(3.\003"
p = list(str(p))

for i in range(len(p) // 2):
	p[i] = chr(ord(p[i]) ^ 0x32)
	p[len(p) // 2 + 1 + i] = chr(ord(p[len(p) // 2 + 1 + i]) ^ 0x41)

p.reverse()
print("".join(p))

When we run this file, we get

So we enter this string as the input for the EditText of the app:

Similarly, the input from the EditText is passed through function b and check if it equals to string r.

The value of String r The value of String r

Function b whose returned value is compared to String r Function b whose returned value is compared to String r

While converting the smali code to java class, there seems to be some problem. The code can be refactored so it can be better understood.

Just a readable version of function b Just a readable version of function b

Here it is not possible to reverse engineer, so we try to brute force our way in. We check for what values of loop iterable i and alphabet, we get the output r.

import string

r = "\000dslp}oQ\000 dks$|M\000h +AYQg\000P*!M$gQ\000"
r = list(str(r))
r.reverse()

for i in range(len(r)):
	if i % 8 == 0:
		print("_", end="")
		continue 

After running this file, we get the output.

The values for every 8th position is ‘_’ because we have i%8 == 0. And irrespective of the alphabets, the output from the function is 0, so it is difficult to find the answer using brute force.

So the message could be May I PLEASE have the password.

Let’s put this message

Third flag captured.

Why did not directly type this message and type the message before?

To understand this, we need to see how the flag is calculated. Function i is responsible for calculating the flag. Let’s see how

The first condition checks if String q and s are not null. That is they have to be initialized and set to some specific value. We cannot delete this if condition like before because we need values of q and s to calculate the flag.

In function onSendMessageIn function onSendMessage

It’s only after successfully sending both questions, the values for q and s are set. So it is necessary to send both messages.

So that’s my solution for this CTF. This was my first ever CTF and learned a lot during this challenge. Hope you also learned something.

Thanks for reading my write-up! Cheers! 🍺

Follow me on Twitter, Github or connect on LinkedIn.