From: feedblas...@hcg.sld.cu Date: Wed, 28 Jan 2015 23:01:37 -0500 To: laz...@hcg.sld.cu X-Mailer: feedblaster.rb - ruby 2.2.0p0 (2014-12-25 revision 49005) [i686-linux] Subject: GetRootByGetHostByName [Hispasec @unaaldia]
Todas las distribuciones Linux que usen la librería glibc (y eglibc) versión 2.17 y anteriores son virtualmente vulnerables. ¿Cómo comprobar la versión? ldd print | grep libc.so o directamente ejecutando la librería en la línea de comandos. Sí, puedes ejecutar una librería en Linux. En el caso de libc esta dispone de un punto de entrada hacia __libc_main donde llama a __libc_print_version que no hace otra cosa que imprimir cierta información en formato humano sobre su compilación. /lib/i386-linux-gnu$ ./libc.so.6 GNU C Library (Ubuntu EGLIBC 2.19-0ubuntu6.5) stable release version 2.19, by Roland McGrath et al. Copyright (C) 2014 Free Software Foundation, Inc. Evidentemente también puedes verificar la versión instalada buscando su paquete correspondiente, pero esto va a variar en función de la distribución usada. Al grano. El fallo reside en la función '__nss_hostname_digits_dots', definida en el archivo 'gnu/glibc/nss/digits_dots.c'. Esta función es usada por un grupo de funciones de la familia 'gethostbyname' (de ahí el GHOST) y su cometido es comprobar si la cadena que se ha pasado a 'gethostbyname' es una IP. De esta forma el sistema se ahorra una consulta DNS. Básicamente es como si intentases resolver una IP (no una resolución inversa, ojo), algo que carece de sentido. Vamos a recorrer la vulnerabilidad al revés, el fallo podemos verlos en la línea 157 del código de 'digits_dots.c' (sin el parche): (157) resbuf->h_name = strcpy (hostname, name); Ya de entrada el uso de 'strcpy' debería resultar sospechoso, básicamente porque no hace ninguna comprobación sobre los límites del búfer de destino y terminará sobrescribiendo "hostname" hasta que encuentre el carácter '\0' en " name". Vemos de donde viene el cálculo del tamaño de "hostname". (125) hostname = (char *) h_alias_ptr + sizeof (*h_alias_ptr); 'h_alias_ptr' es: (124) h_alias_ptr = (char **) ((char *) h_addr_ptrs + sizeof (*h_addr_ptrs)); nuevamente, a su vez, 'h_alias_ptrs' es: (122-123) h_addr_ptrs = (host_addr_list_t *) ((char *) host_addr + sizeof (*host_addr)); seguimos, 'host_addr' es un simple casting a 'buffer': (121) host_addr = (host_addr_t *) *buffer; 'buffer' es donde se ha pasado el puntero que apunta al bloque de memoria reservado en 'new_buf': (116) *buffer = new_buf; Ya queda poco. 'new_buf' es donde está recogido el comienzo de la memoria reservada: (101) *buffer_size = size_needed; (102) new_buf = (char *) realloc (*buffer, *buffer_size); Como podemos ver el tamaño viene definido por 'buffer_size'que es definido más arriba, teniendo en cuenta el tamaño de 'host_addr', 'h_addr_ptrs' y 'name'. (85-86) size_needed = (sizeof (*host_addr) + sizeof (*h_addr_ptrs) + strlen (name) + 1); Pero, ay, cuando se calcula el tamaño se hace con la intención de que en ' buffer' se guarden cuatro objetos, dejando un cuarto fuera del cálculo del tamaño de memoria a reservar: 'h_alias_ptr'. Esta variable es un puntero a char. Luego la función 'strcpy' va a sobrescribir el tamaño, dependiente de la arquitectura, de un puntero a char. 4 bytes, típicamente, en arquitecturas de 32 bits, 8 bytes en las de 64 bits. Esta es la cabecera de la función '__nss_hostname_digits_dots': int __nss_hostname_digits_dots (const char *name, struct hostent *resbuf, char **buffer, size_t *buffer_size, size_t buflen, struct hostent **result, enum nss_status *status, int af, int *h_errnop) 'name' es el parámetro que puede controlar el atacante. Cuando el servidor a la escucha necesite efectuar una llamada a 'gethostbyname' para resolver un nombre de dominio, es ahí donde comenzará la explotación. Curiosamente, como apuntan en el anuncio de seguridad de Qualys, llegar a la línea donde se produce el desbordamiento es un camino lleno de obstáculos debido a la comprobación de ciertos valores en la cadena donde se supone que está el nombre del host. Todo un desafío para escribir un exploit. Consideraciones La librería 'libc' es omnipresente en todos los sistemas Linux, incluidos sistemas empotrados. Prácticamente casi todo el software nativo y no nativo hace uso de 'libc'. Eso convertiría en virtualmente vulnerable a casi todos los programas que hagan uso del grupo de funciones 'gethostbyname'. La salvedad es la forma en la que se hace uso de dichas funciones y más en el procesamiento previo que se efectúa sobre el nombre de host. Luego no todo es vulnerable, hay muchos condicionantes a tener en cuenta. Curiosamente, este fallo ya fue parcheado en mayo de 2013, en la versión 2.18 de glibc, aunque en aquel momento no se llegó a tener en cuenta la " militarización" del error. Si vemos el parche aplicado en su día: size_needed = (sizeof (*host_addr) + sizeof (*h_addr_ptrs) + sizeof (*h_alias_ptr) + strlen (name) + 1); Comprobamos como se ha añadido el elemento faltante: 'h_alias_ptr'. Bug neutralizado. Muchas distribuciones Linux ya contienen una versión corregida de este fallo desde entonces, 2013 y sin saberlo. Pero no es suficiente, ahora mismo, ahí afuera, hay cientos de miles de servicios que podrían estar a tres paquetes TCP de volar por los aires. La vulnerabilidad está presente desde 2000. Una calma que precede a la tempestad. Arriad velas, atrincad la carga y preparémonos para el impacto cuando publiquen los exploits. -- Este mensaje ha sido analizado por MailScanner en busca de virus y otros contenidos peligrosos, y se considera que est� limpio.
______________________________________________________________________ Lista de correos del Grupo de Usuarios de Tecnologías Libres de Cuba. Gutl-l@jovenclub.cu https://listas.jovenclub.cu/cgi-bin/mailman/listinfo/gutl-l