sábado, 13 de noviembre de 2010

C: Desbordamientos

Como bien he podido leer en uno de mis libros, "Un programa sólo puede hacer aquello para lo que está programado". Muchos programadores noveles echan la culpa de sus fallos al propio Ordenador, y es evidente que no siempre es así, pues es el propio programador el que ha escrito un código erróneo. Así que en esta entrada, voy a analizar un tipo de fallo muy dado hace unos años, que ahora con los lenguajes de programación de alto nivel, es un poco "Complicados" cometerlos pues la gestión de la memoria es automática; Voy a hablar sobre los Desbordamientos.

C es un lenguaje de programación de nivel Alto, pero que puede usarse a Bajo Nivel. El compilador no se encarga de controlar la integridad de los datos. Es por eso que el programador adquiere el control total sobre los datos. Y como todos somos humanos, puede contener fallos. Aquí hablamos de los desbordamientos de Buffer, el cual se produce cuando, por ejemplo, el contenido de una variable ocupa el "Sitio" de otra variable. Por ejemplo, un desbordamiento de Buffer sería asignar 10 bytes de información a una variable asignada con 8 bytes. Un desbordamiento de Buffer puede producir desde el mas mínimo cuelgue de un programa, hasta ser usado como Xploit para obtener un Shell remoto a nuestro Ordenador. Por este motivo son tan peligrosos.

Vamos a trabajar con el siguiente código de ejemplo.

//      desbordamiento.c

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    int value =5;
    char buffer_one[8], buffer_two[8];
   
    strcpy(buffer_one, "one");
    strcpy(buffer_two, "two");
   
    printf("[ANTES] buffer_two está en %p y contiene \'%s\'\n", buffer_two, buffer_two);
    printf("[ANTES] buffer_one está en %p y contiene \'%s\'\n", buffer_one, buffer_one);
    printf("[ANTES] value está en %p y es %d (0x%08x)\n", &value, value, value);
   
    printf("\n[STRCPY] copiando %d bytes dentro de buffer two\n\n", strlen(argv[1]));
    strcpy(buffer_two, argv[1]);
   
    printf("[DESPUÉS] buffer_two está en %p y contiene \'%s\'\n", buffer_two, buffer_two);
    printf("[DESPUÉS] buffer_one está en %p y contiene \'%s\'\n", buffer_one, buffer_one);
    printf("[DESPUÉS] value está en %p y es %d (0x%08x)\n", &value, value, value);   
   
    return 0;
}

Como vemos, tenemos 3 variables, una de tipo Entero y 2 tipo Cadena. Inicializamos las 3, y las mostramos por pantalla. Seguidamente, copiamos el valor por parámetro en la segunda variable y lo volvemos a mostrar todo de nuevo. Vamos a llamar al programa con un parámetro de 10 bytes (abcdefghij) y vamos a observar el resultado que nos da.

serch@serch-server:~$ ./a.out abcdefghij
[ANTES] buffer_two está en 0xbfbbdd8c y contiene 'two'
[ANTES] buffer_one está en 0xbfbbdd94 y contiene 'one'
[ANTES] value está en 0xbfbbdd88 y es 5 (0x00000005)

[STRCPY] copiando 10 bytes dentro de buffer two

[DESPUÉS] buffer_two está en 0xbfbbdd8c y contiene 'abcdefghij'
[DESPUÉS] buffer_one está en 0xbfbbdd94 y contiene 'ij'
[DESPUÉS] value está en 0xbfbbdd88 y es 5 (0x00000005)
serch@serch-server:~$
Como vemos, buffer_two se ha desbordado, y se han sobreescribido los bytes sobrantes en la siguiente variable, la cual era buffer_one. Si sobreescribimos mas zonas de memoria, podemos colgar el programa. Para demostrarlo, vamos a pasarle como parámetro 30 bytes de datos. (La salida que produce es bastante larga, os animo a probarlo en vuestros equipos).

La solución en el caso de ese código, es bastante sencilla: Podemos limitar la entrada de datos con un simple condicional, y para mas seguridad, en vez de usar strcpy(), podemos usar strncpy(), a la cual se pasa como parámetro el número de bytes a copiar de una cadena a otra.

Existen mas tipos de desbordamientos, como los desbordamientos de pila, de los cuales hablaré en alguna próxima entrada.
 
Adaptado de: Hacking: Técnicas fundamentales

No hay comentarios:

Publicar un comentario