Buffer overflow: el desbordamiento de búfer que lleva décadas causando estragos

Buffer overflow: el desbordamiento de búfer que lleva décadas causando estragos

Un buffer overflow —o desbordamiento de búfer— ocurre cuando un programa escribe más datos de los que caben en un espacio de memoria reservado, sobrescribiendo zonas adyacentes. Esta vulnerabilidad de memoria lleva causando estragos desde los años 80 y sigue siendo una de las técnicas favoritas para construir un exploit buffer. Morris Worm, Code Red, Slammer, EternalBlue: todos aprovecharon variantes de este fallo. Y sí, el stack overflow como vector de ataque sigue vivo en 2026, por mucho que llevemos décadas hablando de él. Es como ese virus de email que tu tío reenvía cada Navidad: pensabas que ya no existía, pero ahí sigue.

Qué es exactamente un buffer overflow y por qué importa

Imagina una estantería con espacio para 10 libros. Alguien mete 15. Los cinco sobrantes caen encima de lo que había al lado: quizá tus fotos, quizá las llaves del coche. En un ordenador, ese "al lado" puede ser la dirección de retorno de una función, un puntero crítico o datos de autenticación.

El desbordamiento de búfer explota lenguajes que no comprueban automáticamente los límites de memoria. C y C++ son los sospechosos habituales. Cuando un programa usa funciones como strcpy(), gets() o sprintf() sin validar el tamaño de la entrada, un atacante puede inyectar código malicioso directamente en la memoria del proceso.

Existen dos variantes principales:

  • Stack-based buffer overflow: sobrescribe la pila de ejecución. Es el tipo clásico. El atacante modifica la dirección de retorno para redirigir el flujo del programa hacia su shellcode.
  • Heap-based buffer overflow: afecta a la memoria dinámica (heap). Más difícil de explotar, pero igual de peligroso. Permite corromper estructuras de datos internas y secuestrar punteros de función.

La organización MITRE clasifica el buffer overflow como CWE-120 (Classic Buffer Overflow) y sus variantes. Según el ranking CWE Top 25 de 2024, las vulnerabilidades de escritura fuera de límites (CWE-787) ocupaban el primer puesto. No el quinto. No el décimo. El primero.

Casos reales que cambiaron la historia de la ciberseguridad

El primer exploit de buffer overflow documentado a gran escala fue el Morris Worm de 1988. Robert Tappan Morris, estudiante de Cornell, explotó un desbordamiento en el demonio fingerd de Unix. Infectó aproximadamente el 10% de los equipos conectados a Internet —que entonces eran unos 60.000—. Le costó una condena federal y a nosotros, la creación del CERT/CC.

Pero la lista no se queda ahí:

AñoIncidenteCVE / Detalle
2001Code RedBuffer overflow en IIS de Microsoft. Infectó más de 350.000 servidores en menos de 14 horas.
2003SQL SlammerCVE-2002-0649. Desbordamiento en SQL Server. Duplicaba infecciones cada 8,5 segundos.
2014HeartbleedCVE-2014-0160. Técnicamente un over-read en OpenSSL, variante del mismo problema de gestión de memoria.
2017EternalBlueCVE-2017-0144. Buffer overflow en SMBv1 de Windows. Base de WannaCry y NotPetya.
2021CVE-2021-3156 (Baron Samedit)Heap overflow en sudo. Permitía escalada de privilegios a root en la mayoría de distribuciones Linux.

EternalBlue merece mención especial. Fue desarrollado por la NSA, filtrado por el grupo Shadow Brokers, y usado como base para WannaCry, que paralizó hospitales del NHS británico. Un buffer overflow nacido en una agencia gubernamental que acabó bloqueando quirófanos. Si esto no es un guion de película, no sé qué lo es.

Estos ataques no solo afectan a infraestructura tecnológica. Si gestionas un negocio online, la seguridad de tu stack es una prioridad — algo que abordamos en detalle en nuestra guía de seguridad para ecommerce.

Anatomía de un exploit: cómo funciona paso a paso

Vamos al grano. Un exploit de buffer overflow típico contra la pila sigue estos pasos:

  1. Identificar la vulnerabilidad: el atacante localiza una función que copia datos sin comprobar longitud. Herramientas como AFL (American Fuzzy Lop), libFuzzer o Honggfuzz automatizan este proceso enviando entradas aleatorias hasta provocar un crash.
  2. Calcular el offset: determinar cuántos bytes hacen falta para llegar exactamente a la dirección de retorno en la pila. Se usan patrones cíclicos (de Bruijn sequences) para identificar la posición exacta.
  3. Inyectar el payload: el shellcode —instrucciones en lenguaje máquina— se coloca en el búfer. Puede abrir una shell remota, descargar malware o crear un usuario administrador.
  4. Redirigir la ejecución: la dirección de retorno se sobrescribe para apuntar al shellcode. Cuando la función intenta "volver", salta directamente al código del atacante.

Suena sencillo, pero las protecciones modernas complican bastante el proceso. Eso no significa que lo hagan imposible.

Defensas modernas: qué funciona y qué no tanto

La industria lleva décadas implementando contramedidas contra la vulnerabilidad de memoria por desbordamiento. Algunas funcionan bien. Otras son más un obstáculo que una solución definitiva.

ASLR (Address Space Layout Randomization): aleatoriza las direcciones de memoria del proceso en cada ejecución. El atacante ya no puede predecir dónde estará su shellcode. Implementado en Linux (desde 2005), Windows (Vista en adelante) y macOS. Problema: en sistemas de 32 bits, el espacio de direcciones es suficientemente pequeño para que un ataque de fuerza bruta lo rompa en minutos.

Stack canaries: valores centinela colocados antes de la dirección de retorno. Si el canario se modifica, el programa aborta. GCC los implementa con -fstack-protector. Problema: si el atacante puede leer memoria (info leak), puede conocer el valor del canario y preservarlo.

DEP/NX (Data Execution Prevention / No-Execute): marca regiones de memoria como no ejecutables. El shellcode en el búfer no puede ejecutarse directamente. Problema: los atacantes responden con ROP (Return-Oriented Programming), encadenando fragmentos de código legítimo ya presente en memoria para construir su exploit sin inyectar código nuevo.

CFI (Control Flow Integrity): verifica que el flujo del programa siga caminos válidos. LLVM lo implementa con -fsanitize=cfi. Es la protección más robusta actualmente, pero su adopción todavía no es universal.

La tendencia real hacia la eliminación de esta clase de vulnerabilidades viene de otro lado: lenguajes memory-safe. Rust, Go, Java, Python y C# gestionan la memoria automáticamente. El proyecto Chromium reportó que aproximadamente el 70% de sus vulnerabilidades graves eran errores de seguridad de memoria. Google y Microsoft están migrando componentes críticos a Rust. La Casa Blanca publicó en 2024 un informe (ONCD) recomendando la adopción de lenguajes memory-safe para software crítico.

Si te interesa fortificar tu entorno digital más allá del código, configurar correctamente tu firewall es un complemento necesario contra exploits que buscan servicios expuestos.

Cómo protegerte: guía práctica

Si desarrollas software:

  • Usa funciones seguras: strncpy() en lugar de strcpy(), snprintf() en lugar de sprintf(). O mejor: usa std::string en C++ o directamente trabaja en Rust.
  • Compila con todas las protecciones activas: -fstack-protector-strong, -D_FORTIFY_SOURCE=2, -pie, -fPIE.
  • Integra fuzzing en tu pipeline de CI/CD. OSS-Fuzz de Google ha encontrado miles de vulnerabilidades de memoria en proyectos open source.
  • Pasa análisis estáticos con herramientas como Coverity, CodeQL o Semgrep.

Si administras sistemas:

  • Mantén el software actualizado. La mayoría de exploits de buffer overflow en producción atacan versiones sin parchear. El CVE ya tiene fix, pero tú no lo has aplicado.
  • Verifica que ASLR esté activo: cat /proc/sys/kernel/randomize_va_space debe devolver 2 en Linux.
  • Reduce la superficie de ataque: desactiva servicios innecesarios, limita permisos, aplica el principio de mínimo privilegio.
  • Monitoriza con herramientas de detección de intrusiones. OSSEC, Wazuh o Falco pueden detectar comportamientos anómalos derivados de exploits.

Si eres usuario final: actualiza. En serio, actualiza. Esa notificación de Windows Update que ignoras desde hace tres semanas podría ser el parche que cierra un desbordamiento de búfer que ya están explotando activamente. Y ya que estás, revisa si tus credenciales han sido comprometidas usando herramientas como Have I Been Pwned, porque un ataque de credential stuffing combinado con un exploit de memoria es la receta perfecta para el desastre.

Preguntas frecuentes

¿Cuál es la diferencia entre buffer overflow y stack overflow?

Un buffer overflow es el concepto general: escribir más datos de los que caben en un búfer de memoria. Un stack overflow es un tipo específico donde el desbordamiento ocurre en la pila (stack) del programa, típicamente sobrescribiendo la dirección de retorno de una función. También existe el heap overflow, que afecta a la memoria dinámica.

¿Los lenguajes modernos como Python o Java son vulnerables a buffer overflow?

En su código nativo, no, porque gestionan la memoria automáticamente y comprueban los límites de los arrays. Pero muchas librerías de Python y Java están escritas en C/C++ por debajo (extensiones nativas, JNI). Si esas librerías tienen un desbordamiento de búfer, el programa sigue siendo vulnerable indirectamente.

¿Puede un antivirus detectar un exploit de buffer overflow?

Un antivirus tradicional basado en firmas tiene dificultades, porque el exploit se ejecuta en memoria y puede no dejar archivos en disco. Las soluciones EDR (Endpoint Detection and Response) modernas como CrowdStrike, SentinelOne o Microsoft Defender for Endpoint monitorizan comportamientos en memoria y pueden detectar técnicas como ROP o shellcode injection.

¿Por qué no se reescribe todo el software antiguo en lenguajes seguros?

Coste y complejidad. El kernel de Linux tiene más de 30 millones de líneas de C. Reescribirlo en Rust llevaría años y requeriría verificar que el comportamiento se mantiene idéntico. La estrategia actual es más pragmática: reescribir los componentes más expuestos (parsers, drivers de red, gestores de memoria) y mantener el resto con protecciones adicionales.

El siguiente paso

Abre una terminal y ejecuta checksec --file=/ruta/a/tu/binario (instala checksec desde tu gestor de paquetes). Este comando te mostrará qué protecciones tiene activas cada ejecutable de tu sistema: RELRO, stack canary, NX, PIE, ASLR. Si ves algún binario expuesto a internet sin NX o sin PIE, ya tienes tu primera tarea de hardening. Y si quieres seguir blindando tu ecosistema digital, pásate por nuestro artículo sobre navegación segura para cubrir el otro lado de la ecuación.

buffer overflow desbordamiento búfer vulnerabilidad memoria exploit buffer stack overflow ataque

Artículos relacionados

← Volver al blog