Hackers rompen la encriptación de SSL usada por millones de webs

Podría haber titulado el post como ‘No dejes que la realidad te estropee un buen titular’, pero como total parece que todo el mundo ha copiado el titular de The Register, que es justo el del post, para que molestarme. Es una de las noticias estrella del mundillo de la seguridad de hace unos días, y se puede leer en el enlace anterior por ejemplo.

Para aquellos que no tengan tiempo o ganas de leer la noticia completa, el primer párrafo lo resume muy bien:

Researchers have discovered a serious weakness in virtually all websites protected by the secure sockets layer protocol that allows attackers to silently decrypt data that’s passing between a webserver and an end-user browser.

Ahí es nada. Hay una vulnerabilidad muy seria en prácticamente todos los sitios que usan SSL/TLS que permite a un atacante realizar ataques de Man-in-the-middle. Que es, precisamente, una de las dos cosas que se supone impide SSL.  A partir de ahí la noticia se dedica a asustarnos más contándonos que a partir de ahora (bueno, en realidad desde antes, ahora solo se ha presentado una prueba de concepto) nuestra navegación ha dejado de ser segura y vamos a tener que volver a ir al supermercado a hacer la compra a mano. Y todo porque los navegadores no implementan TLS 1.1 y 1.2. Y no lo hacen porque los desarrolladores de NSS y OpenSSL son una panda de vagos que no han implementado un estándar que tiene cinco años. Curiosamente, yo hubiese jurado que Chrome usa CryptoAPI y no NSS, pero en realidad es lo de menos.

Pero… ¿es cierta la noticia? ¿Tenemos de verdad que volver a ir al banco a hacer las transferencias en persona? ¿Que va a ser de nuestra vida online? Pues sí, y no. Lo que no cuenta la noticia es cual es el problema real. El problema para el que se ha presentado una prueba de concepto se conoce desde el año 2002 (al menos el enlace más antiguo que yo he encontrado eshttp://www.openssl.org/~bodo/tls-cbc.txt que incluye correos de Febrero del 2002), y se debe a la forma en la que se realiza el cifrado en SSL.

De forma muy sencilla, y obviando algunas cosas, cuando se manda un mensaje cifrado normalmente el mensaje se parte en bloques de un tamaño fijo (tamaño de la clave normalmente). Hay varias formas de cifrar los bloques, a su vez. El mecanismo más sencillo es ECB (Electronic Codebook Cipher), que consiste en cifrar cada bloque de forma independiente:
Este es el mecanismo más sencillo, pero tiene un problema básico: un bloque se cifra siempre de la misma forma. Y esto da lugar a dos problemas:

  • Da información del contenido del mensaje.
  • Permite ataques de texto elegido: Un atacante que capture un mensaje cifrado cuyo valor sea ‘ABCD’ no puede descifrarlo para saber que es en realidad ‘HOLA’ cifrado. Pero si puede inyectar bloques, o incluso mensajes completos, puede introducir ‘HOLA’, obtener ‘ABCD’ y así sabrá lo que se había transmitido. En un ejemplo más real, si sabemos que hay una parte del mensaje interceptado es un PIN que tiene un valor entre 0000 y 9999, y podemos inyectar bloques en el proceso de cifrado, podemos probar todos los valores y así averiguar cual era el PIN original.

Para solucionar estos dos problemas hay otros mecanismos de cifrado por bloques. El usado por SSL se conoce como CBC (Cipher Block Chaining) y podemos verlo en la siguiente figura:
Este mecanismo de cifrado evita los dos problemas que tiene ECB: un mismo bloque de texto en claro se cifrará de forma distinta según la posición del mensaje en la que esté. Y, si además el mensaje de inicialización es aleatorio (o pseudoaleatorio), un mismo mensaje completo, cifrado con la misma clave, dará un mensaje cifrado distinto cada vez que se introduzca en el sistema. Y el problema que tiene TLS 1.0 es que usa un vector de inicialización pseudoaleatorio para el primer mensaje que se intercambia. Pero para el resto de los mensajes se usa como vector de inicialización el último bloque cifrado del mensaje anterior.

Así pues, si llamamos
  • C(K,B) a la función que cifra un bloque B con clave K,
  • (B1,…,Bn) a los bloques de un mensaje M
  • + a la función XOR (ya, ya sé que tradicionalmente + es OR, pero no sé poner el + con un círculo en ASCII)

Entonces, los bloques cifrados son
  • C1=C(K,IV+B1)
  • C2=C(K,C1+B2)
  • Ci=C(K,Ci-1+Bi)
  • Cn=C(K,Cn-1+Bn)

Y, en SSL, el mensaje M’, que está compuesto por los bloques (B’1,…,B’n) se cifrará como
  • C’1=C(K,Cn+B’1)
  • C’2=C(K,C’1+B’2)
  • C’n(C(K,Cn-1+B’n)

Ahora supongamos que el que realiza el cifrado es un navegador web que usa SSL, que yo soy un pirata ruso, que creo que Bi es un PIN, y quiero verificar si el valor del PIN es 1234. Y supongamos que yo, con los superpoderes que me proporciona el ser un pirata ruso, puedo generar mensajes (o bloques) con el valor que yo quiera en el navegador del usuario. Entonces simplemente genero un mensaje cuyo primer bloque sea Cn+Ci-1+’1234′, y lo envío tal cual. El mecanismo de cifrado, amablemente, me calcula C’1=C(K,Cn+Cn+Ci-1+’1234′). O lo que es lo mismo, C’1=C(K,Ci-1+’1234′).

Entonces, si Bi=’1234′, C’1 será igual a Ci. Y ya sé el PIN. Si sé que Bi contiene el PIN, pero no es ‘1234′ basta con repetir esta operación otras 9999 veces y sacaré el PIN.

Como decía, este ataque se conoce desde el 2002, pero se creía que no era explotable porque los superpoderes de los piratas rusos no incluían el envío de paquetes escogidos desde el navegador del usuario. He encontrado un paper del 2006 que explica el problema y propone un ataque factible basado en applets en el navegador.

Y la ruptura del SSL a la que hace referencia el artículo de The Register es una prueba de concepto basada en Javascript, que lo que permite es realizar ataques de fuerza bruta remota. O sea, adivinar el PIN generando todas las opciones posibles, mandándolas cifradas como comentaba antes, y verificando en un Sniffer si el valor que se envía es el que se capturo originalmente. En la noticia dicen que funciona para extraer cookies, supongo que porque es más fácil saber en que bloques se envían las cookies.

Para que el ataque sea práctico, es necesario:

  • Que la víctima descargue un Javascript malicioso. El Javascript debe quedarse corriendo en segundo plano.
  • Que la víctima visite el sitio de el que el pirata quiere obtener algún dato, como por ejemplo Paypal (es el ejemplo del artículo).
  • Que sea factible sacar el valor de la cookie por fuerza bruta. O tienen un valor pequeño, o tienen una estructura conocida. Por cierto, en este caso el que el cifrado sea en bloques es una ventaja para el atacante. Si los bloques son de 4 bytes, para romper un PIN de 8 dígitos hay que probar  100.000.000 de combinaciones. Solo hay que probar 20.000 combinaciones, o sea los cuatro primeros dígitos y los cuatro últimos por separado.
  • Que la víctima no cierre el navegador mientras estamos haciendo el ataque.
  • Y que la sesión SSL no caduque en el proceso, porque  caduca cambia la clave K.

¿Es un ataque interesante? Sí. ¿Práctico? No mucho, la verdad. Creo que sigue siendo más sencillo mandarle un correo a la víctima en perfecto castellano powered-by-Google diciéndole que vaya a piratasrus.com a cambiar la contraseña de Paypal o le cerramos la cuenta.



Fuente:

Autor: Antonio Manuel Amaya