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.

14 comentarios:

fix dijo...

en vez de fakedns, es más facil configurar el uso del proxy burp directamente en las propiedades de la conexión wireless ¿No?

TheSur dijo...

Hola Selvi, el nuevo burpsuite que en su versión free salio hace menos de una semana solventa esto y es todo automatico

Jose Selvi dijo...

@fix: No todas las aplicaciones hacen caso del proxy que se define en el terminal. En muchos casos te valdrá, pero en alguno no.

@TheSur: Lo miré cuando salió y he visto que tiene un par de temas con SSL, pero no me dio la sensación de que se refiriera a esto ¿Tienes algún enlace? ¿Lo has probado? Pásate la info! Yo he usado la versión 1.5 de Burp y he tenido que usar el truco de siempre (el del post), pero si hay mejores maneras de hacerlo estoy abierto a sugerencias :)

Gracias a ambos!

Xavi Rubio dijo...

No se si es el caso, pero en otros sistemas operativos (esto lo había hecho en WebOS) puedes abrir la página con el navegador de sistema y aceptar el certificado allí, y como el almacén de certificados es común para todo el sistema, la otra aplicación lo aceptará. En mi caso lo usaba para importar certificados para poder acceder al servidor de correo con certificados autofirmados, o sea, que el certificado quedaba como válido sin importar el protocolo (lo aceptaba para HTTPS y me valía para IMAPS).

Nikolay Elenkov dijo...

You can import certificates directly from the UI in 4.0+, no root required. Settings->Security->Install from storage. It will pick up any certificate in the root of the SD card and let you choose which one to import.

Nikolay Elenkov dijo...

Also see this:
http://blog.opensecurityresearch.com/2012/07/proxying-android-40-ics-and-fs-cert.html

Jose Selvi dijo...

@Nikolay: Good point :) In lower versions this option only exists for VPN certificates but not for HTTPS.

Anyway, rooting the device is needed in order to check other internal behaviors.

Thanks!

Jose Selvi dijo...

@Xavi: Buen comentario! En Android creo que eso no funciona (me suena que lo probé hace bastante tiempo), pero es cierto que si varias aplicaciones comparten repositorio puedes hacer lo que comentas.

Josep Pi dijo...

Hola Jose,

Sobre lo que comentan de Burp es correcto.

Yo con terminales emulados (levantandolo con la opcion http-proxy) y con burp 1.5rc3 PRO me funciona tanto para navegacion https como apps que tiran de SSL.Eso sí, metiendo el crt de Burp en el terminal y poniendolo como trusted en settings->security desde la UI (En Android 4.0.3 en mi caso).

Aun no me he encontrado alguna APP que me de problemas de esta forma.Muy rápido y comodo!

La explicación de por que ya no hay que tirar de herramientas tipo Androidproxy y ya con Burp funciona:

http://www.h-online.com/open/news/item/Burp-proxy-opens-Android-SSL-connections-1741625.html

Jose Selvi dijo...

@Josep: Es correcto que se puede importar el certificado de CA desde un menú, no que rompa SSL de forma automática ¿no?

Yo el problema de los CONNECT no estandar no los he sufrido porque me parece "manipular el entorno" el configurar un proxy, así que las intercepciones las he hecho con fakedns o redirect de iptables.

Gabriel Pozo dijo...

No lo había leído a este post, muy bueno ;)

Ole dijo...

Para los que, como yo, tuvieron problemas al hacer el adb push porque el sistema de ficheros estaba montado en solo lectura.

# adb shell
# mount -o remount,rw /

Y ahora si, adb push...

Jose Selvi dijo...

@Ole: ¿Seguiste los pasos del Post? Si lo subiste a la SDCard como hice yo no deberías tener problemas, ya que es un dispositivo de lectura/escritura para cualquier aplicación. Luego, en el post está especificado como montar el sistema de ficheros en solo lectura para poder copiar al directorio ya definitivo.

Ole dijo...

Si, segui los pasos pero al hacer el adb push me saltaba el erro diciendo que era un medio de solo lectura. Pero vamos, lo monte lectura escritura y listo.