5 minutes
Android CTF - CyberTruck Challenge 2019
CyberTruck Challenge 2019 is a premier event to bring together a community of interest related to heavy vehicle cybersecurity issued and develop talent to address those challenges. This is a write up for their CTF. Their website can be found here and the Github profile for the challenge can found here.
Note: This was originally written on Medium and has been converted to markdown using mediumexporter
Note: I was not present during the event. All I wanted to do was practice Android CTFs and that’s when I came across their Github page.
Tools used
Challenge description
A new mobile remote keyless system “CyberTruck” has been implemented by one of the most well-known car security companies “NowSecure Mobile Vehicles”. The car security company has ensured that the system is entirely uncrackable and therefore attackers will not be able to recover secrets within the mobile application.
If you are an experienced Android reverser, then enable the tamperproof button to harden the application before unlocking your cars. Your goal will consist on recovering up to 6 secrets in the application.
Preparing for the CTF
Installing the app
Using adb to install the app on the phone.
adb install cybertruck19.apk
Decoding the app using ApkTool
Decode the APK using Apktool and output it into cybertruck-smali folder.
apktool d cybertruck19.apk -o cybertruck-smali
Converting the apk in .jar format using dex2jar
I converted the .apk to jar because then I can use JD-GUI to see Java source code.
Note: I downloaded dex2jar and create a tools directory so all my tools are easily accessible
Using JD-GUI, we open the cybertruck.jar created by the dex2jar (previous command).
Note: I downloaded jd-gui and create a tools directory so all my tools are easily accessible
Launching the app
As soon as we launch the app, we get this image.
So we try to understand what the unlock button and toggle buttons do.
Challenge #1
Challenge1 to unlock car1. “DES key: Completely Keyless. Completely safe”
To figure out what activity is being launched, let’s take a look at AndroidManifest.xml
AndroidManifest.xml file is under cybertruck-smali directory (created by apktool)
MainActivity is the activity that is being launched first
So, using JD-GUI to take a look at the source code of MainActivity.class
Note: I downloaded jd-gui jar file inside tools directory and launch using java
Looking at the onCreate function, we find the Unlock button. On clicking the unlock button, it calls this.b.k() . So we further investigate.
Snapshot of function k
The function creates an instance of class Challenge1. So we take a look at Challenge1.class
Static Flag for challenge1 is s3cr3t$_n3veR_mUst_bE_h4rdc0d3d_m4t3!
For dynamic flag, we will have to find a way to get the value returned by generateDynamicKey function in the runtime. These are exactly the scenario where Frida comes in handy. You can learn more about Frida from their official documentation.
generateDynamicKey returns a byte array. The byte array is stored in variable result which we forward it python function on_message. Here we convert byte array to string.
Capturing Dynamic flag
First we run frida-server on the android device. Then we use the flag-capture.py, to capture the dynamic flag
The dynamic flag is 046e04ff67535d25dfea022033fcaaf23606b95a5c07a8c6
Challenge #2
Challenge2 to unlock car2: “AES key: Your Cell Mobile Is Your Key”
Going through the this.b.k()
function in MainActivity.class
Instance of class a is called. Let’s investigate further.
So we have class a with constructor a and two functions with name a.
While declaring constructors, you do not have specify the return value. So public a(Context paramContext) is the constructor and the rest are functions.
So this file contains:
Constructor
Function that takes one argument and returns byte array
Function that takes two arguments and return byte array
Anyways, coming back to constructor a, it calls a(Context paramContext) and then its returned value is then passed as one of the arguments in a(byte[] paramArrayOfbyte1, byte[] paramArrayOfbyte2)
So we take a look at function a(Context paramContext)
File ch2.key is opened. So we take a look at its contents.
The value of static flag for Challenge2 is d474_47_r357_mu57_pR073C73D700!!
Now let’s take look at function a(byte[] paramArrayOfbyte1, byte[] paramArrayOfbyte2)
For dynamic flag, we will need to use Frida again to capture the returned value of this function
After appending the above snippet to js_code, we rerun the flag-capture.py
The dynamic flag for Challenge2 is 512100f7cc50c76906d23181aff63f0d642b3d947f75d360b6b15447540e4f16
Challenge #3
Challenge3 to unlock car3. “Mr Truck: Unlock me Baby!”
Challenge3 description: There is an interesting string in the native code. Can you catch it?
Inside MainActivity.class, this native-lib.so is loaded.
We first locate this file and then use strings to print all the strings in the file
The static flag for this challenge is Native_c0d3_1s_h4rd3r_To_r3vers3
For dynamic flag, it depends upon on your device’s instruction set. In my case, it was arm64-v8a which requires you to be able to understand assembly language instructions for the same. Which seems to be out of my league (..yet!).
How to bypass Tamperproof check?
This function checks if there is a frida server in this device
This function returns true if there is frida server is present and false otherwise. So we use Frida to overwrite this function’s return value
So that’s my solution for this CTF. I am still new to CTFs and have a lot to learn yet. Still this CTF was a good learning opportunity. Hope you also learned something.
Thanks for reading my write-up! Cheers! 🍺