DID YOU KNOW? By 2016, 20% of enterprise BYOD programs will fail due to deployment of mobile device management (MDM) measures that are too restrictive.

Recently, I came across a bug in Android’s Device Administrator code and questioning whether it can be classified as a security vulnerability and if/how it can be exploited. This resulted in the CVE-2014-0900. Below (as promised in my OBAD analysis blog entry), I will share the vulnerability in Android OS code and describe how it can be exploited to give a false sense of control and authority to an affected MDM Android app.

What this means is that the MDM app on your Android device would have a false sense that it can wipe data, lock the device, enforce password quality policies and so on and will therefore let you access corporate email, data or intranet resources while in reality it would have no such control and you can continue to use your device without any of the corporate restrictions. We know you did not like to type those long passwords and would rather have no password and no lock screen. After all, don’t you want to share your personal data with everyone?

I have verified that two commercially used MDM solutions are affected by this. It is very likely that most MDM apps (if not all) are affected, too. Below, I will share the vulnerability and exploitation details. If you are not interested in technical details, you can jump to the end to read about the mitigation possibilities and lessons learned from this that will help you in your BYOD strategy as a solutions provider and as a buyer. If you are responsible for developing an MDM app, we recommend that you take a look under the section titled Mitigation to determine whether your product is affected by this and how to mitigate the risk.

Disclaimer: For your personal safety and job security, we strongly discourage trying this on your BYOD-approved device.

 

The Details

The vulnerability exists in private void handlePackagesChanged(int userHandle) methods of com.android.server.DevicePolicyManagerService for versions below android-4.4.1_r1.

DevicePolicyManagerService class maintains two data structures to track the active device admins on a device:

final HashMap mAdminMap = new HashMap(); final ArrayList mAdminList = new ArrayList();

However, in handlePackagesChanged mAdminList is updated, but mAdminMap is not updated to remove the admin from the hash map.

private void handlePackagesChanged(int userHandle) { ... for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { ActiveAdmin aa = policy.mAdminList.get(i); try { if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) { removed = true; policy.mAdminList.remove(i); }

Interesting. Let’s see where in code mAdminMap is consulted but mAdminList is not. We find that getActiveAdminUncheckedLocked and getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) with “who” parameter being non null relies on mAdminMap only, and getActiveAdminUncheckedLocked is used by isAdminActive of android.app.admin.DevicePolicyManager. So an MDM app that uses this isAdminActive method to check whether its DeviceAdministrator is active can potentially be deceived. Here is how:

To demonstrate this, we will use Lookout’s free anti-virus as an example. Note that this is just for demonstration purposes since this is what I had on my phone. This is a benign bypass for demonstration/verification only, and this app is different from the commercial MDM solution from Lookout. The idea is that AV apps typically have features for extra protection (such as remote wiping of a device) if you allow them to enable their Device Administrator component. The AV app would check whether its device administrator is enabled and would show status on their dashboard. We will demonstrate how you can trick it into getting this wrong.

Step 1

The first step is to get hold of the apk package for Lookout anti-virus (hint: install on your phone, and get the apk using adb pull) and to extract the AndroidManifest.xml file. If you are not familiar with how to do this, you can find some hints in my earlier post, DIY: Android Malware Analysis – Taking Apart OBAD . Look at the AndroidManifest.xml file, and take note of two things: The package name for the app and the name of the DeviceAdministrator component. You can read up on the previously linked reference about DeviceAdministrator to learn how to create your own DeviceAdministrator.

Go ahead and create an Android project with the same package name and same name for the DeviceAdministrator component as the one you are trying to deceive. The special thing you need to do with your DeviceAdministrator is to execute the following code once it is enabled as a device administrator on the device:

pm.setComponentEnabledSetting(this.getWho(context), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

I added this in the onEnabled method of my DeviceAdministrator. What this will do is disable my DeviceAdministrator component after it has been given the rights of a DeviceAdministrator, resulting in the vulnerable code in handlePackagesChanged (mentioned above) being executed. Note that, after this, my device administrator component will still be in the mAdminMap even if I uninstall my app.

Once you have done this, go ahead and uninstall your app.

Step 2

Now install the anti-virus software that you are benignly trying to deceive. If you have done everything right, then you should be able to get something like the screen shots below, in which Lookout’s AV thinks that it has the feature requiring device administration privilege enabled. Note that, if you run into any unexpected results, you can try to debug by building your own Android image with debug log statements inserted in the code related to vulnerable code. You can find some hints for that as well in my earlier post on OBAD analysis.

Note: If you did not take my advice and, instead of trying it with an AV, you tried it on your corporate MDM app, it may not have worked because of what I will explain below.

The real list of device administrators as seen from Settings -> Security -> Device Administrators – showing none is enabled.

One More Obstacle

If you tried the above steps on an MDM app, it likely did not work. The reason is that MDM apps typically also use other methods to check whether the device is compliant with the security policies. One common way is to check for password strength compliance using isActivePasswordSufficient of DevicePolicyManager. Taking a look at its code, you will see:

 public boolean isActivePasswordSufficient(int userHandle) { enforceCrossUserPermission(userHandle); synchronized (this) { DevicePolicyData policy = getUserData(userHandle); // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);

As you can see in the highlighted code and comment above, it uses getActiveAdminForCallerLocked to ensure that the caller is an active device administrator who has permissions to use the password limiting policy. If the MDM uses this method and you have done what I have mentioned above, the reason it will not work is that, in getActiveAdminForCallerLocked when called with first parameter being null, we execute:

ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { final int callingUid = Binder.getCallingUid(); final int userHandle = UserHandle.getUserId(callingUid); final DevicePolicyData policy = getUserData(userHandle); if (who != null) { ... } else { final int N = policy.mAdminList.size(); for (int i=0; i

This enumerates the admins in mAdminList, which is correctly updated when we disable or remove a Device Administrator. In the way we tried to exploit it above, this check will throw a security exception because the MDM’s Device Administrator would not be in mAdminList.

Note that the exception will not be thrown so long as there exists one enabled device administrator with the same policies as the MDM app that you are trying to bypass. It should have the same user ID (because of admin.getUid() == callingUid check) as that of the MDM to be bypassed. Now this is possible if you can use the android:sharedUserId attribute in Android manifest file. This is how you can exploit an MDM:

Perform Step 1 as mentioned above. Unpack the apk of the MDM you are trying to bypass, edit the AndroidManifest.xml file and add android:sharedUserId=, repackage it and generate a new apk signed with your own key .

Create a different app with a DeviceAdministrator component using same policies as the Device Administrator you are trying to bypass, this would be a simple and dumb app and would not enforce anything, use the same setting for android:sharedUserId= in its manifest file, sign it with same key, install it on your device and enable its device administrator. Install the repackaged apk for the MDM you are trying to bypass, and it should think that it has its Device Administrator enabled and that the password is compliant because the security exception will not be thrown by getActiveAdminForCallerLocked since there would be an active device administrator with the same UID as the one you are trying to bypass.

After all this, you can get your MDM to think that you are fully compliant with the corporate policies while your device does not even have a device administrator enabled except perhaps a self-signed, very user-laziness-friendly one that even allows the absence of a password when the unlock setting is enabled.

 

Mitigation and Responsible Disclosure

MDM apps should also check whether their DeviceAdministrator component is enabled by using getActiveAdmins() of DevicePolicyManager along with its isAdminActive method. Furthermore, to be safer, they should also look into using code protection techniques and verify the app signing certificate at run time.

The Android security team has been notified of this vulnerability, and it has already been fixed in the latest version of Android. However, earlier versions remain vulnerable, and the easiest thing here may be for the MDM apps to update themselves if they are affected; even if earlier versions of Android are patched, who knows when it will reach all the devices that an MDM supports. We have also informed some of the top MDM vendors who may be affected by this and have coordinated the release of this blog entry with them.

Conclusions

We hope this will emphasize the need for the following:

  • Well-balanced BYOD solutions that meet security needs while being user-friendly and not causing unnecessary trouble to users.
  • Emphasis on the importance of code protection for your apps and on verification of app signature at run time.

 

More from Endpoint

Deploying Security Automation to Your Endpoints

Globally, data is growing at an exponential rate. Due to factors like information explosion and the rising interconnectivity of endpoints, data growth will only become a more pressing issue. This enormous influx of data will invariably affect security teams. Faced with an enormous amount of data to sift through, analysts are feeling the crunch. Subsequently, alert fatigue is already a problem for analysts overwhelmed with security tasks. With the continued shortage of qualified staff, organizations are looking for automation to…

Threat Management and Unified Endpoint Management

The worst of the pandemic may be behind us, but we continue to be impacted by it. School-aged kids are trying to catch up academically and socially after two years of disruption. Air travel is a mess. And all businesses have seen a spike in cyberattacks. Cyber threats increased by 81% while COVID-19 was at its peak, with 79% of all organizations experiencing a loss of business operations during that time. The risk of cyberattacks increased so much that the…

3 Ways EDR Can Stop Ransomware Attacks

Ransomware attacks are on the rise. While these activities are low-risk and high-reward for criminal groups, their consequences can devastate their target organizations. According to the 2022 Cost of a Data Breach report, the average cost of a ransomware attack is $4.54 million, without including the cost of the ransom itself. Ransomware breaches also took 49 days longer than the data breach average to identify and contain. Worse, criminals will often target the victim again, even after the ransom is…

How EDR Security Supports Defenders in a Data Breach

The cost of a data breach has reached an all-time high. It averaged $4.35 million in 2022, according to the newly published IBM Cost of a Data Breach Report. What’s more, 83% of organizations have faced more than one data breach, with just 17% saying this was their first data breach. What can organizations do about this? One solution is endpoint detection and response (EDR) software. Take a look at how an effective EDR solution can help your security teams. …