El pasado viernes, en la última jornada de la Ekoparty, los investigadores representantes de Core Security Technologies, Martin Balao y Martin Fernandez, nos deleitaron con su demostración de explotación de aplicaciones Android para lograr la ejecución de comandos en dispositivos remotos. Esto se lograba mediante la posibilidad de inyectar procesos para hacer uso de aplicaciones con vulnerabilidades conocidas, y así conseguir acceso a los permisos vigentes en el equipo víctima. A lo largo de su presentación explicaron cómo explotar, escalar y post-explotar este tipo de debilidades presentes en uno de los sistemas operativos móviles más utilizados mundialmente, de manera absolutamente imperceptible para el usuario del terminal.
¿En qué consiste la explotación?
La idea principal de su desarrollo radica en la inyección de procesos para obtener los permisos otorgados a una aplicación vulnerable, y así lograr ganar acceso a la Dalvik VM. Esto se logra mediante la explotación de la clase WebView, la cual presenta componentes HTML y JavaScript –usualmente utilizados para mostrar publicidades al usuario. Éstos vuelven posible la exposición de instancias de clases de Java con la utilización del método addJavascriptInterface() que exporta un objeto JSInterface, deviniendo en la invocación de métodos estáticos como getClass() o forName(), y la eventual obtención del contexto de ejecución conjuntamente a la explotación de cualquier clase cargada en la VM, pudiendo ejecutarse con esta vulnerabilidad diferentes comandos en el sistema operativo remoto.
Entre las dificultades que este enfoque presenta encontramos la fuerte presencia de sandboxing en Android, con aplicaciones corriendo en espacio de usuario, sin privilegios de administrador –y consecuentemente, sin acceso al sistema de archivos o la posibilidad de instalar otras aplicaciones, y el hecho de que binder –el driver del kernel en el sistema operativo Android– utiliza tanto identificadores de usuario como de procesos en su operatoria.
Dado que la presencia de sandboxes restringe la comunicación entre aplicaciones, el objetivo de la explotación se torna entonces en utilizar permisos de aplicaciones vulneradas para interactuar con otros procesos, no desde un proceso separado, sino con la escritura e invocación de archivos en el filesystem desde el mismo proceso mediante inyección. Esto implica la capacidad de alocar un espacio de memoria, escribir un shellcode en el mismo, crear un hilo que lo ejecute, y lograr realizar esto sin corromper la memoria virtual del proceso y el estado de los diferentes hilos.
Y ahora, ¿cómo resulta esto posible?
Ya que, al acoplar un depurador a un proceso, generamos otro proceso padre del mismo bajo nuestro control, somos capaces entonces de interceptar los mensajes enviados al hilo original, otorgándonos el poder de escribir espacio de memoria –incluso de sólo lectura–, leer el contexto de ejecución del hilo, secuestrarlo, detenerlo, o ejecutarlo en un lugar de memoria diferente. Con base en este principio, podemos acoplar un depurador a un hilo de la Dalvik VM, alocar memoria, escribir un shellcode, crear un hilo de ejecución, y utilizar las variables mapeadas entre direcciones físicas y virtuales, dejando finalmente el proceso en su estado original.
Algunos linkers dinámicos presentan la función dlopen, la cual carga una dirección en la memoria del proceso. Para ubicar esta función y acoplarse a ella, es posible buscar la entrada correspondiente en la Global Offset Table (GOT), la cual nos redireccionará a la posición final absoluta de los símbolos de la llamada a la función, pero sólo una vez que el linker dinámico la resuelva.
Entonces, debemos mirar cada entrada en la Procedure Linkage Table (PLT), las cuales constan de un pequeño código ejecutable. En vez de llamar a la función directamente, el código llama una entrada en la PTL, la cual luego se encarga de invocar la función genuina. Esta estructura es conocida como “trampolín”. La identificación de este arreglo se basará en el estudio de patrones aritméticos de los registros, donde cada secuencia de instrucciones corresponde a una función diferente. Una vez determinado el trampolín correspondiente a dlopen, es posible colocar en éste el hilo secuestrado a ejecutar.
La clase ActivityThread del framework contiene un método estático que inicializa la creación del hilo principal de la aplicación vulnerable. Ésta presenta un atributo sMainThreadHandler que devuelve una instancia de Handler, la cual permite mediante el método post() encolar objetos Runnable a ser ejecutados. Un atacante puede generar una llamada nativa para invocar este método, y así obtener una referencia a un objeto Context. Este último actúa como interface para acceder a la información general sobre el contexto de ejecución de la aplicación, como ser recursos y clases específicos de la misma, o llamadas desde binder al Activity Manager Service para realizar operaciones como lanzar actividades, publicar y recibir intentos, y concretar acciones de alto nivel –como la lectura o envío de SMSs.
Resumiendo lo aprendido…
Luego de la inyección, un atacante podría interactuar con binder utilizando Java a modo de post-explotación. De esta forma, se consigue acceso a los objetos en Java, sus métodos, y los métodos estáticos de las clases a las que pertenecen. Una manera de lograr esto es instanciar un objeto de APK ClassLoader, y utilizarlo para cargar código malicioso.
El resultado final de la explotación es la posibilidad de reemplazar los javascripts, incluir payloads binarios, escribir éstos en el sistema de archivos, y concluir con un Java Agent ejecutando en el equipo víctima con el mismo identificador de proceso que la aplicación vulnerable, lo que permite la posterior escalación de privilegios y la inyección remota de comandos –como la generación de llamadas o el envío de SMSs, el listado del sistema de archivos o de los procesos actualmente siendo ejecutados en el sistema operativo.
Como bien resaltaron los oradores, el comprender este tipo de vulnerabilidades nos recuerda la importancia de evitar aplicaciones depurables en entornos de producción, siendo las entidades corporativas potenciales blancos para estos ataques. Además, los archivos .apk construidos en modo standalone –es decir, paquetes de aplicación que no requieren de otros paquetes o archivos para funcionar– se constituyen como un sistema inherentemente débil, que de ser combinado con un proceso de explotación como el explicado a lo largo de esta charla, pueden generar poderosos vectores de ataque.