Buffer Overflow y bit NX

De Wiki de Sistemas Operativos
Saltar a: navegación, buscar

Buffer Overflows

Definición y causa

Los desbordamientos de búfer es una vulnerabilidad presente cuando se escribe en un búfer sin validar el tamaño del contenido. Esto puede hacer que si se introduce un dato lo suficientemente grande, el búfer se desborde, dando como resultado que se sobreescriba con código del atacante. Lo cual constituye un gran problema de seguridad cuando el programa se ejecuta con privilegios de superusuario.

Este error de programación de encuentra comúnmente en programas que gestionan su propio uso de la memoria (P. ej, C/C++). Según la OWASP (Proyecto de código abierto sobre seguridad web) es una de las vulnerabilidades más comunes, con un riesgo de explotación muy alto y variado, aún siendo una de las más antiguas y conocidas.

Ejemplo

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

int main(int argc, char *argv[])
{
	char buffer[5];
	if(argc != 2)
	{
		fprintf(stderr, "USO: %s cadena\n", argv[0]);
		return -1;
	}
	strcpy(buffer, argv[1]); // Cadenas de 5 o más caracteres causarán desbordamiento
	return 0;
}

Otro tipo de buffer overflow: Stack buffer overflow

Ejemplo modificando el código anterior

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

void mi_funcion(char *param)
{
	char buffer[5];
	strcpy(buffer, param);
}

int main(int argc, char *argv[])
{
	if(argc != 2)
	{
		fprintf(stderr, "USO: %s cadena\n", argv[0]);
		return -1;
	}
	mi_función(argv[1]);
	return 0;
}

Funcionamiento del exploit

Contenido de la pila:

	 _______
	|       |
	|_______| <- vbles. locales mi_funcion	(char buffer[] y char *param)
	|_______| <- dirección de retorno	(dir. siguiente instrucción después de mi_funcion)
	|       |
	|_______| <- vbles. locales main

Si se desborda el contenido de buffer:

	 _______
	|xxxxxxx|
	|xxxxxxx| <- vbles. locales mi_funcion
	|xxxxxxx| <- dirección de retorno
	|       |
	|_______| <- vbles. locales main

x = Código introducido por el atacante

Con lo cual, se han sobreescrito las variables de mi_funcion y la dirección de retorno, que es a la que se hará un jump después de ejecutar el código de mi_funcion. Es decir, estamos permitiendo al atacante saltar a una dirección arbitraria y ejecutar el código que contenga.

No confundir esta vulnerabilidad con un desbordamiento de pila o stack overflow, esto último ocurre cuando la pila de invocaciones se desborda por errores como recursión infinita o parámetros de retorno de demasiado tamaño.

Solución

Una máxima en seguridad informática es validar siempre los datos introducidos por el usuario. En este caso, bastaría con sustituir la línea de strcpy por:

	...
	strncpy(buffer, argv[1], sizeof(buffer));
	buffer[sizeof(buffer) - 1] = '\0'; // Caracter nulo
	...

De esta forma, nos aseguramos que el contenido del buffer no se desborde al copiar argv[1] en él.

Bit NX

La tecnología NX (No eXecutable) se introdujo para establecer determinadas zonas de memoria como no ejecutables, y así prevenir los ataques de tipo buffer overflow. Este bit es el último de cada entrada de la tabla de páginas, y si se encuentra puesto a 1 significa que el contenido de dicha página se considerará como datos y por tanto no podrá ser ejecutado. En el caso de arquitecturas como IA32, al basar inicialmente la protección de memoria en el mecanismo de segmentación, hizo que sus servidores sufrieran muchos ataques de buffer overflow hasta que se dió mayor control al mecanismo de paginación incluyendo esta tecnología (En el caso de Intel, llamada XD bit-Executing Disabled).

El núcleo de Linux soporta esta tecnología para arquitecturas IA-32 e IA-64. Si el hardware no proporciona la tecnología NX, el kernel para la arquitectura de 32 bits permite emularla por software.

Fuentes