Este documento explica de qué trata un ataque de desbordamineto de buffer y como protegerse de este tipo de ataques con la herramienta libsafe. También se hace un repaso al funcionamiento de libsafe, cómo instalarlo, configurarlo y un breve ejemplo de su efectividad a través de un ejemplo práctico mediante un exploit.
Comentarios:
La Desbordamiento de Pila o Stack Overflow es posiblemente el tipo de ataque más común, puede ejecutarse sobre cualquier programa que no se haya programado correctamente, lo que que todos los programas sean objetivos potenciales. Si pudiésemos controlar los programas y evitar desbordamientos de sus pilas no solo evitamos los ataques de stack overflow descubiertos sino también los futuros. Y eso es lo que hace libsafe, detectar y tratar este tipo de exploits. Todo ello de forma invisible a los programas y a los usuarios.
Una de las formas más comunes de tomar el control de una máquina ilegalmente es ejectuar un ataque de "Desbordamiento de Pila" (Stack Overflow), este tipo de ataque intenta que un programa normal y corriente ejecute otro proceso mediante la desbordamiento de la pila. A grosso modo este tipo de ataques buscan errores de programación escribiendo datos no intencionados en la parte de la memoria del programa, si este programa no protege su pila de memoria un proceso atacante puede sobreescribirla y si consigue sobreescribir la dirección de retorno con una dirección de un segundo programa este segundo programa se ejecutará. Si el programa defectuoso es por ejemplo un servidor FTP y este está ejecutándose con permisos de root, un atacante puede sobreescribir la pila del servidor FTP y ejecutar un intérprete de comandos (bash por ej.) o cualquier otro proceso con los mismos derechos que el servidor FTP en este caso root, tomándo el control de la máquina.
Los programas 'inseguros' usan funciones como pueden ser: strcpy, strcat, getwd, gets, scanf, realpath y spritnf. Éstas funciones copian información a las variables del progarama pero no controlan que lo que se copia es mayor al tamaño de la variable. Estas funciones son muy usadas por los programadores, y hacen que el programa sea inseguro. Si se ejecuta una de estas funciones y puede copiarse esta información ...
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
... en una direción de retorno sin estar protegidos por libsafe, se ejecutará /bin/sh.
Es por eso que es realmente importante protegerse de estos ataques y eso es lo que hace la herramienta libsafe.
Libsafe es una librería que se carga dinámicamente en el kernel. Libsafe está basado en un software que intercepta todas las llamadas hechas a funciones que pueden ser vulnerables, al interceptar las llamadas las substituye de manera que tengan la misma funcionalidad pero que no puedan hacer ningún ataque a la pila, de manera que no puedan sobreescribir ninguna dirección de retorno para redirigir el flujo del programa que se esté ejecutando.
Este programa trabaja con programas binarios ya existentes, lo que significa que no es necesario modificarlos. Eso hace que sea independiente y que proteja a todo el sistema de manera transparente al usuario.
Los pasos de libsafe son los siguientes: intercepta una llamada a una función vulnerable y ejecuta su propia versión. Determina si puede ejecutarse de forma segura, en caso de no ser así libsafe termina la ejecución de la función y crea una alerta, todo esto según se haya configurado.
Advertencia! libsafe no funcionará correctamente en dos situaciones: no soporta libc5 ni tampoco si se compila usando -fomit-frame-pointer.
Debido a la forma de interceptar las llamadas los programas que se ejecuten a través de libsafe tienen que estar compilados con libc6, sino dará un segmentation fault. Para saber con qué se ha linkado un porgrama podemos usar la herramienta ldd sobre el programa que queramos averiguar de la siguiente manera:
# ldd /sbin/init
libc.so.6 => /lib/libc.so.6 (0x4001d000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
En este caso /sbin/init está compilado con libc.so.6, es decir que este programa soportará libsafe. Si no es así
debemos recompilar el programa con libc6 o bien añadir el programa al fichero /etc/libsafe.exclude como se explica más adelante.
La segunda situación donde no funciona libsafe es si el programa se ha compilado con la opción gcc -fomit-frame-pointer, ya que al compilarlo de esta
manera libsafe no puede controlar correctamente el tamaño del frame, y no sabe si se está saltando fuera del frame. Pero esta opción de compilación es extraña,
así que la mayoría de programas que nos interesa (servidores principalmente). Y en el caso de no ser así el programa libsafe simplemente no busca si hay violaciones,
es decir no modificará el funcionamiento del programa.
La instalación de libsafe es sencilla. Primero deberemos bajarnos la última versión del programa de la página de Avaya. Actualmente se trata de la versión 2.0-16. Y seguiremos los siguientes pasos:
$ cd /usr/src $ wget http://www.research.avayalabs.com/project/libsafe/src/libsafe-2.0-16.tgz $ tar xvzf libsafe-2.0-16.tgz $ cd libsafe-2.0-16 $ make gcc -M util.c intercept.c > dep gcc -c -o util.o -O2 -Wall ... ... ... $ su # make install cd src; make install ... ...
Para hacer el make install es necesario tener permisos de root, ya que copiara la librería libsafe.so en /lib, igual que instala las páginas de ayuda man, ejecuta /sbin/ldconfig que es necesario tras instalar nuevas librerías y nos preguntará si queremos que se ejecute libsafe para todos los procesos, mejor responder que no así tenemos la posibilidad de configurarlo como deseemos.
Ahora que ya está instalado se puede configurar de dos maneras: una para que se cargue por defecto al arrancar el sistema y otra mediante una variable de entorno.
# echo "LD_PRELOAD=libsafe.so.2" >> /etc/bash.bashrc # echo "export LD_PRELOAD" >> /etc/bash.bashrc # echo "setenv LD_PRELOAD libsafe.so.2" >> /etc/csh.cshrc
# echo "/lib/libsafe.so.2" >> /etc/ld.so.preload
Para evitar que un programa pase por libsafe debemos añadir el programa con path completo a /etc/libsafe.exclude, en cada línea un programa diferente. Esta opción puede sernos útil si tenemos algún programa que esté compilado con libc5 o bien que desborda la pila intencionadamente (poca utilidad en un servidor, pero es posible). Debido a lo que esto implica /etc/libsafe.exclude solo debería poderse modificar por root.
Si deseamos configurar libsafe para que nos notifique una violación de la pila con un email, debemos modificar el Makefile y añadir a los CFLAGS la opción -DNOTIFY_WITH_EMAIL. Y lo hacemos de la siguiente manera:
$ cd src/ $ vim Makefile CCFLAGS = -O2 -Wall -fPIC ....Modificar a:
CCFLAGS = -O2 -Wall -fPIC .... -DNOTIFY_WITH_EMAIL
Una vez configurado podemos pasar a ver un ejemplo de uso, de esta manera podremos identificar los intentos de desbordamiento de pila que se hayan ejecutado a nuestro sistema.
Una vez configurado libsafe pasemos a ver un ejemplo práctico de un exploit antes y después de instalar libsafe. A modo de ejemplo usaremos el programa t1.c, incluido en el directorio exploits con el que viene libsafe. Este programa busca una dirección de retorno y desborda la pila copiando un puntero para ejecutar el intérprete de órdenes (shell en inglés) de /bin/sh. Probar el exploit antes de instalar libsafe y nos mostrará lo siguiente:
[carlosm:~/exploits]$ gcc -o test_exploit t1.c [carlosm:~/exploits]$ ./test_exploit This program tries to use strcpy() to overflow the buffer. If you get a /bin/sh prompt, then the exploit has worked. Press any key to continue... sh-2.04$
El exploit ha tenido éxito: ha ejecutado /bin/sh, de esta manera el atacante tiene oportunidad de abrir un shell con los permisos del propietario del fichero.
Para protegerse deberemos tener instalado libsafe y después activarlo. Para activarlo seguir los pasos antes comentados, pero en este ejemplo usaremos las variables de entorno:
$ LD_PRELOAD=libsafe.so.2 $ export LD_PRELOAD $ ./test_exploit This program tries to use strcpy() to overflow the buffer. If you get a /bin/sh prompt, then the exploit has worked. Press any key to continue... Libsafe version 2.0.16 Detected an attempt to write across stack boundary. Terminating /home/carlosm/exploits/test_exploit. uid=1000 euid=1000 pid=4294 Call stack: 0x400169b0 /lib/libsafe.so.2.0.16 0x40016ad4 /lib/libsafe.so.2.0.16 0x80485fc /home/carlosm/exploits/test_exploit 0x8048612 /home/carlosm/exploits/test_exploit 0x4003c14a /lib/libc-2.2.5.so Overflow caused by strcpy() Killed $
Hemos visto como ha evitado el desbordamiento de la pila de manera exitosa. Otra cuestión importante es ver en los logs si ha habido algún intento de desbordamiento. Este paso es muy importante ya que si no se ha configurado el programa para que envie emails de alerta la única manera de saber si ha habido un intento de ataque es a través de los ficheros de log.
Bajo Debian las alertas van al fichero /var/log/auth.log y esta es la alerta que nos ha dado libsafe al ejecutar el exploit anterior:
libsafe.so[4294]: Libsafe version 2.0.16 libsafe.so[4294]: Detected an attempt to write across stack boundary. libsafe.so[4294]: Terminating /home/carlosm/exploits/test_exploit. libsafe.so[4294]: uid=1000 euid=1000 pid=4294 libsafe.so[4294]: Call stack: libsafe.so[4294]: 0x400169b0 /lib/libsafe.so.2.0.16 libsafe.so[4294]: 0x40016ad4 /lib/libsafe.so.2.0.16 libsafe.so[4294]: 0x80485fc /home/carlosm/exploits/test_exploit libsafe.so[4294]: 0x8048612 /home/carlosm/exploits/test_exploit libsafe.so[4294]: 0x4003c14a /lib/libc-2.2.5.so libsafe.so[4294]: Overflow caused by strcpy()
libsafe es una herramienta muy pontente disponible para GNU/Linux con licencia GPL, que nos evitará ataques de desbordamiento de pila. La instalación es sencilla y su funcionamiento es efectivo. Y es efectivo no solo para los ataques de desbordamiento de pila conocidos, sino también para ataques futuros todavía desconocidos. Es a la vez un detector de intrusiones y una forma de seguridad activa en la misma herramienta. Así que añadamos esta herramienta en la política de seguridad y dispongámonos a instalar libsafe en todas las máquinas Linux que dispongamos en producción.
Todos los comentarios/sugerencias/ideas/críticas mejoran esta documentación y por consiguiente tus conocimientos: