Vulnerabilidades escurridizas, invisibles en el código durante años

miércoles, 15 de enero de 2014

Hace poco se ha corregido una vulnerabilidad de desbordamiento de pila que afecta al servidor X11. Llevaba "escondida" en el código desde 1991, presente en muchas de las distribuciones Linux y permitiendo, para quien la conociese, elevar privilegios en el sistema afectado. ¿Existen otros casos de vulnerabilidades que han pasado desapercibidas durante años?

El caso X11

X11 es un servidor gráfico desarrollador por el MIT a mediados de los 80 que proporciona interfaz gráfica a los sistemas basados en UNIX. A principios de 2014, y usando una herramienta llamada cppcheck, se ha encontrado un desbordamiento de pila a la hora de procesar fuentes BDF con la librería libXfont. Básicamente, esto permite a un atacante local elevar privilegios a root haciendo que el sistema procese un tipo de letra especialmente manipulado. La sencillez del parche (que simplemente limita el tamaño) explica el problema. Se trata de un desbordamiento de pila "de libro").

-        if (sscanf((char *) line, "STARTCHAR %s", charName) != 1) {
+        if (sscanf((char *) line, "STARTCHAR %99s", charName) != 1) {
             bdfError("bad character name in BDF file\n");
             goto BAILOUT; /* bottom of function, free and return error */}

Página de descarga de cppcheck.sourceforge.net
X11, aun siendo un software extremadamente usado y popular, contuvo durante 23 años una vulnerabilidad, en principio, que parecía bastante sencilla de detectar por el ojo humano, pero que en realidad tuvo que se cazada con la ayuda de un programa automático.

Un caso Solaris

El  12 de febrero de 2007 se da a conocer una vulnerabilidad en (por aquel entonces) Sun Solaris 10 tan simple como sorprendente. El fallo permitía el acceso trivial como cualquier usuario (incluido root) a través de telnet. El error fue ya descubierto y corregido en sistemas UNIX en 1994, pero Solaris lo "reintrodujo"en sus sistemas en noviembre de 2002, con lo que pasó inadvertida durante unos 5 años. A través de un simple parámetro del cliente telnet ("-f", utilizado para traspasar las credenciales locales), se podía acceder a un servidor telnet en Sun Solaris 10 sin necesidad de autenticación. Sólo conociendo el nombre de usuario. El comando para "explotar" el fallo era:

telnet -l "-froot" [direccion_del_host]

El código del demonio telnet en Solaris 10 es abierto.

Un caso Oracle

El fallo CVE-2012-1675 en Oracle, reconocido por la compañía en abril de 2012, fue reportado en 2008 por Joxean Koret (@matalaz). Afectaba a todas las versiones de Oracle Database (desde 8i hasta la versión 11g R2). La vulnerabilidad permitiría controlar el tráfico cliente-servidor y modificarlo, a través de un ataque MITM. Aunque se reportó en 2012, la vulnerabilidad estaba en el código probablemente desde 1999. Además de la antiguedad del problema, Oracle protagonizó un episodio vergonzante en la gestión de parches. Koret, creyendo que había sido por fin solucionado, publicó todos los detalles. Haciendo gala de una respuesta totalmente absurda, Oracle respondió que en realidad "the vulnerability was fixed in future releases of the product", lo que no tenía sentido (fue corregida en futuras versiones).

Un caso Windows

A principios de 2007, todo el mundo hablaba de la vulnerabilidad de los Windows MetaFile (WMF) que supuso una pesadilla para Microsoft por muchas razones (se llegó a sacar un parche extraoficial por la comunidad, antes que la propia Microsoft). Era tan sencilla de explotar que Steve Gibson llegó a insinuar que podría ser intencionada, una puerta trasera incluida a propósito en el sistema operativo más famoso.

El fallo estaba basado en los registros de tipo META_ESCAPE, concretamente en el subcódigo SetAbortProc. En ella se deben especificar dos argumentos, uno que representarían el "Device Context" y el segundo sería una función a ejecutar ante un evento de cancelación de impresión. Controlarlos y ejecutar código era tan sencillo como enviarles los comandos adecuados. Stephen Toulouse escribió además en el blog oficial de Microsoft que el fallo estaba presente desde los tiempos de Windows 3.0, creado hacia 1990. SetAbortProc fue programada cuando la seguridad no representaban la mayor de las prioridades y fue introducida en los tiempos en los que procesar imágenes era lento y quizás fuese necesario abortar el proceso de impresión antes de que terminara, mucho antes incluso de que existiera el formato WMF. Aunque la funcionalidad fue perdiendo importancia, se fue portando junto con muchas otras, versión tras versión, en lenguaje ensamblador a los siguientes sistemas operativos que surgieron después. Se mantuvo por tanto unos 17 años en el código sin que nadie lo detectara. Ni siquiera los profesionales que se dedican a tiempo completo a encontrar fallos en Windows (que los hay).

¿Cómo puede ocurrir esto?

Los ejemplos expuestos son los más llamativos y escandalosos. Hay más ejemplos de todo tipo, en código abierto y cerrado. De hecho, todos los días se corrigen vulnerabilidades en sistemas operativos o programas que llevan años funcionando, y quizás las vulnerabilidades corregidas hoy llevan ahí ocultas desde que se usa ese sistema. Por ejemplo, muchas vulnerabilidades que se siguen encontrando en XP puede que estén ahí desde octubre de 2001, cuando fue sacado al mercado.

Las vulnerabilidades son inevitables, tanto en el diseño de programas como de protocolos. En este sentido, el fallo de Kaminsky en los DNS descubierto en 2008 es un buen ejemplo de un fallo de diseño que pasó desapercibido durante decenas de años, aun siendo un estándar completamente abierto aprobado en su teoría e implementado en la práctica por decenas de compañías.

istruecryptauditedyet.com
Poco parece que tenga que ver la eterna discusión sobre el código abierto o cerrado y las ventajas frente a la detección "temprana" de vulnerabilidades. Sin entrar en el aspecto filosófico del uso de software de código abierto, ¿en realidad resulta más sencillo encontrar vulnerabilidades en programas muy complejos de código abierto que en programas muy complejos de código cerrado? Un buen ejemplo es el caso TrueCrypt. Aunque sea de código abierto, sus usuarios necesitamos poder fiarnos totalmente de él, dada su importancia para proteger la confidencialidad. Pero para conseguirlo, se ha precisado de una campaña de recogida de fondos para (entre otras cosas) poder permitirse auditar su código, y premiar a los auditores que encuentren fallos en él. Llevan ya varios meses con el proyecto, y su sueño (porque no es fácil) sería realmente conseguir una auditoría completa de un código tan complejo como es cualquiera que trabaje con criptografía. Otro ejemplo de lo difícil que es auditar (o encontrar errores) en código en general y criptográfico en particular, es el desastre ocurrido en el demonio openSSL de Debian, que eliminó la entropía de creación de claves públicas y privadas en 2006. Nadie lo notó durante dos años.

Todo esto viene a recordar que de esos "miles de ojos" que pueden mirar el código, no son todos igual de efectivos... que algunos programas son más eficaces que el ojo humano, y que el hecho de que se permita mirar el código no significa que todo el mundo lo mire ni lo entienda realmente. El código abierto tiene muchas ventajas (prácticas y teóricas): en programas muy complejos una que sí se aprovecha en la práctica es que permite entender y mitigar (pero quizás no tanto detectar) las vulnerabilidades más rápidamente. Por supuesto, se puede argumentar que, si no fuese código abierto, no se hubiesen encontrado nunca estos fallos. Es posible. Defender uno u otro modelo es un asunto delicado para muchos. Lo que no hay que olvidar en cualquier caso es que auditar código desnudo es una tarea muy compleja que no puede ser delegada exclusivamente a programas. Necesita además del ojo humano, pero no cualquiera... no los "miles de ojos potenciales", sino de "pocos pero reales" que cuentan con gran experiencia, que son buenos programadores, profesionales, que saben interpretar correctamente los resultados de los programas automáticos de auditoría, que disponen de paciencia, tiempo... Y no se dedican todos estos recursos a todos los programas de código abierto (ni cerrado) "mágicamente". De hecho, lamentablemente, encontrar vulnerabilidades es una tarea a la que los atacantes profesionales parecen dedicar mucho más esfuerzo y empeño que cualquier comunidad o auditores y se centran en cualquier programa que les reportes beneficios, independientemente de la filosofía de código.

Sergio de los Santos
ssantos@11paths.com

No hay comentarios:

Publicar un comentario