domingo, 17 de junio de 2007

Heap Overflow

El heap overflow es un tipo de buffer overflow que se produce en un area de memoria denominada heap. La memoria heap se reserva dinamicamente con funciones como por ejemplo malloc() y puede ser sobreescrita de forma similar a la que se produce en los buffer overflow, es decir, en situaciones en las que el programador no verifica correctamente el tamaño de los datos que copia. Veamos un ejemplo sencillo de heap overflow.

int main(int argc, char *argv[])
{
char *user = malloc(64);
char *pass = malloc(64);
int *login_ok = malloc(sizeof(int));
*login_ok=0;

strncpy(user, argv[1], strlen(argv[1]));
strncpy(pass, argv[2], strlen(argv[2]));

printf("User: %s\n", user);
printf("Pass: %s\n", pass);
printf("Login: %d\n", *login_ok);

/* ... check user/pass ... */

if(*login_ok)
{
printf("Access Accept\n");
} 
else
{
printf("Access Denied\n");
}

return 0;
}

Como podemos observar en el ejemplo anterior, el programa copia los datos introducidos por el usuario en dos buffers cuya memoria ha sido reservada con malloc() sin verificar su longitud máxima.
Pero, ¿Qué ocurre si sobrepasamos los 64 bytes de memoria reservada para las variables user y pass? Veamoslo con un ejemplo.

Esta es la ejecución normal del programa:
$ ./a.out myusername mypass
User: myusername
Pass: mypass
Login: 0
Access Denied

Ahora intentemos sobrepasar el tamaño máximo de la variable pass:

./a.out myusername `perl -e 'print "A"x100'`
User: myusername
Pass: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Login: 1094795585
Access Accept

Como vemos el programa nos da acceso sin necesidad de introducir una contraseña correcta. Pero, ¿Qué ha ocurrido? La respuesta es bastantes sencilla. Al reservar memoria con malloc() se nos ha assignado un espacio contiguo de memoria para las variables user, pass y login_ok. Por lo que al sobrepasar el limite de espacio asignado a una de ellas, se sobreescribe el contenido de las demás. Así, si sobrepasamos los 64 bytes de user, sobreescribimos pass y a continuación login_ok. O, como hemos hecho en el ejemplo, si sobrepassamos los 64 bytes de pass, sobreescribimos login_ok.

El valor que hemos assignado a login_ok es una cadena de As que ha dado como resultado el valor 1094795585. Aunque cualquier valor diferente de 0 nos hubiese servido igualmente para poder entrar en la sentencia if.

Existen diferentes maneras de aprovechar un heap overflow para explotar un programa. Estas dependen en gran medida de la imaginación del atacante. Lo más común es sobreescribir directamente una variable como hemos hecho en el ejemplo o modificar un puntero para que salte a cierto código controlado (ver buffer overflow). En cualquier caso, como ya se comentaba en el documento sobre buffer overflow, es necesario verificar correctamente la cantidad de datos que se escribe en los buffers.




No hay comentarios: