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

Responder a