Hoy veremos lo que es un desbordamiento de búfer en C y cómo puede (en su forma más simple) hacer que un usuario aproveche esa vulnerabilidad para explotar nuestro programa.
Nota: esto es diferente a cuando se desborda una variable.
Según la Wikipedia:
En seguridad informática y programación, un desbordamiento de búfer (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): Si dicha cantidad es superior a la capacidad preasignada, los bytes sobrantes se almacenan en zonas de memoria adyacentes, sobrescribiendo su contenido original, que probablemente pertenecían a datos o código almacenados en memoria. Esto constituye un fallo de programación.
En otras palabras le da al usuario de nuestro programa la forma de sobrescribir una variable a su antojo; bueno, no siempre y no tan fácil, pero alguien con tiempo puede encontrarlas y explotarlas.
Esto es peligroso en programas que se van para producción, por ejemplo un sistema de la apertura de una puerta o cosas de esas que tienen que ver con la seguridad.
Esto se da más que nada cuando trabajamos con cadenas. Por ejemplo, tenemos una cadena de 3 caracteres:
char cadena[3];
Todo bien hasta ahí, ¿pero qué pasa si le decimos al usuario que introduzca la contraseña para entrar (la cual tiene 3 dígitos)? pues fácil, hacemos esto:
scanf("%s", cadena);
Más tarde hacemos una comparación y si la cadena es igual a 123 entonces ponemos una variable en true.
Abajo de todo ello comparamos la variable y si es que sí entonces lo dejamos pasar.
/*
Ejemplo simple de desbordamiento de búfer en C
@author parzibyte
*/
#include <stdio.h>
#include <string.h>
int main() {
char cadena[3];
int autenticado = 0; // 1 es que sí, 0 que no
printf("Ingresa la contraseña:\n");
scanf("%s", cadena);
if (strcmp(cadena, "123") == 0) {
autenticado = 1;
}
if (autenticado)
printf("Bienvenido al programa");
else
printf("Acceso denegado");
printf("\nAl final de todo, el valor que tiene 'autenticado' es: %d",
autenticado);
}
Muy bien, estamos declarando un entero que será 1 o 0 para ver si se autenticó correctamente. Esa variable la declaramos junto con la cadena.
La cadena tendrá un máximo de 3 caracteres, y abajo de ella tenemos a autenticado. Por lo tanto, en la RAM estará un espacio reservado para 3 caracteres y un entero.
El usuario intentará con contraseñas de 3 dígitos y con suerte no sabrá la contraseña, pero ¿qué pasa si pone 4 caracteres? justo ahí está el desbordamiento de búfer.
Digamos que le pasamos la cadena “4321”. El programa (con scanf
) pondrá los 3 caracteres en cadena, pero como no sabrá en dónde poner el 1 sobrante lo va a poner en la siguiente posición de memoria.
¿y qué hay en la siguiente posición de memoria? la variable entera llamada autenticado. Como es un carácter, le pondrá su valor ASCII (49).
Cuando hagamos el if, como cualquier cosa que no sea 0 pasa como verdadero (y en este caso es 49) entonces lo dejará pasar.
Si intentas con una contraseña incorrecta de 3 dígitos, el programa nunca te dejará pasar. En cambio, si pones una de 4 dígitos sin importar la que sea, te dejará pasar.
Al final del programa se imprime el valor de la variable autenticado para que puedas ver cómo funciona el escaneo de variables.
Ya sé que tal vez estás pensando en que puedes mejorar el if
, o que puedes declarar tus variables de otra forma; cosas de esas. Solamente te digo que ese código es el más simple, hay otros que permiten hacer más cosas, y es mejor siempre saber lo que uno está haciendo.
Nunca puedes confiar en tus propios métodos, mejor sigue los estándares. Tampoco uses (nunca en tu vida) la típica frase de:
¿pero quién se complicaría tanto para romper el sistema?
Porque ten por seguro que alguien por ahí está dispuesto a hacerlo si es que vale la pena.
Únicamente ten cuidado cuando el contenido de un búfer no venga de una fuente confiable. También recuerda usar, por ejemplo, strncpy
en lugar de strcpy
, o fgets
en lugar de scanf
.
En caso de que tus programas sean didácticos no pasa nada, al momento de practicar se vale equivocarse y dejar agujeros de seguridad.
Tal vez próximamente traiga unos ejemplo de cómo prevenir esto.
Actualización: aquí puedes ver cómo usar fgets en lugar de scanf para prevenir estos comportamientos.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.
Ver comentarios