Android MX Player — Path Traversal to Code Execution

David Wells
Tenable TechBlog
Published in
5 min readJul 9, 2020

MX Player is an Android App that you can find on the Google Play Store, having over 500M downloads.

While this is a video player app, we won’t be attacking it with malformed video files. Instead I attacked the video sharing feature it had. This video sharing feature is a direct phone-to-phone file sharing feature which had a path traversal vulnerability in it (CVE-2020–5764). I will show how I found it and how we ended up gaining code execution (for certain devices) with it. Fortunately, since we disclosed it to the developers, this issue has been patched in v1.24.5, so if you are a MX Player user, its highly recommended to update to this version or higher.

MX Player Sender/Receiver Relationship

MX Player transfers video files between two phones by setting one of the phones (“receiver”) into hotspot mode, while the other phone (“sender”) authenticates via shared password and sends the video over this connection. The video will then be saved to the receiver’s “/sdcard/MxShare” directory.

Before I get into the vulnerability, there is one issue I saw with this password implementation. When the receiver puts their phone in “Hotspot” mode, the password for this Hotspot is base64 encoded and broadcasted publicly as a discoverable bluetooth device.

This means if an attacker is within the receiver’s bluetooth range, the password to the phone’s Hotspot can be compromised, and the following issues I go over were also open to nearby unauthenticated attackers.

Exploiting the Media Sharing Protocol

The protocol features various commands along the transfer process. One of these commands tells the app the file name to save the incoming file as.

If we reverse engineer the app’s code, we find the part where this app processes the sharing protocol. In it we see the command that is responsible for processing the file name is “FILE_LIST” (outlined above), and when this message is received through the transfer protocol, parameters are taken which tell the app how to save the file. An expected message would look something like this:

‘mx\x00\x01\x00\x02\x00\x00\x00\xb5{“hash”:”FA730A013D17D705CAF504B5CA560501",”id”:0,”name”:”cool_video”,”suffix”:”mp4",”size”:5976,”type”:0}

The “\x01” after the “mx” header is the FILE_LIST command, and the following JSON text contains a field called “name”. When the message is received during an MX Player transfer session, it will simply take the name and concatenate it against a hardcoded path of “/sdcard/MXShare/”.

You might be able to see the issue here, which is the ability to do path traversal if the file name passed under this protocol message is “../../traversedFile”.

So sending a message like:

s.sendall(b’mx\x00\x01\x00\x02\x00\x00\x00\xb5{“hash”:”FA730A013D17D705CAF504B5CA560501",”id”:0,”name”:”../cool_video”,”suffix”:”mp4",”size”:5976,”type”:0}

Will result in the video being saved outside of the “/sdcard/MXShare” path, and directly to the sdcard root directory.

Gaining Code Execution

I hit a bit of a snag trying to gain code execution through this. Initially I thought to traverse all the way to “/data/data/com.mxtech.videoplayer.ad/” (the application install directory which we can write to) and overwrite some .dex file (executable android code) to gain execution. Unfortunately, this particular write could not write over existing files…only create new ones. So to find how to gain RCE here, we need to search for files that do not exist, but ones that if we create…can gain code execution…does such a thing even exist??

For this, I ran “strace” on the phone, to attempt to find any non-existent files that the app tries to read from. I found a couple, but the most interesting one was “audience_network.odex” and “audience_network.vdex”. In this case, I need to capture file i/o upon the start of this app, so I ran the following command for this:

am start -n com.mxtech.videoplayer.ad/com.mxtech.videoplayer.ad.ActivityWelcomeMX && ps -A | grep [m]x -m 1 | tr -s ‘ ‘ | cut -d ‘ ‘ -f2 | xargs strace -f -p 2>&1

After executing this, I discovered a few files that the app tried to open, but didn’t exist. The most interesting one was “files/audience_network.dex”. Below, I specifically grepped for “audience_network” and saw a few files with that name.

These are part of the FBaudiencenetwork dex file that the app dynamically loads at runtime, which appears to be some kind of Facebook AD Sdk for app developers to use https://developers.facebook.com/docs/audience-network. In android, “.dex” files can be optimized as “.odex” files, which are native modules of compiled dex code using AOT (Ahead of time Compilation https://source.android.com/devices/tech/dalvik/configure). ART runtime (libart.so) will try to load and run one if it sees it exists in “<appPath>”/files/oat/<arch>/*.odex”. In my testing with Pixel 3a (factory reset) and my personally owned Pixel 3 XL (both Android 10), these optimized files did not seem to exist by default after installing the app, which meant they were vulnerable to this attack.

Like I mentioned previously, odex is native code. In certain scenarios, libart will just load it as a shared object using a dlopen call (https://android.googlesource.com/platform/art/+/master/runtime/oat_file.cc#1104). In this scenario, it really is as easy as compiling a shared object targeting the phone’s architecture, renaming it to “audience_network.odex” (and also dropping an empty “audience_network.vdex” file) for code execution to occur the next time the app is run again.

Exploitation

With user in “receive” mode, an attacker can connect to the remote phone and interact with the MX Transfer protocol (as seen in PoC) to drop an executable .odex file in /data/data/com.mxtech.videoplayer.ad/files/oat/<arch>/audience_network.odex (as well as .vdex). The MX Transfer protocol can support multiple files being sent in one transfer session, so creating a FILE_LIST message as seen below, will properly drop both these files in the paths for execution upon next time the app is run.

s.sendall(b’mx\x00\x01\x00\x02\x00\x00\x00\xb5{“hash”:”FA730A013D17D705CAF504B5CA560501",”id”:0,”name”:”../../../../../data/data/com.mxtech.videoplayer.ad/files/oat/arm64/audience_network.odex”,”suffix”:””,”size”:5976,”type”:0}\x00\x00\x00\xb2{“hash”:”BAF54A9DAD144105C1FF04B4E90FC901",”id”:1,”name”:”../../../../../data/data/com.mxtech.videoplayer.ad/files/oat/arm64/audience_network.vdex”,”suffix”:””,”size”:2,”type”:0}’)

v1.24.5 Patch

During disclosure with MX Player, we received very little vendor communication on patch progress and updates. During our occasional testing of versions, we discovered that the path traversal issue was fixed in the v1.24.5 release.

--

--