miércoles, 3 de septiembre de 2014

Análisis de un 0-day de Buffer Overflow en BASH 4.3

Un día con tiempo, te pones a revisar código de diversas aplicaciones. Muchas veces vas con la idea de que no encontraras ninguna vulnerabilidad, pero claro, ningún código o programa es perfecto. ¿Qué pasaría si encuentras un 0 Day mientras te paseas por el código fuente de la ultima versión de alguna aplicación? Eso me paso a mi hace unos días, y en este artículo analizaré ese mismo 0 Day que encontré en la última versión disponible de BASH la 4.3 y explicaré un poco el proceso que seguí para crear un exploit en Linux.

1.- Creación del laboratorio

Voy a explicar todo el proceso que hice para saber que impacto tenia mi descubrimiento y como podría ser aprovechado si era posible. Nuestro entorno controlado será un pequeño “laboratorio” que utilizara: · VirtualBox + Guest Additions por mayor comodidad. En él instalé una imagen de Ubuntu Desktop 14.04.1 LTS arch:i386.


Figura 1: Instalación de Ubuntu 14.04 sobre Virtual Box en el laboratorio

Una vez configurada e instalada la imagen sobre VirtualBox, instalamos las Guest Additions para una mayor comodidad con el entorno. ¿Por que hacemos esto? Pues simplemente para que si se nos va de las manos, no salpique a nuestro sistema operativo de uso diario y así evitar posibles futuros problemas. 

2.- Descargar y analizar el código vulnerable

Para descargar la aplicación usaremos el comando apt-get o en su defecto aptitudepara descargar el código fuente mediante el uso del parámetro source de la siguiente manera: 


Figura 2: Descarga del código de fuente de bash con apt-get

Ahora ya podemos pasar a analizar el código vulnerable que esta alojado en la siguiente ruta: bash4.3ubuntu1.tar\bash-4.3\lib\sh\unicode.c linea 65: 

static char charsetbuf[40];


static char *stub_charset ()
{

char *locale, *s, *t;

 locale = get_locale_var ("LC_CTYPE");
if (locale == 0 || *locale == 0)
{

strcpy (charsetbuf, "ASCII");
return charsetbuf;
}
s = strrchr (locale, '.');
if (s)
{

strcpy (charsetbuf, s+1);
t = strchr (charsetbuf, '@');
if (t)
*t = 0;
return charsetbuf;
}
strcpy (charsetbuf, locale);
return charsetbuf;
}


Se puede observar una evidente vulnerabilidad en el tratamiento de las variablescharsetbuf y locale, y el bug puede reproducirse de la siguiente manera: Todo lo que se tienes que hacer es configurar LC_CTYPE o LC_ALL con un string muy largo pasando por la función de tratamiento de caracteres Unicode y usando printf. Con una simple linea se puede observar el desbordamiento:

$ bash -c "LC_CTYPE='$(printf %40s)' printf '\U876543210'"

Figura 3: Explotación del bug con bash -c "LC_CTYPE='$(printf %40s)' printf '\U876543210'"

Hay que tener en cuenta que esta vulnerabilidad solo esta presente en sistemas que no implementen locale_charset en libc/libintl/libiconv. 

3.- En busca del 'Program received signal'. 

Juguemos ahora un poco con los caracteres y observemos las diferentes salidas mediante una gran herramienta, GBD:

Program received signal SIGABRT, Aborted in 0xb7fdd424 in __kernel_vsyscall ()

Figura 4: SIGABRT mediante bash -c "LC_CTYPE='$(printf %40s)' printf '\U876543210'"
Program received signal SIGSEGV, Segmentation fault in __gconv_close (cd=cd@entry=0x0)

Figura 5: SIGSEGV mediante bash -c "LC_CTYPE='$(printf %40)' printf '\U876543210'"

Es curioso, que solo cambiando un carácter %40s a %40 salgan salidas distintas. En la primera salida pone __kernel_vsyscal, que para los que no lo sepan es el método utilizado por linux-gate.so, una parte del kernel de Linux, para hacer una llamada al sistema usando el método más rápido disponible, usa preferentemente la instrucción SYSENTER. En la segunda salida, en el archivo gconv_close.c en linea 35pertenece a una función encargada de abortar calls, y posteriormente liberar todos los recursos.

4.- Preparando y analizando el binario en nuestro entorno controlado.


Vamos a ver qué protecciones tiene este binario y qué podemos y qué no podemos hacer. Para ello, podemos usar checksec.sh para comprobar las implementaciones de seguridad que tiene este binario de fabrica.


Figura 6: chechsec.sh sobre el binario de Bash 4.3

Ahora vamos a comprobar si ASLR esta activado: 


Figura 7: Comprobación de estado de ASLR

Por ultimo comprobamos si tiene el SetUID o el SetGID activado: 


Figura 8: Comprobación de estado de SetUID y SetGID

A primera vista, el escenario de ataque sobre el que hay que trabajar a partir de ahora se queda con las siguientes implementaciones de seguridad:

Partial RELRO: GOT no modificable.
STACK CANARY(ProPolice): No hay nada que hacer..
NX: Stack no ejecutable.
ASLR: 'Random' Memory.
SETUID: No esta activo.
La pregunta que hay que hacerse a partir de este punto es ¿se puede hacer unbypass a estas protecciones? La respuesta es: , pero NO. Veamos por que:

5.- ¿Que implementaciones de seguridad nos 'molestan' realmente?

Tanto a NX como ASLR se les puede hacer un bypass mediante una técnica llamadaROP. Ahora veremos qué fácil es crear un payload en ROP de forma automática gracias a ROPgadget una gran herramienta que también nos permite hacer búsqueda de gadgets. 

Hay otras herramientas como ropeme la cual ofrece la búsqueda de gadgets en el binario y también la creación de payload de forma automática. Hay que destacar que estas dos grandes herramientas solo pueden generar payload de arquitecturasx86, veamos cómo.

Iniciamos ROPgadget con la opción '--ropchain' para que genere nuestro payloaddel binario bash.

$ python ROPgadget.py --ropchain --binary /bin/bash
Figura 9: ROPchain mediante ROPgadget

Teniendo esto, solo habría que guardarlo en un archivo *.py y cambiar el padding a:p = 'A' * 40 y ya tendríamos nuestro payload funcional. Se pueden dar algunas situaciones con las que tendríamos que lidiar:

- STACK CANARY o ProPolice nos frena en seco: una solución no perfecta es cambiar el valor de canary mediante un proceso hijo, y volverlas a cambiar por el valor canary original antes de que esta sea comprobada de nuevo si no, se detectaría un error. 

- RELRO nos implementa un nivel de seguridad más: Cuando el binario es ejecutado y trasladado a la memoria, se hace una llamada a Procedure Linkage Table o PLT que posteriormente hace un jmp a la GOT. Básicamente RELRO nos impide modificar GOT. 

6.- Conclusiones

Esto artículo quiere demostrar que no debemos confiar en ningún programa, porque nunca son 100% seguros, somos humanos y por tanto hacemos cosas imperfectas.

En este caso hemos visto un 0 Day, en concreto un Buffer Overflow en la ultima versión de BASH, la 4.3. Hemos seguido unos pasos para comprobar su protección, entender cómo funcionaba, y saber qué podríamos y qué no podríamos hacer.

Hemos visto que hacer un bypass de NX y ASRL no es demasiado complicado, queRELRO no nos molesta demasiado, y que STACK CANARY nos frena en seco toda la diversión. Además, aunque no hubiese estado, simplemente podríamos conseguir un ejecución de código arbitrario, pero no podríamos haber hecho un Privilege Escalation ni nada por el estilo ya que no esta el bit SetUID activado. 

En este caso, esta vulnerabilidad se 'salva' de ser completamente explotada debido aSTACK CANARY, pero hemos visto que el proceso de investigación es divertido y curioso. Solo nos faltaría informar a los encargados de seguridad de este proyecto, de forma responsable, y dejarles un tiempo para corregirla, en mi caso fueron avisados hace 2 semanas aproximadamente, y me dieron ya el consentimiento para hacer la divulgación publica. 

Espero que este articulo anime a personas jóvenes como yo, y no tan jóvenes a adentrarse en el mundo de la seguridad informática y el exploiting de Linux. Un saludo muy grande de un chico de 16 años que a veces piensa.



No hay comentarios:

Publicar un comentario