Exploiting CVE-2016-2060 on Qualcomm Devices

Mandiant’s Red Team recently discovered a widespread vulnerability
affecting Android devices that permits local privilege escalation to
the built-in user “radio”, making it so an attacker can potentially
perform activities such as viewing the victim’s SMS database and phone
history. The vulnerability exists in a software package maintained by
Qualcomm that is available from the Code Aurora Forum. It is published
as CVE-2016-2060 and security advisory QCIR-2016-00001-1 on the Code
Aurora Forum. We have provided general details in an FAQ, and a
technical analysis of the vulnerability follows.

FAQ

What is CVE-2016-2060?

CVE-2016-2060 is a lack of input sanitization of the
"interface" parameter of the "netd" daemon, a
daemon that is part of the Android Open Source Project (AOSP). The
vulnerability was introduced when Qualcomm provided new APIs as part
of the "network_manager" system service, and subsequently
the "netd" daemon, that allow additional tethering
capabilities, possibly among other things. Qualcomm had modified the
"netd" daemon.

How many devices are affected?

There is no solid answer. Since many flagship and non-flagship
devices use Qualcomm chips and/or Qualcomm code, it is possible that
hundreds of models are affected across the last five years. To provide
some API numbers, Android Gingerbread (2.3.x) was released in 2011.
This vulnerability was confirmed on devices running Lollipop (5.0),
KitKat (4.4), and Jellybean MR2 (4.3), and the Git commit referenced
in the post is Ice Cream Sandwich MR1 (4.0.3).

How is the issue being addressed?

Qualcomm has addressed the issue by patching the "netd"
daemon. Qualcomm notified their customers (all of the OEMs) in early
March 2016. The OEMs will now need to provide updates for their
devices; however, many devices will likely never be patched.

FireEye reached out to Qualcomm in January 2016 and subsequently
worked with the Qualcomm Product Security Team to coordinate this blog
release and security advisory. When contacted by FireEye, Qualcomm was
extremely responsive throughout the entire process. They fixed the
issue within 90 days – a window they set, not FireEye. FireEye would
like to thank Qualcomm for their cooperation throughout the disclosure
and diligence with addressing the issues.

Google has included this issue in its May 2016 Android Security Bulletin.

How would an attacker exploit this vulnerability?

There are two ways to exploit this vulnerability, though this does
not account for a determined attacker who possesses additional
vulnerabilities. The first is to have physical access to an unlocked
device, and the second is to have a user install a malicious
application on the device.

Any application could interact with this API without triggering any
alerts. Google Play will likely not flag it as malicious, and FireEye
Mobile Threat Prevention (MTP) did not initially detect it. It’s hard
to believe that any antivirus would flag this threat. Additionally,
the permission required to perform this is requested by millions of
applications, so it wouldn’t tip the user off that something is wrong.

What could an attacker do if they successfully exploit this vulnerability?

On older devices, the malicious application can extract the SMS
database and phone call database, access the Internet, and perform any
other capabilities allowed by the "radio" user. Some
examples of potential capabilities of the "radio" user are
presented in the blog itself, though it was difficult for all of these
to be tested.

Newer devices are affected less. The malicious application can
modify additional system properties maintained by the operating
system. The impact here depends entirely on how the OEM is using the
system property subsystem.

It should be noted that once the vulnerability is exploited, there
is no indication to the user that something has happened. For example,
there is no performance impact or risk of crashing the device.

Are only Android devices affected?

Since this is an open-source software package developed and made
freely available by Qualcomm, people are using the code for a variety
of projects, including Cyanogenmod (a fork of Android). The vulnerable
APIs have been observed
in a Git repository from 2011
, indicating that someone was using
this code at that time. This will make it particularly difficult to
patch all affected devices, if not impossible.

Is this vulnerability being actively targeted or exploited?

No. The MTP team is monitoring usage of this API, but has not
discovered anything.

Are FireEye customers protected?

FireEye MTP customers will be able to detect attempted exploitation
of this vulnerability.

Technical Analysis

Next we will dive more deeply into CVE-2016-2060 and demonstrate how
an attacker can exploit the vulnerability, but first an introduction
to Android system services.

Understanding System Services

A system service is similar to a regular
bound service
found in an Android application, but a system
service typically runs in a privileged process, such as the
“mediaserver” or “system_server”. These services are the core of
Android, and there are currently 99 system services registered on a
default emulator build for Android Marshmallow. When USB debugging is
enabled on a device, the `service` utility can be used to list system
services registered on the device, shown in Figure 1.

Figure 1: Listing system services using
‘service’ utility

To illustrate how system services play a role on Android devices, we
walk through the process of sending a text message (SMS) from an
Android application. Figure 2 shows a Java snippet that can be used to
send an SMS message with the content of “Test” to the number 1234567890:

        SmsManager smsManager = SmsManager.getDefault();

       
smsManager.sendTextMessage(“1234567890”, null, “Test”, null, null);

Figure 2: Sending an SMS message from an
application (from StackOverflow)

The code first obtains the SmsManager object associated with the
default subscription ID using the static method “getDefault()”, and
then calls the method “sendTextMessage(..)” with the appropriate
arguments. The SmsManager
class
contains other SMS-related methods such as
“downloadMultimediaMessage(..)” and “sendMultipartTextMessage(..)”.

Next, we’ll look at the Java
source
for the “sendTextMessage(..)” method of the SmsManager
class used previously. For simplicity, we view the source for the
SmsManager class included as part of Android 4.4 (“KitKat”), shown in
Figure 3.

Figure 3: Java source of “sendTextMessage(..)” method

This method performs two functions: it first performs basic argument
checking and then attempts to interact with a system service called
“isms”. The “getService(..)” method of the ServiceManager class is
used to obtain an IBinder object, which is then cast to an ISms object
by using the “asInterface(..)” method. At this point, methods can be
called from the “isms” system service using the Binder interface, which
in this case is the method “sendText(..)”. Note that use of the
ServiceManager class is not available to application developers using
the Android SDK. This indicates that the SmsManager class is merely a
wrapper for the “isms” system service, and this particular pattern is
consistent across many other APIs such as location and telephony.

Calling System Services Directly

While Google does not recommend bypassing their official APIs to
interact with a system service directly, it is possible to do so. To
do this in an application, a developer has to import and use
non-standard APIs (namely the aforementioned ServiceManager class). As
an alternative, the `service` utility mentioned earlier can be used
from the command line. In order to utilize the `service` utility, we
need to gather additional pieces of information: the transaction ID of
the method we would like to call and information regarding the arguments.

Obtaining a Transaction ID

When creating a bound Service in an Android application, the first
step is to define the service interface using the Android
Interface Definition Language (AIDL)
. When an AIDL file is
compiled by the `aidl` utility during the application build process, a
unique identifier is stored for each method of the interface in the
form of a static field of the “Stub” inner-class. Developers rely on
the method names and not these transaction IDs, as they will change
between API builds and across vendors.

To illustrate this for the previous SMS example, we investigate the
class “com.android.internal.telephony.Isms.Stub”, which is typically
found on a device in the system JAR file
“/system/framework/framework.jar”. By disassembling this JAR, we can
determine the transaction ID for the method “sendText()”, which is 0xb
hexadecimal or 11 decimal on this device, shown in Figure 4.

Figure 4: Obtaining the transaction ID of the
“sendText(..)” method

Determining Method Arguments

Now that we understand the transaction ID, we need to determine how
to interact with the method. If the system service of interest is
public like the “isms” service, the AIDL
source can be reviewed
. If it is not, the service implementation
needs to be reversed in order to determine the purpose of each
argument. If we dissemble the inner-class
“com.android.internal.telephony.Isms.Stub.Proxy” included in
aforementioned “framework.jar”, we should be able to get an idea of
what each of the augments represent and determine the return type.
Figure 5 shows the arguments and return value for the “sendText(..)” method.

Figure 5: Method prototype of “sendText(..)” method

In the screenshot above we see that the “sendText(..)” method takes
six arguments, denoted by the “pn” notation, and returns a
void, as denoted by the trailing “V” in method prototype.

Putting it All Together

Now we can use the `service` utility to interact with the “isms”
service and call the “sendText(..)” method. Figure 6 shows the syntax
for the `service` utility to call a system service’s method.

    service call service_name transaction_id [arguments]

Figure 6: ‘service

utility syntax to call service method

The ‘service’ utility accepts string, integer, and null value
arguments, represented by “s16”, “i32”, and “null”, respectively. Note
that for anything more complex, a Java application must be used. We
can now call the “sendText(..)” method, which has the transaction ID
of 11, of the “isms” system service to send a message, shown in Figure 7.

    adb shell service call isms 11 s16
"com.fake" s16 "1234567890" s16
"1234567890" s16 "Test" i32 0 i32 0

Figure 7: Invoking “sendText(..)” using
‘service’ utility

This command shown sends an SMS message with the content of “Test”
to the number 1234567890, similar to the Java snippet in Figure 2.

Exploring CVE-2016-2060

Starting from the Top

Device manufactures and other non-Android Open Source Project (AOSP)
vendors add and modify system services on a regular basis. From an
attacker’s perspective, new or changed APIs in system services are a
prime target. A researcher can enumerate these by comparing the static
fields beginning with “TRANSACTION_” found within the “Stub”
inner-class of system services on a target device to that of the AOSP.
During one such review, we discovered two methods added to the
“network_management” system service called
“addUpstreamV6Interface(..)” and “removeUpstreamV6Interface(..)”,
found in “android.os.INetworkManagementService.Stub”, which is part of
the system JAR “/system/framework/framework.jar”. This is depicted in
Figure 8 and Figure 9.

Figure 8: “addUpstreamV6Interface(..)”
transaction ID 0x1e (30)

Figure 9: “removeUpstreamV6Interface(..)”
transaction ID 0x1f (31)

The “addUpstreamV6Interface(..)” method accepts a single string
argument, interface_value, and returns void. Viewing the disassembled
method “addUpstreamV6Interface(..)” of the class
“com.android.server.NetworkManagementService” found in the system JAR
“/system/framework/services.jar” indicated that when called, the
method passed interface_value to the native daemon “netd” by writing
the string shown in Figure 10 to the UNIX socket “/dev/socket/netd”.

    tether interface add_upstream interface_value

Figure 10: Command sent to “netd” native daemon

From here, analysis of the “/system/bin/netd” indicated that this
daemon executed “/system/bin/radish” using the “execv(..)” function
which executes the shell command depicted in Figure 11.

    /system/bin/radish –i interface_value –x -t

Figure 11: Arguments passed to “/system/bin/radish”

The “/system/bin/radish” executable then passed the interface_value
to the `brctl` utility using the “system(..)” function, using the
syntax depicted in Figure 12.

    brctl addif bridge0 interface_value

Figure 12: interface_value present in `brctl` command

It is at this point we witness the code execution capabilities of
CVE-2016-2060: any value passed to the “addUpstreamV6Interface(..)” is
ultimately passed to the “system()” function without being sanitized
or validated. A trivial example of this can be achieved with the
`service` command shown in Figure 13, which prints the output of the
`id` command to the Android log buffers:

    adb shell ‘service call network_management 30
s16 ‘\”fake; log -t radio_exe "`id`"’\”’

Figure 13: ‘service’ command to write the output
of ‘id’ to Android log buffers

This command passes the interface_value of ‘\”fake; log -t
radio_exe "`id`"’\”’ to the “/system/bin/radish”
executable, which calls the “system()” function with the string shown
in Figure 14.

    brctl addif bridge0 fake; log -t radio_exe "`id`"

Figure 14: Command injection into `brctl`
“system()” function

We can check the Android log buffers to capture the output of our
injected commands using the `logcat`
utility
, shown in Figure 15.

Figure 15: Output of ‘id’ captured in the
Android log buffers

The output of the `id` command indicates that we are running as the
Linux UID 1001 (“radio”) and under the SEAndroid context of “netd”.
Next, we explore how an attacker would take advantage of this
vulnerability and what actions this permits the attacker.

Practical Exploitation

The most feasible way of exploiting CVE-2016-2060 is by creating a
malicious application. A malicious application needs only to request
access to the “ACCESS_NETWORK_STATE”
permission, a widely requested permission. Figure 16 shows how the
“addUpstreamV6Interface(..)” method can be used to inject the command ‘id’.

Figure 16: Malicious application calling “addUpstreamV6Interface(..)”

Since the commands above are executed as the user “radio”, data
owned by applications that are also running as “radio” are accessible
to the malicious application. On stock Android devices, this includes
the Phone
application
and the Telephony
Providers application
, both of which contain sensitive
information. The “radio” user also inherits several system permissions
not accessible to a third-party application. A short list includes:

  • WRITE_SETTINGS_SECURE – Change key system settings
  • BLUETOOTH_ADMIN – Discover and pair with Bluetooth devices
  • WRITE_APN_SETTINGS – Change APN settings
  • DISABLE_KEYGUARD – Disable the key guard (lock screen)

Whether or not an attacker can abuse these permissions depends on
the specific model, and may not be possible across all devices.

SEAndroid Considerations

Beginning in Android 4.4 (“KitKat”), devices utilize Security
Enhancements for Android™ (SEAndroid) and set enforcing mode by
default. Devices running SEAndroid in this mode are not impacted as
significantly as older devices. The “netd”
context
that the “/system/bin/radish” executable runs as does not
have the ability to interact with other “radio” user application data,
has limited filesystem write capabilities and is typically limited in
terms of application interactions. The “netd” context does have the
ability to alter “system_prop” properties of the Android property
subsystem, which includes the “service.”, “persist.sys.”,
“persist.service.”, and “persist.security.” property keys. Depending
on how a particular device manufacture utilizes these properties, it
is possible to further compromise a device by altering these properties.

Conclusions

CVE-2016-2060 has been present on devices since at least 2011 and
likely affects hundreds of Android models around the world. This
vulnerability allows a seemingly benign application to access
sensitive user data including SMS and call history and the ability to
perform potentially sensitive actions such as changing system settings
or disabling the lock screen. Devices running Android 4.3 (“Jellybean
MR2”) or older are the most affected by the vulnerability, and are
likely to remain unpatched. Newer devices utilizing SEAndroid are
still affected, but to a lesser extent.

FireEye would like to thank Qualcomm for both working diligently to
address CVE-2016-2060 and for supporting the release of this blog
post. For FireEye Mobile Threat Prevention (MTP) customers, FireEye
has added detection of CVE-2016-2060 exploitation on devices as of
writing this blog post.

This is a Security Bloggers Network syndicated blog post authored by Nick Harbour. Read the original post at: Threat Research Blog