Bypass de SSL Pinning y Root Detection con Frida

El pentesting de aplicaciones móviles requiere dominar un conjunto de técnicas que nos permitan analizar el funcionamiento de una aplicación e identificar posibles vulnerabilidades.

En el caso de Android, lo habitual es comenzar obteniendo el APK de la aplicación y realizando un análisis estático, examinando su código y sus recursos en busca de posibles vulnerabilidades. Posteriormente, mediante el análisis dinámico, estudiamos su comportamiento en tiempo de ejecución, las medidas de seguridad que implementa y las comunicaciones que establece.

En muchas ocasiones, este proceso también nos lleva a realizar un pentesting de API, ya que gran parte de las aplicaciones móviles se comunican con servidores externos mediante APIs para gestionar datos y funcionalidades. Por este motivo, analizar las peticiones y respuestas que intercambia la aplicación con su backend resulta especialmente interesante.

Durante este proceso, podemos encontrarnos con mecanismos de seguridad que dificultan nuestro análisis. Dos de los más habituales son el SSL Pinning y la detección de root.

En este artículo veremos en qué consisten estos mecanismos y cómo podemos evadirlos. Para ello, utilizaremos la aplicación vulnerable Allsafe, con la que practicaremos el bypass de SSL Pinning, y el bypass de root para eludir los mecanismos de detección de root de una aplicación Android.

SSL Pinning

La mayoría de las aplicaciones móviles se comunican con servidores remotos para consultar, enviar y almacenar información. Si estas comunicaciones no se realizan de manera segura, por ejemplo, utilizando HTTP en lugar de HTTPS, los datos transmitidos viajan sin cifrar.

Esto supone un riesgo importante, ya que un atacante con acceso al tráfico de red podría interceptar las comunicaciones y obtener información sensible, como credenciales de acceso, tokens de sesión o datos personales. Este escenario puede darse mediante un ataque Man-in-the-Middle (MITM) y está relacionado con la vulnerabilidad M5: Insecure Communication, recogida en el OWASP Mobile Top 10.

Para proteger las comunicaciones, las aplicaciones utilizan HTTPS para cifrar los datos transmitidos entre el cliente y servidor.

No es objeto de este artículo explicar en detalle el funcionamiento de TLS (que merece su artículo própio), pero TLS además del cifrado también permite verificar la identidad del servidor mediante certificados digitales. Cuando una aplicación establece una conexión HTTPS, el servidor presenta su certificado, que debe ser validado por el cliente. El cliente verifica que el certificado sea válido, corresponda al dominio certificado y que su cadena de confianza esté respladada por una autoridad de certificación (CA) reconocida.

Durante la fase de análisis dinámico de una aplicación, es habitual utilizar herramientas como Burp Suite para interceptar y analizar las peticiones HTTP y HTTPS que se intercambian con el servidor.

Sin embargo, como hemos visto, cuando una aplicación utiliza HTTPS, las comunicaciones están cifradas, por lo que no podemos acceder directamente a su contenido. Para poder analizarlas, configuramos Burp Suite como proxy entre la aplicación y el servidor e instalamos su certificado de CA en el dispositivo.

De esta manera, siempre que la aplicación confíe en dicha CA, Burp Suite podrá establecer las conexiones TLS necesarias para interceptar y descifrar el tráfico HTTPS, permitiéndonos examinar las peticiones y respuestas que intercambia la aplicación con su backend.

Pero ¿qué ocurre si una aplicación no se conforma con verificar que el certificado sea válido y esté firmado por una autoridad de confianza, sino que también comprueba que se corresponde con un certificado o una clave pública concretos?

Aquí es donde entra en juego el SSL Pinning, un mecanismo de seguridad que permite a una aplicación establecer qué certificados o claves públicas considera válidos para comunicarse con un servidor.

Por tanto, aunque hayamos instalado el certificado de Burp Suite y este sea considerado de confianza por el dispositivo, la aplicación puede rechazar la conexión, ya que tiene determinados certificados o claves públicas «pinneados» y únicamente acepta aquellos que coincidan con los valores esperados.

Nuestro objetivo será, por tanto, bypassear esta restricción para que la aplicación acepte las conexiones interceptadas por Burp Suite y podamos continuar con el análisis dinámico.

Bypass de SSL Pinning

Para poner en práctica lo que acabamos de explicar, utilizaremos Allsafe, una aplicación Android intencionadamente vulnerable que incluye diferentes vulnerabilidades y retos de seguridad.

Como podemos observar, si intentamos interceptar el tráfico HTTPS de la aplicación mediante Burp Suite, esta devuelve un error de conexión.

Este error nos dice que la aplicación no puede establecer una cadena de confianza válida para el certificado presentado. Aunque pueda parecer un fallo de SSL Pinning, en realidad todavía estamos ante un problema de validación del certificado TLS. Esto ocurre porque, en las versiones modernas de Android, las aplicaciones no confían por defecto en los certificados instalados por el usuario, salvo que su configuración permita expresamente confiar en ellos.

Por tanto, antes de realizar el bypass del SSL Pinning, debemos asegurarnos de que la aplicación confía en la CA de Burp Suite. De lo contrario, la conexión fallará antes de que podamos comprobar si los certificados o claves públicas coinciden con los valores esperados.

Para entender cómo implementa Allsafe este mecanismo de seguridad, abrimos el APK mediante JADX y buscamos la clase CertificatePinning, ubicada en el paquete infosecadventures.allsafe.challenges.

Código de la aplicación, donde mediante el método certificatePinner.add() se ascoia el dominio httpbin.io

De esta manera, al establecer la conexión, OkHttp comprobará que al menos una de las claves públicas de la cadena de certificados del servidor coincide con alguno de los hashes configurados. Si ninguno coincide, la conexión será rechazada.

Sin embargo, si seguimos analizando el código, encontramos algo interesante. La aplicación no tiene definidos directamente los hashes válidos, sino que utiliza el método extractPeerCertificateChain() para obtenerlos dinámicamente.

Ejemplo extractPeerCertificateChain

Este método configura deliberadamente un hash incorrecto, almacenado en la constante INVALID_HASH, para provocar un error de Certificate Pinning. Cuando OkHttp genera la excepción, incluye en el mensaje los hashes de las claves públicas presentadas por el servidor. La aplicación aprovecha esta información para extraer los hashes y almacenarlos en la lista hashes, que posteriormente utiliza al construir el cliente HTTP.

Classe extractPeerCertificateChain

Nuestro objetivo será utilizar Frida para interceptar el método encargado de validar estos hashes y modificar su comportamiento, de forma que podamos evitar que la aplicación rechace la conexión cuando los valores no coincidan.

Como hemos visto durante el análisis estático, la aplicación utiliza OkHTTP para validar las claves públicas de los certificados. Podríamos desarrollar un script específico, pero también existe script públicos desarrollados y testeados por la comunidad de Frida, que nos pueden ayudar en este tipo de tareas.

Para ello, utilizaremos Frida CodeShare, una plataforma donde la comunidad comparte scripts de instrumentación dinámica que podemos usar en nuestro día a día como pentesters.

Antes de continuar, debemos tener correctamente configurado Burp Suite como proxy de nuestro emulador de Android. En este caso, necesitaremos el certificado de la autoridad de certificación de Burp suite, lo podemos exportar desde: Settings –> Tools –>Proxy –> Import / export CA Certificate (lo exportamos en formato DER y lo guardamos como cacert.der).

Una vez obtenido, podemos utilizar ADB para copiarlo al sistema de archivos del emulador. Importante que lo copiemos en el directorio donde tenemos frida-server instalado y con el nombre de cert-der.crt.

adb push cacert.der /data/local/tmp/cert-der.crt

Para realizar el bypass usaremos el script frida-multiple-unpinning. Este script está diseñado para evadir diferentes implementaciones de SSL Pinning en aplicaciones Android. En lugar de actuar sobre un método específico, intenta interceptar distintas clases y funciones utilizadas durante la validación de certificados.

Una vez, descargado el certificado, copiado en el emulador y con el proxy de burp interceptando, ejecutaremos el siguiente comando

frida -U -f infosecadventures.allsafe --codeshare akabe1/frida-multiple-unpinning

Una vez ejecutado, podemos ver en burpsuite, como hemos interceptado la petición correctamente.

Aunque se haya usado código de una librería, es importante saber leer el código y comprenderlo. En el análisis estático vimos que la aplicación que estamos auditando usa la clase okhttp3.CertificatePinner, por tanto necesitamos que el script que usemos ataque a esa librería.

Observemos el siguiente fragmento del script que estamos usando:

Mediante Java.use(), Frida obtiene una referencia a la clase CertificatePinner. Posteriormente, con overload() selecciona el método check() encargado de realizar la comprobación y sustituye su implementación por una función que simplemente ejecuta un return.

De esta manera, cuando la aplicación intenta verificar los hashes, se ejecuta el código que hemos importado de la codeshare, en lugar del original, evitando que el método rechace la conexión por una discrepancia en los valores.

Otra alternativa que podemos emplear es Objection, una herramienta de instrumentación dinámica basada en Frida que permite realizar diferentes tareas de análisis de aplicaciones móviles sin necesidad de escribir nuestros propios scripts. Para utilizarla, ejecutamos objection -n infosecadventures.allsafe start y, una vez dentro de su consola interactiva, introducimos el comando android sslpinning disable.

De esta manera, Objection intentará evadir las comprobaciones de SSL Pinning de la aplicación, permitiéndonos interceptar y analizar sus comunicaciones HTTPS mediante Burp Suite, siempre que el bypass sea compatible con los mecanismos de validación utilizados.

Bypass de detección de root con Frida

Otra de las medidas de seguridad que podemos encontrar durante el análisis de una aplicación móvil es la detección de root. Algunas aplicaciones comprueban si el dispositivo está rooteado y, en caso afirmativo, pueden limitar determinadas funcionalidades o incluso impedir su ejecución. Esto se debe a que un dispositivo rooteado permite obtener privilegios elevados sobre el sistema operativo, facilitando la modificación de archivos, el acceso a información protegida o uso de herramientas como frida, es por ello que algunas aplicaciones incorporan mecanismos para detectar este tipo de entornos.

Como hemos visto, en un pentesting móvil es habitual trabajar con dispositivos o emuladores rooteados, ya que necesitamos disponer de ciertos privilegios para utilizar herramientas como Frida y analizar el comportamiento de las aplicaciones, por lo que si una aplicación implementa mecanismos de detección de root, tendremos que evadirlo para poder seguir con nuestro análisis.

Para verlo en la práctica, volveremos a utilizar Allsafe, que incluye un desafío llamado Root Detection.

Si accedemos a este desafío e intentamos realizar la comprobación desde nuestro emulador rooteado, la aplicación detecta la presencia de root y muestra el mensaje Sorry, your device is rooted!.

Si analizamos el código de la aplicación, podemos ver como la comprobación se está haciendo llamando a un método isRooted de la biblioteca RootBeer.

Si la función isRooted() Si devuelve true, la aplicación considera que el dispositivo está rooteado y muestra el mensaje de error. En caso contrario, muestra el mensaje indicando que no se ha detectado root.

Por tanto, si conseguimos interceptar este método y forzar que devuelva siempre false, podremos evitar que la aplicación detecte que estamos trabajando sobre un dispositivo rooteado.

Para ello, podemos crear un script de frida bastante sencillito, que básicamente lo que hará es mediante la propiedad implementation, reemplazará el comportamiento original del método isRooted, de manera que cada vez que en el contexto de la aplicación se ejecute la función isRooted, este método se ejecutará y devolverá false.

Java.perform(function () {
    var RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");

    RootBeer.isRooted.implementation = function () {
        console.log("Bypass de Root detection");
        return false;
    };
});

Como podemos observar, después de ejecutar frida e inyectar el script, cuando comprobamos si somos root o no, la aplicación no es capaz de detectarnos, ya que cada vez que la función isRooted se ejecuta, frida inyecta nuestra función y está devuelve false.

Conclusiones

Como hemos visto, tanto el SSL Pinning como la detección de root son mecanismos de seguridad que pueden dificultar el análisis dinámico de una aplicación móvil, pero no son infalibles. Mediante herramientas como Frida y Objection, podemos evadir estas comprobaciones y continuar con nuestro análisis.

Lo importante es entender cómo están implementados estos mecanismos y qué comprobaciones realiza la aplicación, ya que esto nos permitirá identificar la mejor manera de evadirlos.

Mateu Joan Perelló
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.