Búsqueda de Ciberamenazas

GnuTLS parchea un error de gestión de la memoria ¡actualiza ya!

La biblioteca criptográfica de código abierto más conocida es, casi con toda seguridad, OpenSSL.

En primer lugar, es una de las más utilizadas, hasta el punto de que la mayoría de los desarrolladores de la mayoría de las plataformas han oído hablar de ella aunque no la hayan utilizado directamente.

En segundo lugar, es probablemente la más conocida, tristemente debido a la vulnerabilidad Heartbleed que se descubrió hace más de ocho años.

A pesar de que se parcheo rápidamente (y a pesar de que existían soluciones fiables para los desarrolladores que no podían o no querían actualizar rápidamente sus versiones vulnerables de OpenSSL), Heartbleed sigue siendo una especie de “escaparate” de fallos, entre otras cosas porque fue uno de los primeros fallos que sus descubridores convirtieron en un agresivo vehículo de relaciones públicas.

Con un nombre impresionante, un logotipo propio y un sitio web dedicado, Heartbleed se convirtió rápidamente en una superhistoria de la ciberseguridad mundial y, para bien o para mal, quedó inextricablemente ligado a OpenSSL, como si el peligro del fallo siguiera vivo incluso después de haber sido extirpado del código.

La vida más allá de OpenSSL

Pero hay otras bibliotecas criptográficas de código abierto muy populares, en particular la NSS (abreviatura de Network Security Services) de Mozilla y la biblioteca GnuTLS del proyecto GNU.

Resulta que GnuTLS acaba de parchear un fallo conocido como CVE-2022-2509, del que se informa en el aviso de seguridad del proyecto GNUTLS-SA-2022-07-07.

Este parche corrige un error de gestión de memoria conocido como de doble liberación.

¿Qué es una vulnerabilidad de doble liberación?

En pocas palabras, una vulnerabilidad doble liberación se crea cuando un programador pide al sistema operativo que asigne un bloque de memoria para usarlo temporalmente y lo devuelve para que sea eliminado de la lista de bloques prestados para su uso por otras partes del programa y luego accidentalmente le pide al sistema que libere el mismo bloque de memoria de nuevo.

En el mejor de los casos, el software de asignación de memoria detectará que el bloque ya no pertenece a la parte del programa que lo está “devolviendo”, se dará cuenta de que el bloque infractor ya ha sido reciclado y no lo desasignará por segunda vez, evitando así los riesgos de “liberarlo” de nuevo.

Gestionar con cuidado una doble liberación que se detecta proactivamente es un asunto complicado. El prototipo de la función C que devuelve la memoria es void free(void *ptr); de modo que se pasa la dirección de un bloque que se quiere liberar, pero no se obtiene un código de retorno. (Una función C con un valor de retorno nulo es lo que otros lenguajes de programación llaman procedimiento: hace algo por tí, pero no tiene forma de informar un resultado). Por lo tanto, incluso el código C cuidadosamente escrito no tiene una forma estándar de detectar que algo salió mal en free(), y por lo tanto no hay forma de manejar el error de una manera exitosa. Terminar el programa infractor unilateralmente es la única solución segura para el sistema.

Pero si el asignador de memoria no se da cuenta (quizás porque ese mismo bloque ha sido entregado a otra parte del mismo programa, por lo que vuelve a estar en la lista de “prestados” exactamente igual que antes), entonces es probable que ocurran cosas malas.

En particular, el gestor de memoria podría “confiscar” inadvertida e inesperadamente el bloque doblemente liberado del código que ahora lo está utilizando legítimamente, y reasignarlo a otra parte del programa, tal vez incluso a un código malicioso que un atacante ha programado cuidadosamente para aprovecharse de la mala gestión.

Así, podrías acabar con dos partes del mismo programa manipulando el mismo sector de memoria.

Una parte del programa asume que puede confiar en el contenido de la memoria implícitamente, porque se considera el “propietario” legítimo del bloque.

Al mismo tiempo, otra parte del programa sabe que puede manipular los datos (o puede engañar para que los manipule) con el fin de engañar a la primera parte deliberadamente.

Hacer lo incorrecto hace lo correcto

Irónicamente, el fallo CVE-2022-2509 existe en el código de verificación de certificados en GnuTLS.

(La ironía, en caso de que te lo estés preguntando, es que el software que es inseguro en general porque no se molesta en comprobar las conexiones TLS de confianza es inmune a este fallo de seguridad específico).

Por ejemplo, cuando visitas un sitio web (u otro tipo de servidor) que está protegido con TLS, el otro extremo suele enviarte un certificado web que afirma que el servidor realmente es propiedad de la organización que esperas y está operado por ella.

Por supuesto, dado que cualquiera puede crear un certificado con el nombre que quiera, un certificado en bruto por sí solo no dice mucho, así que el propietario del certificado suele hacerlo firmar digitalmente por una empresa en la que su navegador ya confía.

En la práctica, los certificados suelen estar firmados por un certificado que, a su vez, está firmado por un certificado en el que confía tu navegador, pero el resultado final es lo que se denomina una cadena de confianza que puede ser rastreada de forma segura hasta un certificado que ya está instalado en una lista de las llamadas Autoridades de Confianza, también conocidas como Roots, que está gestionada por tu navegador o tu sistema operativo.

Para simplificar y agilizar el proceso de validación de la cadena de certificados, muchos servidores no se limitan a enviar su propio certificado y dejan que el navegador “persiga la cadena” hasta una raíz de confianza.

El servidor suele incluir la cadena de confianza en la que se basa, que sólo tiene que construir una vez, de modo que el navegador, o cualquier software que verifique el certificado, puede simplemente comprobar que la cadena es digitalmente válida, y luego verificar que el último certificado de la cadena coincide con uno que ya es de confianza.

En ese caso, GnuTLS validará correctamente y de forma segura el certificado suministrado, antes de liberar el bloque de memoria que se acaba de utilizar para almacenarlo.

Pero si el otro extremo no proporciona una cadena de certificados pregenerada, dejando que GnuTLS cree y compruebe la cadena por sí mismo, entonces el código de GnuTLS libera accidentalmente la memoria utilizada para almacenar el certificado suministrado antes de iniciar el proceso de comprobación de la cadena y luego la libera de nuevo después de que la comprobación se haya completado.

Esto provoca un error de doble liberación, que podría llevar a la corrupción de la memoria, seguida de un fallo del programa.

Cómo guiar un fallo para implantar un malware

Normalmente, o al menos a menudo, los fallos provocan un comportamiento tan distinto que el sistema operativo detecta que el programa infractor ha perdido el control del flujo de ejecución del programa, por ejemplo, si el programa salta a una dirección de memoria aleatoria e intenta ejecutar código desde un bloque de memoria que no ha sido asignado en absoluto.

En este caso, el fallo provocaría un error del sistema, y aunque este tipo de error podría ser abusado para lo que se llama un ataque de denegación de servicio (DoS), donde el objetivo es simplemente interrumpir el programa que está siendo atacado, no conduce a la ejecución remota de código (RCE), donde el código de software no confiable y no deseado se ejecuta.

Pero siempre que hay un fallo de programa que los atacantes pueden provocar a voluntad, basándose en datos no fiables que ellos mismos han suministrado, existe el riesgo de que el fallo pueda ser guiado de tal manera que desvíe el programa que se bloquea para que salte a un código ejecutable proporcionado por los atacantes.

Como te puedes imaginar, los atacantes a menudo pueden explotar tales vulnerabilidades para implantar malware, ya sea temporal o permanentemente, dado que consiguen inyectar código no fiable en tu ordenador sin que salte ningún aviso o ventana pidiendo permiso.

¿Qué hacer?

Actualiza a la última versión de GnuTLS, que es la 3.7.7 en el momento de escribir este artículo.

(Este fallo se introdujo aparentemente en GnuTLS 3.6.0, y existe en todas las versiones desde entonces, hasta la 3.7.6 inclusive).

Ten en cuenta que muchas aplicaciones populares y conjuntos de herramientas de programación incluyen o pueden ser construidos para hacer uso de GnuTLS, aunque no sea conscientes de ello, incluyendo pero no limitado a: FFmpeg, GnuPG, Mplayer, QEMU, Rdesktop, Samba, Wget, Wireshark y Zlib.

Muchos paquetes de Linux o *BSD que utilizan GnuTLS dependerán de una versión central gestionada por la propia distro, así que asegúrate de actualizar tan pronto como su distro tenga esta versión disponible.

Dejar un comentario

Your email address will not be published. Required fields are marked *