jueves, 24 de marzo de 2011

Evitar Buffer Overflows

En seguridad informática y programación, un desbordamiento de buffer (del inglés buffer overflow o buffer overrun) es un error de software que se produce cuando un programa no controla adecuadamente la cantidad de datos que se copian sobre un área de memoria reservada a tal efecto (buffer), de forma que si dicha cantidad es superior a la capacidad preasignada los bytes sobrantes se almacenan en zonas de memoria adyacentes, sobrescribiendo su contenido original. Esto constituye un fallo de programación.

Buffer Overflows son una fuente muy fertil de bugs y ataques maliciosos (xploits).
Protegernos de este tipo de ataques no es facil pero podemos hacer difícil a un atacante.

Un ejemplo de un Buffer Overflow podemos encontrarlo aqui , en el enlace nos explica que un atacante podría producir una denegacion de servicio mediante un fallo en el programa wireshark.


Para poder entender los buffer overflows, es necesario conocer cómo se dividen los programas en la memoria. Estos se dividen en varias secciones, y las 6 más importantes son las siguientes:

- .text: contiene las instrucciones del programa, es decir, la parte ejecutable. El tamaño de esta sección es fijada en tiempo de ejecución, cuando se carga el proceso.

- .data: se utiliza para almacenar variables globales inicializadas (por ejemplo: int enData = 0;). Esta sección también es fija en tiempo de ejecución.

- .bss (below stack section): contiene las variables globales no inicializadas, como por ejemplo: int enbss;. El tamaño es fijado en tiempo de ejecución.

- Heap: esta sección se usa para almacenar variables alocadas dinámicamente y crece desde las direcciones de memoria más bajas hacia las más altas. La alocación se controla mediante las funciones malloc() y free(). Un ejemplo de variable alocada en tiempo de ejecución sería una declarada así: int dinamica = malloc(sizeof(int));

- stack: esta es la conocida pila. La sección de la pila permite guardar datos entre llamadas a funciones y crece desde las direcciones altas de memoria hacia las direcciones bajas. Esta forma de crecimiento es la que permite buffer overflows.

- entorno/argumentos: se usa para almacenar una copia de las variables a nivel sistema que pueden ser requeridas por el proceso durante su ejecución. Como ejemplo, alguna de estas variables son el path, nombre del shell, hostname, etc. Esta sección es escribible, permitiendo exploits del tipo format string y buffer overflows.

Tipos de buffer overflow

Básicamente los buffer overflow pueden ser de dos tipos, stack based o heap based.
Para entender los ataques stack based overflow, necesito explicar un poco de lo que sucede cuando llamamos a una función en un programa. En una llamada a función, sucede lo siguiente:
- se colocan los parámetros pasados a la función dentro de la pila, en orden inverso.
- se salva el registro que indica la dirección de la próxima instrucción (eip) dentro de la pila. Esta será la dirección de retorno.
- se ejecuta el comando call y la dirección de la función llamada se coloca dentro de eip.
La función recién llamada debe encargarse de lo siguiente:
- salvar el valor del registro que indica la base de la pila de la función anterior (ebp).
- colocar el valor de esp (registro que apunta al tope de la pila) en ebp. Con esto se setea la base de la pila de la función llamada.
- decrementar esp para hacer espacio para las variables locales de la función llamada. Cabe destacar que la pila crece en dirección contraria a las direcciones de memoria, por eso se decrementa en lugar de aumentar.
- se ejecuta la función
Una vez que la ejecución de la función se completa, sucede lo siguiente:
- se coloca el valor de ebp en esp (limpiamos la pila actual).
- se saca el valor de la pila actual y se coloca en ebp (restauramos la pila de la función llamadora).
- se saca de la pila el valor de retorno y se coloca en eip. Con esto (si todo sale bien) volvemos a donde se quedó la función anterior antes de llamar a la actual.

Los exploits stack-based utilizan las variables almacenadas en la pila para explotar un programa, sobreescribiendo la dirección de retorno de una función (almacenada en la pila), ya sea para llamar a un código insertado por el atacante o bien para llamar alguna función de librería que realice una función particular (el llamado return to libc attack).

Como protegernos 

Mantener un sistema actualizado en todo momento. Desactivar aquellos servicios que no utilicemos.

Montar en modo solo lectura (ro) nuestra particion /usr y montar las particiones /home, /tmp y /var con las opciones noexec,nosuid,nodev, (editando el fichero /etc/fstab). Previamente tenemos que tener nuestro sistema operativo particionado.

Evitar utilizar programas que son conocidos por ser muy inseguros, se pueden encontras en internet mucha informacion de cuales son. Un buen modo de desinstalar este tipo de programas es instalar los siguientes programas:

  • harden-clients - Evite a los clientes que se sabe que son inseguros
  • harden-development - Herramientas de desarrollo para la creación de programas más seguros.
  • harden-doc - Documentación útil para asegurar un sistema Debian
  • harden-environment - Entorno de sistema Hardened.
  • harden-remoteaudit - Audite sus sistemas remotos desde su anfitrión.
  • harden-servers - Evita servidores que se saben inseguros.
  • harden-surveillance - Comprueba servicios o servidores automáticamente.
  • harden-tools - Herramientas para mejora o analizar la seguridad de un sistema local.
 Estos programas lo unico que hacen es crear conflictos con los programas que son inseguros de forma que si tenemos uno de estos programas instalados, apt-get nos informará que hay un conflicto y que debe desinstalar ese servicio inseguro.

Instalar un IDS como Snort, un atacante tratará de buscar que servicios corren por la maquina y por tanto cuales pueden ser explotados.

Configurar Selinux es una buena opcion para evitar la mayor parte de estos ataques, el problema con Selinux es la dificultad. Realmente no es facil configurarlo y mucho menos entenderlo.

Todos estos sistemas no son infalibles pero se lo pondremos dificil a un atacante.

Fuentes:

http://itfreekzone.blogspot.com/2010/12/protecciones-contra-buffer-overflows-en.html

No hay comentarios:

Publicar un comentario