Introduccion
A mediados de abril,
publicamos noticias sobre el troyano
Android.InfectionAds.1 , que explotó varias vulnerabilidades críticas en Android. Uno de ellos, CVE-2017-13156 (también conocido como
Janus ), permite que el malware infecte archivos APK sin dañar la firma digital. El otro es CVE-2017-13315. Otorga privilegios extendidos al troyano, para que pueda instalar y desinstalar aplicaciones independientemente del usuario. Un análisis detallado de
Android.InfectionAds.1 está disponible en
nuestra biblioteca de virus ; Mientras estamos aquí, abordaremos la vulnerabilidad CVE-2017-13315 y veremos qué hace.
CVE-2017-13315 pertenece al grupo de vulnerabilidades denominado EvilParcel. Se encuentran en varias clases de sistema Android. Los errores en estas clases permiten sustituir información durante el intercambio de datos entre aplicaciones y el sistema. Por lo tanto, el malware que explota las vulnerabilidades de EvilParcel recibe privilegios más altos y se vuelve capaz de lo siguiente:
- instalar y eliminar aplicaciones con cualquier permiso sin la confirmación de los usuarios;
- infectar el software instalado en el dispositivo y reemplazar los originales limpios con copias infectadas cuando se usa junto con otras vulnerabilidades;
- restablecer el PIN de la pantalla de bloqueo en dispositivos Android.
A partir de ahora, conocemos 7 vulnerabilidades de este tipo:
- CVE-2017-0806 (error en la clase GateKeeperResponse), publicado en octubre de 2017;
- CVE-2017-13286 (error en la clase OutputConfiguration, publicado en abril de 2018;
- CVE-2017-13287 (error en la clase VerifyCredentialResponse), publicado en abril de 2018;
- CVE-2017-13288 (error en la clase PeriodicAdvertizingReport), publicado en abril de 2018;
- CVE-2017-13289 (error en la clase ParcelableRttResults), publicado en abril de 2018;
- CVE-2017-13311 (error en la clase SparseMappingTable), publicado en mayo de 2018;
- CVE-2017-13315 (error en la clase DcParamObject), publicado en mayo de 2018.
Todos ellos representan una amenaza para los dispositivos que ejecutan Android 5.0 - 8.1 sin la actualización de seguridad de mayo de 2018 (o posterior) instalada.
Requisitos previos para las vulnerabilidades de EvilParcel
Veamos cómo pueden aparecer las vulnerabilidades de EvilParcel. En primer lugar, debemos analizar algunas características de las aplicaciones de Android. Todos los programas de Android interactúan entre sí, así como con el sistema operativo, enviando y recibiendo objetos Intent. Estos objetos pueden contener un número arbitrario de pares clave-valor dentro de un objeto Bundle.
Al transferir una Intención, un objeto Bundle se convierte (serializa) en una matriz de bytes envuelta en Parcel y luego se deserializa automáticamente después de leer las claves y los valores de un Bundle serializado.
En el paquete, la clave es la cadena, y el valor puede ser casi cualquier cosa. Por ejemplo, puede ser un tipo primitivo, una cadena o un contenedor con tipos o cadenas primitivas. También puede ser un objeto parcelable.
Por lo tanto, el paquete puede contener un objeto de cualquier tipo que implemente la interfaz Parcelable. Para esto, necesitamos implementar los métodos writeToParcel () y createFromParcel () para serializar y deserializar el objeto.
Para ilustrar nuestro punto, creemos un paquete serializado simple. Escribiremos un código que ponga tres pares clave-valor en el paquete y lo serialice:

Figura 1. Estructura de un objeto de paquete serializado
Tenga en cuenta las características específicas de la serialización de paquetes:
- todos los pares clave-valor se escriben secuencialmente;
- el tipo de valor se indica antes de cada valor (13 para la matriz de bytes, 1 para el entero, 0 para la cadena, etc.);
- el tamaño de datos de longitud variable se indica antes de los datos (longitud de la cadena, número de bytes para la matriz);
- Todos los valores están alineados en 4 bytes.
Todas las claves y valores se escriben en el paquete secuencialmente para que al acceder a cualquier clave o valor de un objeto Bundle serializado, este último se deserialice por completo, también inicializando todos los objetos Parcelable contenidos.
Entonces, ¿cuál podría ser el problema? El problema es que algunas clases de sistema que implementan Parcelable pueden contener errores en los métodos createFromParcel () y writeToParcel (). En estas clases, el número de bytes leídos en createFromParcel () diferirá del número de bytes escritos en writeToParcel (). Si coloca un objeto de esta clase dentro de un paquete, los límites del objeto dentro del paquete cambiarán después de la reserialización. Esto crea las condiciones para explotar una vulnerabilidad EvilParcel.
Veamos un ejemplo de una clase que contiene este 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); } }
Si el tamaño de la matriz de datos es 0, al crear un objeto, se leerá un int (4 bytes) en createFromParcel () y dos int (8 bytes) se escribirán en writeToParcel (). El primer int se escribirá llamando explícitamente writeInt. El segundo int se escribirá al llamar a writeByteArray (), ya que la longitud de la matriz siempre se escribe antes que la matriz en Parcel (consulte la Figura 1).
Las situaciones en las que el tamaño de la matriz de datos es igual a 0 son bastante raras. Pero incluso cuando esto sucede, el programa sigue funcionando, si solo transmite un objeto serializado a la vez (en nuestro ejemplo, el objeto Demo). Por lo tanto, tales errores tienden a pasar desapercibidos.
Ahora intentaremos colocar un objeto de demostración con longitud de matriz cero en el paquete:

Figura 2. El resultado de agregar un objeto de demostración de longitud cero al paquete
Nosotros serializamos el objeto:

Figura 3. El objeto Bundle después de la serialización
Ahora intentemos deserializarlo:

Figura 4. El objeto Bundle después de la deserialización
¿Qué obtenemos? Echemos un vistazo al fragmento de paquete:

Figura 5. Estructura del paquete después de la deserialización del paquete
En las Figuras 4 y 5, vemos que en lugar de dos int, se leyó uno int en el método createFromParcel durante la deserialización. Por lo tanto, todos los valores posteriores del paquete se leyeron incorrectamente. El valor 0x0 en 0x60 se leyó como la longitud de la siguiente clave. El valor 0x1 en 0x64 se leyó como una clave. El valor 0x31 en 0x68 se leyó como un tipo de valor. La parcela no tiene valores con el tipo 0x31, por lo tanto, readFromParcel () informa minuciosamente una excepción.
¿Cómo se puede usar esto en la vida real y convertirse en una vulnerabilidad? A ver! El error anterior en las clases del sistema Parcelable permite la creación de paquetes que pueden diferir durante la primera y repetidas deserializaciones. Para demostrar esto, modificaremos el ejemplo anterior:
Parcel data = Parcel.obtain(); data.writeInt(3);
Este código crea un paquete serializado que contiene una clase vulnerable. Ahora veamos qué obtenemos después de ejecutar este código:

Figura 6. Crear un paquete con una clase vulnerable
Después de la primera deserialización, este paquete contendrá las siguientes claves:

Figura 7. Después de la deserialización de un paquete con una clase vulnerable
Ahora serializaremos el paquete nuevamente, luego lo deserializaremos nuevamente y miraremos la lista de claves:

Figura 8. Resultado de la reserialización y deserialización de un paquete con una clase vulnerable
Que vemos El paquete ahora contiene la clave oculta (con el valor de cadena "¡Hola!"), Que no estaba allí antes. Veamos el fragmento de paquete de este paquete para ver por qué sucedió esto:

Figura 9. Estructura de parcela de un objeto Bundle con una clase vulnerable después de dos ciclos de serialización y deserialización
Aquí es donde podemos ver todo el punto de las vulnerabilidades de EvilParcel. Podemos crear específicamente un paquete que contendrá una clase vulnerable. Cambiar los límites de esta clase permitirá la colocación de cualquier objeto en este paquete; por ejemplo, una Intención, que solo aparecerá en el Paquete después de la segunda deserialización. Esto ayuda a ocultar una intención de los mecanismos de seguridad del sistema operativo.
Explotando EvilParcel
Android.InfectionAds.1 explotó CVE-2017-13315 para instalar y eliminar software independientemente de los propietarios del dispositivo. Pero como?
En 2013,
se descubrió el
error 7699048 , también conocido como Launch AnyWhere. Permitió que aplicaciones de terceros iniciaran actividades arbitrarias en nombre de un usuario del sistema más privilegiado. Vea el diagrama a continuación para el mecanismo de acción:

Figura 10. Operación del error 7699048
Una aplicación explotadora puede usar esta vulnerabilidad para implementar el servicio Autenticador de cuenta, diseñado para agregar nuevas cuentas al sistema operativo. El error 7699048 ayuda a las actividades de inicio de explotación para instalar, eliminar, reemplazar aplicaciones, así como restablecer el PIN o el Bloqueo de patrón y causar muchos más problemas.
Google Inc. ha eliminado esta violación al prohibir el lanzamiento de actividades arbitrarias desde AccountManager. Ahora, AccountManager solo permite el lanzamiento de actividades que se originan en la misma aplicación. Para este propósito, verifica y compara la firma digital del software que inició la actividad con la firma de la aplicación donde se encuentra la actividad. Se ve así:
if (result != null && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) { 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); } }
Parece que el problema se ha resuelto, pero no es tan fácil como todo eso. Resultó que la conocida vulnerabilidad, EvilParcel CVE-2017-13315, ofrece una solución alternativa. Como ya sabemos, después de arreglar Launch AnyWhere, el sistema verifica la firma digital de la aplicación. Si se verifica con éxito, el paquete se transfiere a IAccountManagerResponse.onResult (). Al mismo tiempo, onResult () se llama a través del mecanismo IPC, por lo que el Bundle se serializa nuevamente. Al implementar onResult (), sucede lo siguiente:
private class Response extends IAccountManagerResponse.Stub { public void onResult(Bundle bundle) { Intent intent = bundle.getParcelable(KEY_INTENT); if (intent != null && mActivity != null) {
Luego, el paquete extrae la clave de intención y la actividad se inicia sin ninguna verificación.
Por lo tanto, para iniciar una actividad arbitraria con privilegios del sistema, solo necesita crear un Paquete con el campo Intención oculto en la primera deserialización y que aparece durante la deserialización repetida.
Como ya sabemos, las vulnerabilidades de EvilParcel realmente pueden realizar esta tarea.
Por el momento, todas las vulnerabilidades conocidas de este tipo se han corregido dentro de las clases vulnerables Parcelable. Sin embargo, pueden aparecer nuevas clases vulnerables en el futuro. La implementación del paquete y el mecanismo para agregar nuevas cuentas siguen siendo los mismos que antes. Todavía nos permiten crear este exploit exacto al detectar clases parcelables vulnerables viejas o nuevas. Además, estas clases todavía se implementan manualmente, y el programador debe asegurarse de que la longitud del objeto Parcelable serializado permanezca igual, lo cual es un factor humano con todo lo que implica. Sin embargo, esperamos que haya la menor cantidad de errores posibles y que las vulnerabilidades de EvilParcel no sean una amenaza para los usuarios de Android.
Puede verificar las vulnerabilidades de EvilParcel en su dispositivo móvil utilizando nuestro
Dr.Web Security Space para Android. El Auditor de seguridad incorporado informará los problemas detectados y recomendará formas de eliminarlos.