La vulnerabilidad de elevación de privilegios de Xorg a examen

5 de noviembre de 2018
En un test de penetración, romper el perímetro y adentrarse tras las líneas enemigas es un hito importante, pero no es el último paso. Más allá de las puertas se encuentra la prueba real que separa al ocasional atacante con suerte del experimentado y curtido veterano: elevar privilegios, la obtención del uid cero, la joya de la corona del sistema, es decir, convertirse en root. Existen bastantes exploits para alcanzar esa cima, pero ni todos son válidos en todos los contextos ni siempre se posee el conocimiento para adaptarlos a una situación particular. De vez en cuando van apareciendo técnicas y scripts para facilitar esa tarea y solo muy de vez en cuando se nos presenta un ejemplar que hace de esta tarea un juego infantil. Hace unos días se liberó un parche para X.org, una de las implementaciones del protocolo X Window System para sistemas UNIX. Un servidor X (también X11), es el sistema sobre el que se sostiene el paradigma de escritorios y gestores de ventanas tales como GNOME o KDE. Orientado a red, se basa en el modelo cliente-servidor y proporciona conectividad no solo para el ambiente local de escritorio, sino para conexiones desde la red local o Internet. Antes de comentar el parche, cómo se ha solucionado y entender su impacto, vamos a comenzar por ver el " exploit":
cd /etc; Xorg -fp "root::16431:0:99999:7:::" -logfile shadow :1;su
Exacto. Eso de ahí arriba es un exploit de elevación local de privilegios. Acostumbrados a verlos en forma de código C mezclado con un conjunto de caracteres hexadecimales a la que llaman "shellcode", este one-liner es capaz de convertirnos en superusuario en poco más de 60 caracteres y sin necesidad de ser compilado. Como ya vimos en la vulnerabilidad de libssh y al igual que esta, no se trata de un error en la gestión de memoria, sino en un descuido al comprobar los permisos al crear un archivo designado para el registro de eventos. Un fallo complejo de descubrir. De hecho podría llevar oculto hasta dos años en el código fuente de X.org.
Cómo y por qué
Veamos, el binario correspondiente al servidor en sí de X.org, por ejemplo: /usr/bin/Xorg, tiene en algunos derivados de UNIX, el bit setuid activado. Eso significa que cuando el binario es ejecutado por un usuario raso tiene capacidad para realizar determinadas operaciones con los permisos de root. Algo tremendamente poderoso y cuyas repercusiones en un sistema, como podemos ver, deben ser cuidadosamente examinadas. En la cadena usada por el exploit, podemos ver cómo se le pasa un parámetro en particular a Xorg, "-logfile", con el valor "shadow". Básicamente le está diciendo que sobreescriba el archivo shadow (donde se encuentran los hashes de las contraseñas de los usuarios del sistema) y lo utilice como archivo de registro de eventos. El archivo no es sobreescrito sin más. La cadena que vemos a continuación de los parámetros ‘-fp’ (usada para indicar la ruta de búsqueda de tipos de fuente): "root::16431:0:99999:7:::" es una entrada dirigida para que se registre en el archivo shadow (designado intencionadamente por -logfile como registro de eventos) cuyo contenido es, usuario: root, sin contraseña, el valor 16431 es un valor cualquiera, en este caso es el equivalente a tiempo unix: 1/1/1970:4:33am. Este valor y los siguientes son parámetros para indicar hasta cuándo es válida la clave. Esa sobreescritura e inyección de la cadena nos deja un archivo shadow en el que el único usuario es root y este no posee contraseña. Por esto último, no es recomendable que se practique la prueba de concepto en un ambiente productivo o sin haber creado una copia de respaldo del archivo. Por cierto, en muchos UNIX suele existir el archivo "/etc/shadow-" con una copia más o menos reciente del contenido de "etc/shadow".
Elevación de privilegios alternativa a través de la carga de módulos
Durante el triaje del fallo, el personal de Red Hat descubrió un vector de ataque que explotaba el mismo error pero de forma alternativa, usando los módulos binarios de extensión de X.org. Además del parámetro "-logfile", también es posible reproducir la vulnerabilidad mediante otro parámetro: "-modulepath"; solo que de manera distinta. En vez de indicar que archivo sobreescribir para el registro de eventos, el parámetro "--modulepath" indica a Xorg dónde encontrar los módulos de este para cargar una funcionalidad determinada. Estos módulos son binarios a modo de extensión para el servidor X. Es posible compilar un módulo malicioso e indicar con la comentada opción desde donde cargarlo. Así, podríamos compilar un programa que simplemente ejecute una shell. Al ser ejecutado con permisos de root, Xorg cargaría el módulo y nos entregaría una shell con los privilegios de aquel.
El parche
El parche es muy simple. No restan o filtran la funcionalidad dentro de los parámetros afectados, simplemente, se limitan a restringir el uso de estos si no es root el usuario que los está invocando directamente (a pesar del setuid activado):
El chequeo que efectúa xf86PrivsElevated devuelve ‘true’ si no es root quien invoca desde consola a Xorg:
chequeo que efectúa xf86PrivsElevated imagen
El fallo fue descubierto por Narendra Shinde y se le ha asignado el CVE-2018-14665. Las versiones afectadas por el fallo comprenden desde la 1.19.0, que es la correspondiente a la versión en la que se introdujo la deficiencia, y la 1.20.3, ambas inclusive. Recordemos, no obstante, que el binario debe tener activado el bit "setuid" porque sin este bit no es posible sobreescribir "/etc/shadow". Precisamente, la contramedida de esta vulnerabilidad es cambiar los permisos y eliminar el setuid del binario Xorg. Si calculamos la franja de tiempo desde las versiones vulnerables, podremos comprobar como el error ha estado presente por dos años. Esto recuerda bastante, aunque desde luego no lo supera, al bug de X.org que estuvo latente durante nada más y nada menos que 27 años. Cómo pasa el tiempo...
David García Innovación y Laboratorio de ElevenPaths
david.garcianunez@telefonica.com