How to Cheat Your MDM: Compliance without a Password

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.

Note:

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.

Lookout AV thinking that it has the feature requiring device administrator access enabled.

Lookout AV thinking that it has the feature requiring device administrator access enabled.
The real list of device administrators as seen from Settings -> Security -> Device Administrators – showing none is enabled.
Security Device Admins List Showing Lookout Is Not an Admin

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.

User (Laziness) Friendly
A typical screenshot showing a device compliance message.

A typical screenshot showing a device compliance message.

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.
Share this Article:
Zubair Ashraf

X-Force Security Researcher, IBM Security

Zubair Ashraf is a security researcher and team lead for IBM X-Force Advanced Research. He is very passionate about fighting all malicious activities in cyber space (aka cyber-crime/ attacks, or APT etc.). Currently he contributes to this via several means, and to share a few, he is actively and passionately: Educating and training others via his Twitter, blogging or presenting at security events; Analyzing Exploitation Techniques, Malware and Vulnerabilities and advising the IBM Security System's product development teams on prevention and detection strategies. His twitter account (@zashraf1337) has been listed among security researchers that will blow your mind and recommended on Metasploit's blog as among those to be followed if you like vulnerability research and/or exploit development.