Planet-X is an intermediate level Android application CTF challenge. The aim of this CTF challenge is to learn and concentrate on the basic flaws which are found while performing security assessment of a mobile application.
We will be observing the basic misconfigurations which will lead our path and help us to find the flag.
Let’s take a minute to thank Moksh for creating this challenge. If someone wants to try and solve the challenge before going through the walkthrough, the link for the CTF can be found [here] and the application can be downloaded from [here].
So, before beginning the walkthrough, highlighting the fact that the challenge can be solved in two different ways. Both the ways teach us something unique and make us aware about the security flaws.
Just stay connected till the end…
First Approach is basically the intended way how the challenge was designed to be solved.
Tools Used :
adb : command line tool that lets you communicate with device
apktool : command line tool for reverse engineering android applications
jadx-gui : tool for producing Java source code from Android Dex and APK files
Android Studio : official Integrated Development Environment (IDE) for Android app development
Device : Android Device/Android Studio Emulator/Genymotion Emulator
Connecting the device with a USB cable and entering command for checking proper connectivity.
The above command will list down all the connected devices/emulators.
Note : Make sure to connect the android phone with debugging mode enabled for initiating the application installation process.
After downloading the application from the above given link, the application can be installed in device/emulator by a very simple command.
adb install <apk-name>
We can run the application in the device/emulator
So the first page indicates that the application needs a 4 digit pin.
Hey ! Why don’t we brute force the pin? It’s just a 4 digit pin!
Let’s begin.. Just trying “1111”
The message says “Incorrect Pin, 2 attempts remaining”
That means we have only 3 attempts to break the pin. Because after that..
The message says “Attempts made! Wait for 30 seconds..”
So, this loop will continue i.e trying 3 wrong attempts and then waiting for 30 seconds for giving a next attempt which means we cannot bruteforce the PIN.
So, we need to find a way out of it. Let’s try reverse engineering the application…
As we have jadx-gui in our bucket. We opened the APK using jadx-gui so that we can read the source code of the application.
Now start reading the code from MainActivity.java
So, here we can see there is an instance of SQLiteDatabase.
Let’s read some more code…
From the above highlighted code we can see that two databases are being created named as
Grab a chair for next couple of points…
- one table created as ‘name’
- table ‘name’ has two columns → (user VARCHAR, pass VARCHAR)
- values stored for (user,pass) → (VALUES(‘moksh’,’password’))
Declaration of function a()
- one table created as ‘a’
- table name has two columns (z VARCHAR,a VARCHAR))
- values stored for (z,a) are random, which is generated by a random number generator function.
So let’s grab the databases for our next hint…
Here we can see.. We have two databases kkk.db and q.db
Let’s pull the database from the device
adb pull /data/data/com.moksh.lab1/databases/
Now try reading them using sqlitebrowser using a very simple command
While trying to open them using sqlitebrowser, facing an error…
The alert message box says
“Could not open database file. Reason : file not a database”
That’s a strange behaviour, because a .db file is a database file.
Let’s check the source code file once again…
See ! What we got. The application loads a SQLiteDatabase native library.
Here, we can see that the application has SQLiteDatabase class in net.sqlcipher.database package and they have used native library System.loadLibrary(“sqlcipher”) for encrypting the database.
So, it means the database is encrypted and we need to decrypt it now…
Now we can use sqlcipher commands for decrypting the database. But before that we need to install sqlcipher in our system.
A very simple basic command can be used to install sqlcipher in our system.
sudo apt-get install -y sqlcipher
After installing sqlcipher, we can go ahead and follow the below mentioned commands for decrypting the database.
Let’s simplify each command one by one.
sqlite> PRAGMA key = ‘123456’;
PRAGMA Key : Whenever a new encrypted database is created, we first need to create a key which is called “keying” the database. SQLCipher uses just-in-time key derivation at the point it.
Note : For pulling the database you either need a rooted device of the back up needs to be enabled and then pulling the data by ca is first needed for an operation. This means that the key must be set before the first operation on the database.
From the source code we can see that the key is “123456”
sqlite> ATTACH DATABASE ‘plaintext.db’ AS plaintext KEY ‘’;
The above command indicates that a new database plaintext.db is being created with an empty key and attach to the present database i.e q.db
sqlite> SELECT sqlcipher_export(‘plaintext’);
The above command explains that the plaintext database has been created and all the data of q.db is being exported to plaintext.db
sqlite> DETACH DATABASE plaintext;
The above command explains that the plaintext.db is being detached from the encrypted database q.db. Now plaintext.db is a separate entity and we can now read the database in plaintext from plaintext.db
Now running the most common and famous SQL command.
sqlite> SELECT * FROM a;
The results come up with two different numbers. We can simply enumerate the numbers and find the exact pin.
We can also see the output in sqlitebrowser for our ease now.
Now entering the pin “4656”
and the flag is…
Yes Morty ! You finally did it !
Let’s talk about the second approach to solve the challenge.
The second approach requires some knowledge of coding and reading the reverse engineered code. A bit of more manual efforts will be required for solving the challenge.
Just stay connected!
So, while traversing and reading the reverse engineered code, we encountered an eye catching statement for key.
So, here we can see the statement
Right Pin, Congratulations
and below that there is a key i.e google_api_key being called.
String string = MainActivity.this.getResources().getString(R.string.google_api_key);
We can find the value of google_api_key in “/res/values/strings.xml”
and an another eye catching statement in MainActivity.java
This clearly indicates that the function ja.c(b, b) plays the game.
Let’s trace back the code…
While reverse engineering and tracing the code down, we can see the five functions are being called in sequence with the string value of google_api_key.
- public static String a(String str)
- public static String a(String str, String str2)
- private static String b(String str)
- public static String b(String str, String str2)
- public static String c(String str, String str2)
Lets understand the flow like this…
String string = google_api_key;
String a2 = ja.a(ja.a(string, string.substring(4))); → ja.a(string, string.substring(4))
String b = ja.b(a2.substring(1), a2); → a2.substring(1), a2
String Flag = ja.c(b, b)
Replicating the complete code in Android studio..
Let’s watch out the logcat for the FLAG..
Yes Morty ! Finally you did it again.
So, for this way you don’t need any rooted device to extract the database and find out the pin.
As the pin was random and getting created at run time but the flag was static.
Learned how to reverse engineer android application
Learned how to read the application source code
Decrypted a sqlcipher encrypted database
Harm caused by hard coding keys
Patience is the key