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)
$ adb shell
shell@android:/ $ su
shell@android:/ # cd /system/etc/security/cacerts/
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
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
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.
en vez de fakedns, es más facil configurar el uso del proxy burp directamente en las propiedades de la conexión wireless ¿No?
ResponderEliminarHola Selvi, el nuevo burpsuite que en su versión free salio hace menos de una semana solventa esto y es todo automatico
ResponderEliminar@fix: No todas las aplicaciones hacen caso del proxy que se define en el terminal. En muchos casos te valdrá, pero en alguno no.
ResponderEliminar@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!
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).
ResponderEliminarYou 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.
ResponderEliminarAlso see this:
ResponderEliminarhttp://blog.opensecurityresearch.com/2012/07/proxying-android-40-ics-and-fs-cert.html
@Nikolay: Good point :) In lower versions this option only exists for VPN certificates but not for HTTPS.
ResponderEliminarAnyway, rooting the device is needed in order to check other internal behaviors.
Thanks!
@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.
ResponderEliminarHola Jose,
ResponderEliminarSobre 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
@Josep: Es correcto que se puede importar el certificado de CA desde un menú, no que rompa SSL de forma automática ¿no?
ResponderEliminarYo 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.
No lo había leído a este post, muy bueno ;)
ResponderEliminarPara los que, como yo, tuvieron problemas al hacer el adb push porque el sistema de ficheros estaba montado en solo lectura.
ResponderEliminar# adb shell
# mount -o remount,rw /
Y ahora si, adb push...
@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.
ResponderEliminarSi, 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.
ResponderEliminar