Siguiendo con la idea del artículo anterior,
Evadiendo implementaciones de certificate pinning, vamos a ver otra forma de resolver el mismo problema: utilizar la API de
Cydia Substrate
la cual nos permitirá hacer hooking y alterar la
ejecución de las
aplicaciones en memoria sin necesidad de modificar el código original de
la aplicación que queremos analizar.
Los ingredientes
Para aplicar esta técnica de análisis de aplicaciones vamos a necesitar:
- Un dispositivo rooteado, nos vale una máquina virtual
- Instalar en el dispositivo la aplicación Cydia Substrate
- Tener configurado un entorno de desarrollo Android (vamos a implementar una extensión Substrate para alterar la ejecución de las aplicaciones)
- Descargar el SDK de Android Substrate
- Proxydroid instalado en el dispositivo + Máquina con Web proxy donde
redirigir el tráfico (en mi caso Burp) + Certificado Burp instalado en
dispositivo
Y para que podamos apreciar mejor la diferencia entre
desensamblar + alterar el código + re-empaquetar y
alterar el código en memoria con Substrate, vamos a realizar las pruebas sobre la misma app:
eTools Private Search, de modo que si ya la teníamos instalada y alterada por la anterior prueba es el momento de reinstalarla desde Google Play.
El paso a paso
Antes de entrar en materia recordemos que en el artículo evadimos la
implementación del certificate pinning (de aquí en adelante CP para
abreviar) anulando el paso del array TrustManager, el cual contenía la
clave pública del servicio que se quería certificar:
![](http://3.bp.blogspot.com/-hM7OD3p8gD0/VF9so5FAWhI/AAAAAAAAAX4/AC0yBU5ZO_Y/s1600/Selecci%C3%B3n_047.png) |
Figura 1 |
Utilizando esta técnica de hooking lo que vamos a hacer es añadir un
hook sobre la clase y método de la que queremos alterar el
comportamiento para, una vez obtenido el flujo de ejecución de la
aplicación, ajustarlo a nuestra necesidad.
Y dicho lo anterior, se nos plantean dos posibilidades:
a) Podemos hacer un hook a nivel de la app sobre el método mostrado en la Figura 1 para
reescribir todo su comportamiento. Lo que haríamos sería no crear el
array TrustManager que contiene la clave pública del certificado y que
así el objeto SSLContext no lo tenga en cuenta y nos admita el
certificado de nuestro Web proxy.
b) Podemos hacer un
hook a nivel de la API de Android sobre el método
init de la clase
SSLContext,
de modo que cuando la app haga la llamada a esa función nosotros
capturemos esa ejecución. Una vez con el control podemos delegar la
ejecución al método
init original, pero pasando un argumento nulo donde se esperaba el array TrustManager con la clave pública fijada.
Vamos a elegir la opción b) ya que como veréis más adelante incluirá una
grata sorpresa al modificar el comportamiento a nivel de la API de
Android.
Ya con la estrategia definida nos ponemos manos a la obra, vamos a crear
una extensión Substrate y a cargarla en nuestro dispositivo de análisis
para alterar la ejecución en memoria y evadir el mecanismo de seguridad
de CP:
1. Creamos un proyecto Android, en mi caso usaré Android Studio aunque
podemos usar cualquier IDE que nos permita desarrollar para Android:
![](http://3.bp.blogspot.com/-zecinFMWGTw/VF9ptq19R8I/AAAAAAAAAXo/zgsrKYMz04M/s1600/Selecci%C3%B3n_044.png) |
Figura 2 |
Y agregamos en el proyecto la librería de Substrate que hemos descargado en el punto 4 del apartado anterior:
![](http://3.bp.blogspot.com/-x4clD1__bMA/VF9ptoK8SaI/AAAAAAAAAXk/uybxrAAejq0/s1600/Selecci%C3%B3n_045.png) |
Figura 3 |
2. Creamos el código de la extensión para modificar el comportamiento
del método init de la clase SSLContext, para ello creamos una clase a la
que llamamos por ejemplo BypassCertificatePinning con el siguiente
contenido:
![](http://2.bp.blogspot.com/-OPU1DjwspME/VF9vJJOK2EI/AAAAAAAAAYE/gW6l6KPG9Qs/s1600/Selecci%C3%B3n_048.png) |
Figura 4 |
En el fragmento de código anterior hacemos lo siguiente:
- Utilizando la función MS.hookClassLoad(...)
de la API de Substrate establecemos un hook sobre la clase SSLContext
de modo que cuando se creen objetos de ese tipo se ejecute el código
contenido en classLoaded(...)
- Cuando se detecte la creación de objetos SSLContext se ejecutará nuestro código, que utilizando reflection nos permitirá acceder al método init que vamos a alterar
- Utilizando la función MS.hookMethod(...) de la API de Substrate definiremos el nuevo comportamiento a realizar por el método init:
![](http://3.bp.blogspot.com/--hZIQyekAdo/VF9wsFgj6iI/AAAAAAAAAYQ/mHnLKYXTRE4/s1600/Selecci%C3%B3n_049.png) |
Figura 5 |
Entrando en más detalle sobre el código de la
Figura 5 lo que he hecho ha sido alterar su comportamiento para pasar la llamada al método
init original ( usando
invoke(...) )con
una diferencia sustancial: anular el segundo parámetro (que es el que
contiene el array TrustManager con las claves públicas que harán el CP).
3. Ajustamos el manifiesto de la aplicación preparándolo para la ejecución de la extensión que vamos a desarrollar:
![](http://1.bp.blogspot.com/-MUKeo2oiuNc/VF9y3cN1soI/AAAAAAAAAYc/ZtM7A_o-DfM/s1600/Selecci%C3%B3n_046.png) |
Figura 6 |
4. Instalamos la aplicación en el dispositivo y si todo ha ido bien
veremos como recibimos una notificación de que se ha detectado una nueva
extensión de Substrate:
![](http://4.bp.blogspot.com/-Je1e262mLl8/VF9zsQ7VyyI/AAAAAAAAAYk/JlEdBhPoprI/s1600/Selecci%C3%B3n_050.png) |
Figura 7 |
Ahora debemos reiniciar el dispositivo para que la extensión tenga efecto, lo podemos hacer desde el botón Restart System (Soft) que se mostrará en la app de Substrate al hacer click en la notificación, este reinicio será bastante rápido:
![](http://4.bp.blogspot.com/-WLeIu4ytlwM/VF9z-roPGxI/AAAAAAAAAYw/Yb6LpWmhgMU/s1600/Selecci%C3%B3n_051.png) |
Figura 8 |
5. Ya estamos preparados, redirigimos el tráfico HTTP/S al web proxy y
ejecutamos la aplicación. Si revisamos los logs del sistema veremos las
trazas que he dejado en el código:
![](http://2.bp.blogspot.com/-kWge-GwYzUQ/VF91CuBxt7I/AAAAAAAAAY8/COx82k6gOhs/s1600/Selecci%C3%B3n_052.png) |
Figura 9 |
Finalmente podemos ver el tráfico en nuestro Web proxy y confirmar la evasión del CP:
![](http://3.bp.blogspot.com/-i1P3DYIFGRc/VF9181XvvRI/AAAAAAAAAZE/qThhXHp4LFQ/s1600/Selecci%C3%B3n_053.png) |
Figura 10 |
Bonus track
Otra ejemplo de implementación de CP como mecanismo de seguridad lo podemos encontrar en la app de
Twitter,
que si probáis a re-empaquetar con el método que comentaba en el
artículo anterior veréis que incluso sin modificar código la aplicación
falla al iniciarse.
Sin embargo, con el paso a paso que hemos descrito en el punto anterior y
sin necesidad de hacer nada más ya estaremos evadiendo su
implementación de CP:
![](http://1.bp.blogspot.com/-MILdmFwqdAU/VF94ZiojM3I/AAAAAAAAAZQ/iei3tc2JnqI/s1600/Selecci%C3%B3n_055.png) |
Figura 11 |
Conclusiones
Como veis se trata de un método bastante inocuo ya que no alteramos la aplicación en sí sino su ejecución en memoria.
Nos ofrece muchísimo potencial ya que tras un análisis previo del código
de la aplicación podemos alterar tanto las funciones de la propia
aplicación como de la API de Android para tener un control todavía
mayor, lo cual nos depurar y alterar la ejecución mientras que pasamos
desapercibidos a determinadas validaciones como puede ser la
verificación de firma de la propia app, comprobación de hash de ficheros
del APK,
aapt modificados para complicar el proceso de re-empaquetado, etc.
Artículo cortesía de Miguel Ángel García