Security Analysis of Care Together Application (Myanmar Contact Tracing App)
UPDATE: The developer team said they have already released an update which include the server-side encryption for the phone number.
Since the beginning of COVID-19 outbreak in Myanmar, there are a handful of mobile apps and websites developed to help the people with technology. You can see a curated list of those in this GitHub repo.
https://github.com/nyanlynntherazi/awesome-myanmar-covid19-resources
One mobile app stands out for me. It’s a contact tracing app named Care Together developed by Za Information Technology. Their FAQs states they are inspired by Trace Together app developed by Singapore GovTech. Since by the nature of how they operate, Contact Tracing applications are of a great privacy concern, I searched for their privacy policy and found this.
I was curious about the claims made by No . 1, 3, and 5, which basically said the data stored in the app is encrypted and the developer made sure no one will be able to access it. So, I decided to look inside the app and figured out how the encryption works.
- I used jadx to decompile the app and get the decompiled java source code. The code is obfuscated using Proguard, which is a good practice.
- As I looked up the sign up session, I can see the app is not encrypting the phone number I used to sign up before storing it in SharedPreferences, which is a first red flag.
- Another interesting place is where the bluetooth data exchange happens. So, I search for Bluetooth in the app and found a file name called BluetoothService.java.
One place to look for is onReceive clause where the app need to handle the data it gets from other phones via bluetooth.
I can see the app receive data from a parcelable and get the current date time and bluetooth device name. But the most interesting thing is there’s a hardcoded weird looking String.
I searched for variable r13 and found that it’s used in two places.
Both of the methods are from the class C0422c so I opened the class and sure enough, it’s where the encryption happens.
The code is a simple AES encryption/decryption. As you can see, the weird looking string is actually the key, and since its’ length is 32 characters long, we can assume AES 256 is used. The encryption also uses IV param which is also generated from the same key, using the substring(0,16).
- Since I found the key and figured out how the encryption works, I tried to actually take the database and decrypt it. I installed the app in two of my phones and gave all permissions.
I check the first phone and I can see a csv filed called AnalysisData.csv file is generated.
If you take a look at the csv file, you can see all the datas are encrypted.
Let’s try to use the key and IV we got to decrypt the db.
After all the decryptions, the csv file looks like this.
Conclusion
So, what all this means? This means that I can install the CareTogether Application, go around the town and get all the phone number and lat/long of all the peoples who happen to install the CareTogether application too, which is a big big security flaw and should never be in a production application. I contacted the developer team and reported about this security flaw. I advised encrypting the phone number on server side during sign up and only storing the encrypted string inside the app. They responded by saying there’ll be an update addressing this issue.
Update:
The developer team contacted me and said they have fixed the issue. I deep dive into the app to check whether the issue is already fixed. Decompiling the app show
So, the key is now inside the method getNativeKey() and it can’t be more obvious that this will be stored in a native library? (C/C++)
Searching the method name getNativeKey() leave me with this.
I looked at the app’s libs folder and can see the native lib. We’ll decompile the native-lib2.so
Let’s decompile the native code.
I will use radare2 for decompiling native library. Using radare2’s rabin2 command, I loaded .so file and search for Java
keyword, since all native methods called from Java will include it. We can clearly see there’s a method called getNativeKey here.
The method memory address is 0x000079b0
Using radare2 commands, we can actually get the string we’re looking for.
Let’s explain the commands:
e emu.str=true;
enables radare2's string emulation. Thanks to this, we can see the string we're looking for
s 0x000079b0
is a seek to the address s 0x000079b0
, where our target function is located. We do this so that the following commands apply to this address.
pdf
means print disassembly of function.
There we can get the actual key and proceed to decrypt the whole database again and it took me 15 minutes to get this. To make the matter worse, it’s the same key they are using previously!
I would strongly recommend the developers to use server-side encryption as in current state, this app has a big vulnerability and by the nature of this kind of application, has a serious privacy breach.