martes, 6 de noviembre de 2012

Análisis de Tráfico SSL en Android 4.x


El post de hoy no trata de ninguna nueva técnica ni nada excesivamente sofisticado, sino más bien de algo que es conocido pero que la gente con memoria de pez como yo se ve obligado a buscar una y otra vez cuando necesita hacer algo.

Cuando queremos analizar una aplicación de Android, ya sea para hacer una auditoría o para analizar si tiene algún componente malicioso (en mi caso suele ser lo primero), una de las cosas que tenemos que mirar son los puntos de comunicación con el exterior. Uno de los medios de comunicación más habituales es el uso de HTTP para comunicarse con aplicaciones web externas o web services. Hasta aquí ningún problema, podemos suplantar el nombre empleando el módulo fakedns de Metasploit ([1] [2] [3]) e interceptar las comunicaciones empleando Burp Proxy, ZAP o cualquier otro a vuestra elección.

El principal problema ocurre cuando esta comunicación es HTTPS, ya que estos proxies lo que hacen es crear una CA interna y van generando certificados firmados por esta CA para cada web que visitas (el funcionamiento puede cambiarse, pero este es el que viene por defecto con Burp). Esta CA creada por Burp, evidentemente, no es de confianza para nuestro Android, así que se nos muestra un mensaje de advertencia como el que vemos arriba o, sencillamente, la aplicación que estamos auditando rechazará la conexión por no estar firmado el certificado por una CA de confianza.

Como muchas veces la aplicación no nos va a dejar que aceptemos este certificado, vamos a tener que hacer algo para que nuestro Android confíe en la CA de nuestro Burp, así que lo primero que vamos a hacer es obtener la clave pública de esa CA. La manera más sencilla es hacer que nuestro navegador estandar use el burp y visitar cualquier web por HTTPS. Si vemos el detalle de los certificados veremos que podemos exportarlos en varios formatos. Hagámoslo en PEM:


Ahora que tenemos el certificado habrá que subirlo de algún modo a nuestro dispositivo. Se puede hacer de varias formas, pero una de las más cómodas es usar el comando "adb" que viene con el SDK de Android:

$ adb push PortSwiggerCA.pem /sdcard/
107 KB/s (1038 bytes in 0.009s)

Ya lo tenemos subido ¿y ahora dónde lo metemos? En versiones anteriores de Android los certificados de las CAs de confianza se encontraban en un único fichero que debíamos bajar a nuestro equipo, añadir la nueva CA y posteriormente volverlo a subir. En el caso de Android 4 la cosa ha cambiado un poco, ahora tenemos una serie de ficheros en /system/etc/security/cacerts/ que contienen cada uno de ellos un certificado de una CA:

$ adb shell
shell@android:/ $ su
shell@android:/ # cd /system/etc/security/cacerts/
shell@android:/system/etc/security/cacerts # ls -la
-rw-r--r-- root     root         4767 2012-09-28 14:15 00673b5b.0
-rw-r--r-- root     root         4573 2012-09-28 14:15 03e16f6c.0
-rw-r--r-- root     root         5292 2012-09-28 14:15 08aef7bb.0
-rw-r--r-- root     root         4540 2012-09-28 14:15 0d188d89.0
-rw-r--r-- root     root         4614 2012-09-28 14:15 10531352.0
-rw-r--r-- root     root         4686 2012-09-28 14:15 111e6273.0
-rw-r--r-- root     root         5027 2012-09-28 14:15 1155c94b.0
-rw-r--r-- root     root         5345 2012-09-28 14:15 119afc2e.0
-rw-r--r-- root     root         5844 2012-09-28 14:15 11a09b38.0
[...]

Parece que, si disponemos de acceso root, debería ser tan fácil como colocar nuestro fichero PEM en este directorio ¿Con cualquier nombre? Pues no, cualquier nombre no vale. Esos números que vemos no son más que un hash del subject del certificado, y se usan como si fuera una tabla hash, es decir, cuando se obtiene un certificado que está firmado por una CA, se realiza el hash del subject de esta CA y se busca el fichero con este nombre. Si se producen colisiones en el hash se va incrementando el número de la extensión (.0 .1 .2 ...). Para obtener ese hash lo podemos hacer con openssl de la siguiente forma:

$ openssl x509 -noout -subject_hash_old -in PortSwiggerCA.pem
9a5ba575

Ahora solo nos quedará meter el certificado en el lugar indicado con el nombre adecuado. Para ello, depende del rooteo que hayamos hecho, es probable que tengamos que remontar en lectura/escritura la partición /system:

shell@android:/system/etc/security/cacerts # mount -o rw,remount /system
shell@android:/system/etc/security/cacerts # cat /sdcard/PortSwiggerCA.pem > 9a5ba575.0
shell@android:/system/etc/security/cacerts # mount -o ro,remount /system

Hecho esto ya solo tenemos que reiniciar el terminal y volver a repetir el proceso. Ahora cuando visitemos una página HTTPS a través de Burp, el navegador va a aceptar el certificado que éste le proporciona, y por tanto va a poder inspeccionar y modificar este tráfico.

Lo mismo va a ocurrir con las aplicaciones en las que no podíamos simplemente darle a "aceptar certificado", con lo que ya tenemos resuelto el problema de inspeccionar este tráfico.

Ahora quedaría mirar si, dentro de ese tráfico, podemos manipular la información o hacer algo con lo que vulneremos la seguridad de la aplicación, pero eso ya... es otra historia.