📜 ⬆️ ⬇️

Parsing EvilParcel Vulnerabilities

Introduction


In mid-April, we published a news about the Android.InfectionAds.1 Trojan, which exploited several critical vulnerabilities in the Android OS. One of them - CVE-2017-13156 (also known as Janus ) - allows malware to infect APK files without damaging their digital signature.

The other is CVE-2017-13315. It gives the Trojan extended privileges, and it can independently install and uninstall applications. A detailed analysis of Android.InfectionAds.1 is available in our virus library, it can be found here . We will dwell on the vulnerability CVE-2017-13315 and see what it is.

CVE-2017-13315 belongs to the group of vulnerabilities that have been named EvilParcel. They are found in various system classes of the Android OS. Due to errors in the latter in the exchange of data between applications and the system, it becomes possible to substitute this data. Malicious programs that exploit the vulnerabilities of EvilParcel receive higher privileges and can do the following with their help:


At the moment, there are 7 known vulnerabilities of this type:
')

All of them threaten devices running Android OS 5.0 - 8.1, on which the May security update of 2018 and later is not installed.

Prerequisites for EvilParcel Vulnerabilities


Let's see how EvilParcel vulnerabilities arise. First of all, consider some features of the Android applications. In the Android OS, all programs interact with each other, as well as with the operating system itself, by sending and receiving objects of the Intent type. These objects can contain an arbitrary number of key-value pairs inside an object of type Bundle.

When passing an Intent, the Bundle object is converted (serialized) into a byte array clothed in Parcel, and when reading keys and values ​​from a serialized Bundle, it is automatically deserialized.

In the Bundle, the key is the string, and the value can be almost anything. For example, a primitive type, string, or container containing primitive types or strings. In addition, it can be an object of type Parcelable.

Thus, in the Bundle you can put an object of any type that implements the Parcelable interface. For this, you need to implement the writeToParcel () and createFromParcel () methods to serialize and deserialize the object.

As a visual example, create a simple serialized Bundle. Let's write a code that puts three key-value pairs in the Bundle and serializes it:

Bundle demo = new Bundle ();
demo.putString ("String", "Hello, World!");
demo.putInt ("Integer", 42);
demo.putByteArray ("ByteArray", new byte [] {1, 2, 3, 4, 5, 6, 7, 8});
Parcel parcel = Parcel.obtain ();
parcel.writeBundle (demo);

After executing this code, we get the following Bundle:



Figure 1. Structure of the serialized Bundle object.

Pay attention to the following features of the Bundle serialization:


Due to the fact that all keys and values ​​in the Bundle are written sequentially, when accessing any key or value of a serialized Bundle object, the latter is deserialized completely, including initializing all Parcelable objects contained in it.

It would seem, what could be the problem? And it is that in some system classes that implement Parcelable, there may be errors in the createFromParcel () and writeToParcel () methods. In these classes, the number of bytes read in the createFromParcel () method will differ from the number of bytes written in the writeToParcel () method. If you put an object of this class inside the Bundle, the borders of the object inside the Bundle after re-serialization will change. And it is here that the conditions are created for the exploitation of the vulnerability of EvilParcel.

Here is an example of a class with a similar error:

class Demo implements Parcelable { byte[] data; public Demo() { this.data = new byte[0]; } protected Demo(Parcel in) { int length = in.readInt(); data = new byte[length]; if (length > 0) { in.readByteArray(data); } } public static final Creator<Demo> CREATOR = new Creator<Demo>() { @Override public Demo createFromParcel(Parcel in) { return new Demo(in); } }; @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(data.length); parcel.writeByteArray(data); } } 

If the size of the data array is 0, then when creating an object, one int (4 bytes) will be read into createFromParcel (), and two int (8 bytes) will be written to writeToParcel (). The first int will be written by explicitly calling writeInt. The second int will be written when calling writeByteArray (), because the length of the parcel is always written before the array (see Figure 1).

Situations where the size of the data array is 0, rarely occur. But even when this happens, the program continues to work anyway, if you transmit only one object in serialized form at a time (in our example, the Demo object). Therefore, such errors tend to go unnoticed.

Now let's try to place a Demo object with zero length of the array in the Bundle:


Figure 2. The result of adding a zero-length Demo object to the Bundle.

Serialize the object:


Figure 3. Bundle object after serialization.

Let's try to deserialize it:


Figure 4. After deserializing the Bundle object.

What is the result? Consider the Parcel fragment:


Figure 5. Parcel structure after Bundle de-serialization.

From Figures 4 and 5, we see that during deserialization in the createFromParcel method, one int was read instead of two previously written. Therefore, all subsequent values ​​from the Bundle were read incorrectly. The value 0x0 at address 0x60 was read as the length of the next key. And the value 0x1 at address 0x64 was read as a key. The value 0x31 at address 0x68 was read as a value type. In Parcel there are no values ​​whose type is 0x31, therefore readFromParcel () faithfully reported an error (exception).

How can this be used in practice and become a vulnerability? Let's get a look! The error described above in the Parcelable system classes allows the construction of a Bundle, which may differ during the first and repeated deserializations. To demonstrate this, modify the previous example:

 Parcel data = Parcel.obtain(); data.writeInt(3); // 3 entries data.writeString("vuln_class"); data.writeInt(4); // value is Parcelable data.writeString("com.drweb.testbundlemismatch.Demo"); data.writeInt(0); // data.length data.writeInt(1); // key length -> key value data.writeInt(6); // key value -> value is long data.writeInt(0xD); // value is bytearray -> low(long) data.writeInt(-1); // bytearray length dummy -> high(long) int startPos = data.dataPosition(); data.writeString("hidden"); // bytearray data -> hidden key data.writeInt(0); // value is string data.writeString("Hi there"); // hidden value int endPos = data.dataPosition(); int triggerLen = endPos - startPos; data.setDataPosition(startPos - 4); data.writeInt(triggerLen); // overwrite dummy value with the real value data.setDataPosition(endPos); data.writeString("A padding"); data.writeInt(0); // value is string data.writeString("to match pair count"); int length = data.dataSize(); Parcel bndl = Parcel.obtain(); bndl.writeInt(length); bndl.writeInt(0x4C444E42); // bundle magic bndl.appendFrom(data, 0, length); bndl.setDataPosition(0); 

This code creates a serialized Bundle that contains the vulnerable class. Let's look at the result of executing this code:


Figure 6. Build a Bundle with a vulnerable class.

After the first deserialization, this Bundle will contain the following keys:


Figure 7. The result of deserializing a Bundle with a vulnerable class.

Now we will serialize the received Bundle again, then deserialize it again and look at the list of keys:


Figure 8. Result of re-serialization and deserialization of the Bundle with the vulnerable class.

What do we see? In the Bundle appeared key hidden (with the string value "Hi there!"), Which was not there before. Consider the Parcel fragment of this Bundle to see why this happened:


Figure 9. Parcel structure of the Bundle object with a vulnerable class after two cycles of serialization-deserialization.

This is where EvilParcel’s vulnerabilities become clearer. It is possible to create a specially crafted Bundle that will contain the vulnerable class. Changing the boundaries of such a class will allow placing any object in this Bundle - for example, Intent, which will appear in the Bundle only after the second deserialization. This will give the opportunity to hide Intent from the operating system protection mechanisms.

EvilParcel operation


Android.InfectionAds.1 using CVE-2017-13315 independently installed and removed programs without the intervention of the owner of the infected device. But how does this happen?

In 2013, an error 7699048 , also known as Launch AnyWhere, was detected. It allowed a third-party application to start arbitrary activity on behalf of the more privileged user system. The diagram below shows the mechanism of its action:


Figure 10. The scheme of the work error 7699048.

Using this vulnerability, an exploit application can implement the AccountAuthenticator service, which is designed to add new accounts to the operating system. Thanks to the error 7699048, the exploit is able to launch activity for installing, deleting, replacing applications, resetting a PIN or Pattern Lock and doing other unpleasant things.

Google Corp. has eliminated this gap by prohibiting arbitrary activity from running AccountManager. Now AccountManager only allows starting the activity originating from the same application. To do this, check and match the digital signature of the program that initiated the launch of activity with the signature of the application in which the started activity is located. It looks like this:

 if (result != null && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) { /* * The Authenticator API allows third party authenticators to * supply arbitrary intents to other apps that they can run, * this can be very bad when those apps are in the system like * the System Settings. */ int authenticatorUid = Binder.getCallingUid(); long bid = Binder.clearCallingIdentity(); try { PackageManager pm = mContext.getPackageManager(); ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId); int targetUid = resolveInfo.activityInfo.applicationInfo.uid; if (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authenticatorUid, targetUid)) { throw new SecurityException( "Activity to be started with KEY_INTENT must " + "share Authenticator's signatures"); } } finally { Binder.restoreCallingIdentity(bid); } } 

It would seem that the problem has been solved, but not everything is so smooth here. It turned out that this fix can be circumvented using the well-known vulnerability EvilParcel CVE-2017-13315! As we already know, after fixing Launch AnyWhere, the system verifies the digital signature of the application. If this check is successful, the Bundle is passed to IAccountManagerResponse.onResult (). At the same time, the onResult () call occurs through the IPC mechanism, so the Bundle is serialized again. In the implementation of onResult (), the following happens:

 /** Handles the responses from the AccountManager */ private class Response extends IAccountManagerResponse.Stub { public void onResult(Bundle bundle) { Intent intent = bundle.getParcelable(KEY_INTENT); if (intent != null && mActivity != null) { // since the user provided an Activity we will silently start intents // that we see mActivity.startActivity(intent); // leave the Future running to wait for the real response to this request } //<.....> } //<.....> } 

Next, the Bundle retrieves the intent key and the activity is started without checks. As a result, to launch an arbitrary activity with system rights, it is enough just to construct a Bundle so that the intent field is hidden during the first deserialization, and it appears when it is repeated. And, as we have already seen, it is this task that is performed by the EvilParcel vulnerabilities.

At the moment, all known vulnerabilities of this type are fixed with fixes in the vulnerable Parcelable classes themselves. However, the reappearance of vulnerable classes in the future cannot be ruled out. The implementation of the Bundle and the mechanism for adding new accounts are still the same as before. They still allow you to create exactly the same exploit when detecting (or the appearance of new) vulnerable classes Parcelable. Moreover, the implementation of these classes is still done manually, and the programmer must keep track of the constant length of the serialized Parcelable object. And this is the human factor with all that it implies. However, let's hope that there will be as few of such errors as possible, and EvilParcel’s vulnerabilities will not bother users of Android devices.

You can check your mobile device for EvilParcel vulnerabilities using our anti-virus Dr.Web Security Space . The “Security Auditor” built into it will report on the identified problems and give recommendations on how to eliminate them.

Source: https://habr.com/ru/post/457558/


All Articles