El típico programa de un buffer overflow en C se da en la siguiente función:
int mi_funcion(char *input){
Si la cadena a la que apunta input es controlada por el usuario y no existe ningún límite en el número de caracteres (ya sea porque estamos leyendo de un fichero en disco, de la red o entrada del usuario vía teclado), al usar la función strcat acabaremos sobrepansando el tamaño de buf, y escribiendo en direcciones de memoria que no se debe. Si el programa donde se da este fallo se ejecuta con privilegios, puede aprovecharse para hacer una escalada desde un usuario normal a otro privilegiado.
char buf[256];
....
....
strcat("CADENA",buf);
....
....
return 0;
}
Lo primero es usar las funciones de la librería estándar de C:strncpy y strncat.
char* strncpy(char *restrict s1, const char *restrict s2, size_t n);El cambio fundamental es es el parámetro n, que especifica el número de bytes del búfer apuntado por s1. Así cualquiera de esas dos funciones copiará como máximo n bytes o bien si encuentra en la cadena que esté copiando, el carácter que manda el fin de cadena en C, el \0.
char* strncat(char *restrict s1, const char *restrict s2, size_t n);
Sin embargo estas dos funciones tienen dos problemas:
- strncpy no termina con el \0 la cadena si se utiliza todo el búfer.
- strncat rellena de ceros todo el búfer de destino hasta el tamaño que se especifica
size_t strlcpy(char *dst, const char *src, size_t size);Estas dos funciones garantizan que las cadenas están terminada con un \0 y permite detectar de manera sencilla en el caso de strlcat la existencia de que una cadena se trunque, como puede verse en este ejemplo sacado de la página de manual de MacOS X:
size_t strlcat(char *dst, const char *src, size_t size);
if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname))Las decisiones de diseño que llevaron a estas funciones están descritas en el artículo enlazado al principio. Aunque hace mucho tiempo del artículo, en el año 1999, es una lectura interesante para comprender la evolución de las API para evitar los problemas de seguridad.
goto toolong;
if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
goto toolong;
Actualización
Me comenta mig21 que estas funciones no siempre le han gustado a otros desarrolladores. Por ejemplo, Ulrich Drepper, mantenedor de la GNU libc:This is horribly inefficient BSD crap. Using these function only leads to other errors. Correct string handling means that you always know how long your strings are and therefore you can you memcpy (instead of strcpy).Y es interesante el enlace a la entrada en la wikipedia de strlcpy.
Technorati Tags: buffer overflow, c