Primero fue Apple con el goto fail, un fallo que permitía interceptar y descifrar tus conversaciones seguras. Después vino GnuTLS, una librería de SSL para Linux, con un fallo que daba por válidos todos los certificados de un tipo concreto. Por si no teníamos suficiente con eso, hoy tenemos otro fallo extremadamente grave (mucho peor que los anteriores) en la librería OpenSSL.
OpenSSL es una librería ampliamente usada en el mundo del desarrollo para implementar SSL/TLS. Por ejemplo, el servidor Apache la usa para establecer conexiones HTTPS sin tener que preocuparse de los detalles de implementación. Servidores de correo, chat o redes privadas virtuales (VPNs) son otros servicios que suelen usar esta librería.
Qué ha fallado
El fallo está en una función encargada de gestionar mensajes Heartbeat. Estos mensajes son llamados keep-alive: es una forma de decirle al servidor que sigues conectado y que no cierre la conexión. El mensaje que mandes puede tener una carga o contenidos (payload), como pueda ser la fecha en la que se ha enviado. El servidor recibe ese mensaje y responde al cliente con esa misma carga. Este tipo de esquema “te paso algo y me respondes con lo mismo” no es exclusivo de TLS: en los paquetes de ping, por ejemplo, también se pueden incluir datos para así calcular cuánto tarda el servidor en responder.
El cliente tiene que decir también qué longitud tiene esa carga, para que el servidor la pueda leer sin tener que adivinar dónde acaba. Y aquí es donde vienen los problemas. ¿Qué pasa si le digo al servidor que le estoy enviando mil bytes y en realidad sólo le estoy enviando uno?
Si habéis programado alguna vez en lenguajes de alto nivel, como Java, C# o JavaScript, pensaréis que eso fallará. Al fin y al cabo, estamos intentando acceder a cosas que no están ahí. Si mi paquete es una lista de bytes de longitud 10 y quiero leer el 20978, no tengo de dónde sacarlo y el programa debería pararse y reportar un fallo.
Pero OpenSSL está escrito en C, y en C las cosas no son tan felices. En este lenguaje, la variable“paquete” no es más que una dirección en la memoria RAM; por ejemplo, la 1076. El primer byte del paquete está en la posición 1076, el segundo en la 1077, el tercero en la 1078 y así sucesivamente.
Cuando se esté ejecutando un ataque, OpenSSL recibe un mensaje de longitud 10 (por ejemplo), que dice que tiene 200 bytes de carga y que almacena en la posición 1076. Cuando tenga que responder, empezará a copiar el byte 1076, el 1077, el 1078… así hasta el 1086. ¿Qué ocurre después? Fácil: OpenSSL sigue. A él le han dicho que hay 200 bytes (el código no verifica si la longitud que aparece en el paquete es incorrecta) y va a copiar sus 200 bytes. Es decir, seguirá leyendo y copiando hasta que llegue a la posición 1276.
¿Y qué hay en esas posiciones? Pues sorpresas. La reserva de memoria no es determinista así que puede haber absolutamente de todo. Quizás sólo hay basura, restos del paquete anterior – así es como se comprueba si un servidor es vulnerable – o la clave privada del servidor.
Repitiendo muchas veces el ataque – cada vez se pueden recuperar hasta 64 KB de la memoria del servidor – es probable que se acaben encontrando cosas de valor. Además, las estructuras más valiosas, como las claves privadas que comentábamos, son relativamente fáciles de encontrar cuando están guardadas en memoria. En resumen, es un fallo muy grave, una ventana abierta a los entresijos confidenciales de OpenSSL.
¿En qué me afecta a mí este fallo?
Vamos ahora a la parte práctica: en qué nos afecta esto a nosotros cómo usuarios. El fallo hace especialmente vulnerables a los servidores, así que en teoría no deberíamos preocuparnos, ¿no?
La realidad es que no. Heartbleed permite a los atacantes conseguir claves privadas de servidores, con las que podrían realizar ataques MITM. Repasemos HTTPS: si un atacante tiene la clave de Google (por ejemplo), podría montar un servidor que se hiciese pasar por legítimo de Google. Tu navegador se conectaría a él y no te darías cuenta, de tal forma que en lugar de enviar tus datos confidenciales (correos, contraseñas, usuarios…) a Google, lo harías al atacante. Fantástico, ¿verdad?
Estaríamos hablando de miles de servidores potencialmente comprometidos. La vulnerabilidad se introdujo hace dos años, y no se sabe si alguien la ha estado explotando en secreto antes de que sea publicada. De hecho, la recomendación es que se revoquen los certificados SSL y se distribuyan otros nuevos por si han sido comprometidos.
Estamos ante uno de los fallos más graves en SSL que se hayan visto.
¿Asusta? Pues todavía queda más. Hemos dicho que el fallo permite ver pedazos de la memoria del servidor. ¿Se puede ver algo más que las claves privadas? ¿Qué pasa si hay otros usuarios conectándose al servidor?
Lo que pasa es que se puede obtener información que permita robarles la sesión directamente. Los servidores de Yahoo!, por ejemplo, filtraban información de usuarios y contraseñas de sus propios usuarios. En texto plano. Sin ningún tipo de protección. Cualquiera podía ejecutar un comando en su ordenador y empezar a ver cómo aparecían contraseñas (ya han arreglado el fallo).
Entre la facilidad para explotar la vulnerabilidad, el número de servicios afectados y el hecho de que el ataque no deja rastros en los registros, este es uno de los fallos más graves que se hayan visto enSSL. Un verdadero caramelo para los black hat hackers. Por nuestro bien, más nos vale que este fallo no lo haya descubierto nadie antes.
¿Cuándo estará arreglado?
La corrección en OpenSSL ya está lista, y varias distribuciones de Linux tienen los paquetes listos para actualizar. La versión con el fallo corregido es OpenSSL 1.0.1g. Las versiones vulnerables van desde la 1.0.1 hasta la 1.0.1f (versiones anteriores no tenían Heartbeat implementado).
Servicios como Heroku, Amazon Web Services o Lastpass han anunciado la corrección del error en sus servidores. Podéis probar qué servidores son vulnerables con un simple test disponible en la web.