Desbordamiento de búfer en C

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.

Lo que es un desbordamiento de búfer

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.

Ejemplo de desbordamiento de búfer en C

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.

Pero yo no uso ese tipo de código

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.

Prevenir desbordamiento de búfer en C

Ú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.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

1 comentario en “Desbordamiento de búfer en C”

  1. Pingback: ¿Qué es un desbordamiento en C? - Parzibyte's blog

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *