Tema 18

18. Fundamentos de vulnerabilidades: memoria, validación de entrada y lógica insegura

Una vulnerabilidad es una condición que permite que un sistema se comporte fuera de lo esperado en términos de seguridad. Comprender sus causas ayuda a evaluar impacto, reproducir fallos en laboratorio y proponer mitigaciones efectivas.

Objetivo Comprender qué hace explotable una debilidad
Enfoque Memoria, entradas, lógica, permisos, impacto y mitigación
Resultado Evaluar vulnerabilidades con criterio técnico y defensivo

18.1 Introducción

Una vulnerabilidad no es solo un error de programación. Es una debilidad que puede afectar confidencialidad, integridad, disponibilidad, autenticidad o control de acceso. Puede estar en código, configuración, arquitectura, permisos, diseño de procesos o lógica de negocio.

En explotación controlada, estudiar vulnerabilidades permite demostrar impacto de forma segura. En defensa, permite priorizar correcciones, diseñar mitigaciones y entender cómo un atacante podría encadenar fallas.

Este tema introduce los fundamentos necesarios antes de estudiar buffer overflow, fuzzing, crash analysis y desarrollo de pruebas de concepto en laboratorio.

18.2 Vulnerabilidad, exploit e impacto

Conviene distinguir tres conceptos relacionados pero diferentes.

Concepto Significado Ejemplo defensivo
Vulnerabilidad Debilidad que puede ser aprovechada Validación insuficiente de entrada
Exploit Método o prueba que aprovecha la debilidad Entrada que provoca fallo reproducible
Impacto Consecuencia de aprovechar la vulnerabilidad Lectura de datos, ejecución, escalada o caída
Mitigación Control que reduce probabilidad o impacto Parche, validación, hardening o monitoreo
No toda vulnerabilidad tiene el mismo impacto. La severidad depende de contexto, exposición, privilegios, datos afectados y facilidad de explotación.

18.3 Superficie de ataque

La superficie de ataque es el conjunto de puntos donde un sistema recibe entradas, expone funciones o interactúa con usuarios, servicios y datos externos.

  • Interfaces web y APIs.
  • Servicios de red.
  • Archivos importados o procesados.
  • Parámetros de línea de comandos.
  • Mensajes, colas y eventos.
  • Plugins, extensiones y dependencias.
  • Permisos, roles y flujos de negocio.

Reducir superficie implica eliminar exposición innecesaria, validar entradas y limitar permisos.

18.4 Validación de entrada

Una entrada es cualquier dato que llega desde fuera de una función, proceso o sistema. Puede provenir del usuario, red, archivo, base de datos, variable de entorno, token, cabecera o sistema externo.

La validación debe comprobar:

  • Tipo de dato esperado.
  • Longitud y tamaño máximo.
  • Rango permitido.
  • Formato y codificación.
  • Caracteres especiales.
  • Relación con permisos y contexto.
  • Consistencia entre campos relacionados.

18.5 Validación, sanitización y normalización

Estos términos suelen confundirse, pero cumplen funciones distintas.

Acción Propósito Ejemplo
Validar Decidir si una entrada es aceptable Rechazar tamaño mayor al límite
Sanitizar Transformar o neutralizar contenido peligroso Escapar caracteres antes de mostrar HTML
Normalizar Convertir a una forma canónica antes de evaluar Resolver rutas relativas antes de aplicar permisos
Codificar salida Adaptar datos al contexto de destino Codificar para HTML, SQL, shell o JSON según corresponda

18.6 Errores de memoria

Los errores de memoria aparecen cuando un programa lee, escribe, libera o ejecuta memoria de forma incorrecta. Son comunes en lenguajes de bajo nivel o componentes que gestionan memoria manualmente.

  • Lectura o escritura fuera de límites.
  • Uso de memoria después de liberarla.
  • Doble liberación de memoria.
  • Desbordamientos en stack o heap.
  • Punteros nulos o no inicializados.
  • Confusión de tipos o tamaños.

Estos errores pueden causar crashes, corrupción de datos, fuga de información o, en casos graves, control de flujo.

18.7 Stack, heap y límites

Muchas vulnerabilidades de memoria se comprenden mejor observando dónde ocurre el error.

Región Uso normal Riesgo típico
Stack Variables locales, llamadas y retornos Corrupción de datos cercanos o dirección de retorno
Heap Memoria dinámica y objetos Use-after-free, overflow, corrupción de estructuras
Datos globales Variables compartidas por el programa Alteración persistente de estado interno
Memoria mapeada Archivos, bibliotecas o regiones especiales Lecturas indebidas o permisos incorrectos

18.8 Integer overflow y errores de tamaño

Un integer overflow ocurre cuando una operación numérica excede el rango del tipo de dato. En seguridad, puede provocar reservas de memoria insuficientes, cálculos de tamaño incorrectos o validaciones que se eluden.

Señales de riesgo:

  • Multiplicaciones para calcular tamaños de buffers.
  • Conversión entre enteros con signo y sin signo.
  • Truncamiento al pasar de tipos grandes a pequeños.
  • Validaciones realizadas antes de transformaciones que cambian tamaño.
  • Longitudes proporcionadas por el usuario o por un archivo.

18.9 Inyecciones

Una inyección ocurre cuando datos no confiables se interpretan como parte de un comando, consulta, expresión o documento ejecutable en otro contexto.

Ejemplos defensivos:

  • SQL interpretando datos como parte de una consulta.
  • Shell ejecutando caracteres especiales como comandos.
  • HTML o JavaScript interpretando datos como código de navegador.
  • LDAP, XPath, NoSQL o plantillas procesando entrada sin separación clara.
  • Comandos de sistema construidos con concatenación de strings.

La defensa principal es separar datos de instrucciones mediante APIs seguras, consultas parametrizadas y codificación de salida por contexto.

18.10 Deserialización insegura

La deserialización convierte datos almacenados o transmitidos en objetos. Si esos datos no son confiables, pueden alterar estado, invocar lógica no prevista o cargar tipos peligrosos.

Riesgos comunes:

  • Objetos manipulados por el usuario.
  • Tipos permitidos demasiado amplios.
  • Validación posterior a la creación del objeto.
  • Firmas o integridad ausentes.
  • Uso de formatos con comportamiento automático complejo.

18.11 Control de acceso roto

El control de acceso falla cuando un usuario o proceso puede realizar acciones o acceder a datos fuera de sus permisos esperados. Es una vulnerabilidad de lógica y diseño, no solo de código.

  • Acceso directo a objetos por ID sin verificar propietario.
  • Funciones administrativas protegidas solo en la interfaz visual.
  • APIs que confían en parámetros del cliente.
  • Roles mal definidos o demasiado amplios.
  • Autorización verificada al inicio pero no en acciones posteriores.

18.12 Lógica insegura

Una falla de lógica aparece cuando el sistema implementa un flujo permitido técnicamente, pero inseguro desde el punto de vista del negocio o la seguridad.

Ejemplos:

  • Reutilizar un cupón más veces de lo previsto.
  • Modificar el precio o cantidad desde el cliente.
  • Omitir pasos de verificación cambiando el orden de solicitudes.
  • Restablecer contraseña sin controlar todos los factores requeridos.
  • Aprobar acciones críticas sin confirmar identidad o contexto.

Estas vulnerabilidades suelen requerir comprensión del proceso, no solo herramientas automáticas.

18.13 Condiciones de carrera

Una condición de carrera ocurre cuando el resultado depende del orden o timing de operaciones concurrentes. En seguridad, puede permitir usar un recurso después de validarlo pero antes de que cambie, duplicar acciones o alterar estado en momentos críticos.

Áreas sensibles:

  • Validación y uso de archivos.
  • Operaciones financieras o de inventario.
  • Creación de cuentas o tokens.
  • Cambios de permisos.
  • Procesos paralelos que actualizan el mismo recurso.

18.14 Configuración insegura

No todas las vulnerabilidades están en código. Una configuración débil puede exponer servicios, datos o privilegios.

  • Credenciales por defecto.
  • Puertos administrativos expuestos.
  • Permisos excesivos en archivos o buckets.
  • Debug habilitado en producción.
  • Cabeceras de seguridad ausentes.
  • Servicios innecesarios activos.
  • Secretos almacenados en texto claro.

18.15 Dependencias vulnerables

Las aplicaciones dependen de bibliotecas, frameworks, contenedores, imágenes, plugins y servicios. Una vulnerabilidad en una dependencia puede afectar al sistema aunque el código propio sea correcto.

Buenas prácticas defensivas:

  • Mantener inventario de dependencias.
  • Usar versiones soportadas.
  • Aplicar parches con pruebas.
  • Eliminar dependencias innecesarias.
  • Revisar advisories y CVEs relevantes.
  • Controlar integridad y origen de paquetes.

18.16 Reproducción controlada

Reproducir una vulnerabilidad permite confirmar existencia e impacto. Debe hacerse en entorno autorizado, con datos de prueba y el menor impacto posible.

  1. Definir alcance y permiso.
  2. Preparar entorno de prueba o laboratorio.
  3. Identificar condición vulnerable.
  4. Usar entrada mínima para demostrar el fallo.
  5. Registrar evidencia sin exponer datos sensibles.
  6. Confirmar mitigación después de corregir.
Una prueba responsable demuestra impacto sin causar daño innecesario ni acceder a datos que no hacen falta para confirmar el riesgo.

18.17 Severidad y riesgo

La severidad técnica debe combinarse con contexto. Una vulnerabilidad crítica en un servicio aislado de laboratorio no tiene el mismo riesgo que la misma falla expuesta a internet con datos sensibles.

Factor Pregunta Impacto en prioridad
Exposición Está accesible desde internet o red interna amplia Aumenta urgencia
Privilegios Requiere usuario autenticado o permisos altos Puede reducir o cambiar prioridad
Impacto Afecta datos, ejecución, disponibilidad o privilegios Define gravedad
Explotabilidad Es fácil de reproducir o requiere condiciones raras Modula riesgo real
Controles existentes Hay mitigaciones, segmentación o monitoreo Puede reducir impacto residual

18.18 CVE, CWE y CVSS

Estas siglas ayudan a clasificar y comunicar vulnerabilidades.

  • CVE: identificador público para vulnerabilidades conocidas.
  • CWE: clasificación de tipos de debilidad, como errores de memoria o validación.
  • CVSS: sistema de puntuación que estima severidad técnica.

Son herramientas útiles, pero no reemplazan el análisis de contexto propio. Un CVSS alto no siempre implica prioridad máxima en todos los entornos, y un CVSS medio puede ser urgente si afecta un activo crítico.

18.19 Mitigaciones

Mitigar una vulnerabilidad puede requerir más que aplicar un parche. La defensa debe reducir probabilidad, impacto y exposición.

  • Corregir código vulnerable.
  • Aplicar parches y actualizar dependencias.
  • Validar y normalizar entradas.
  • Aplicar mínimo privilegio.
  • Segmentar servicios expuestos.
  • Agregar monitoreo y alertas.
  • Deshabilitar funciones innecesarias.
  • Usar mitigaciones de plataforma como ASLR, DEP o sandboxing.

18.20 Evidencia y reporte

Un reporte de vulnerabilidad debe ser claro, reproducible y responsable.

  • Descripción de la debilidad.
  • Activo y versión afectada.
  • Condiciones necesarias.
  • Impacto demostrado de forma segura.
  • Evidencia mínima suficiente.
  • Riesgo y prioridad sugerida.
  • Recomendación de mitigación.
  • Validación posterior esperada.

18.21 Relación con malware

El malware puede aprovechar vulnerabilidades para entrar, elevar privilegios, moverse lateralmente o evadir controles. También puede incluir exploits como módulos separados o descargar componentes según el entorno.

Durante análisis de malware, buscar:

  • Checks de versión o sistema operativo.
  • Cadenas relacionadas con CVEs o módulos de explotación.
  • Comportamiento distinto según privilegios.
  • Crashes o excepciones provocadas contra servicios.
  • Descarga de componentes específicos para una plataforma.

18.22 Checklist de análisis de vulnerabilidad

  1. Definir activo, versión y alcance autorizado.
  2. Identificar entrada o condición vulnerable.
  3. Clasificar tipo de debilidad.
  4. Reproducir con impacto mínimo.
  5. Registrar evidencia y contexto.
  6. Evaluar impacto, exposición y explotabilidad.
  7. Proponer mitigación y prioridad.
  8. Validar corrección después del cambio.

18.23 Errores frecuentes

  • Confundir crash con explotación demostrada.
  • Medir severidad sin considerar exposición real.
  • Probar fuera de alcance autorizado.
  • Usar datos reales cuando bastan datos de prueba.
  • Reportar solo la técnica sin explicar impacto.
  • Aplicar parches sin validar corrección.
  • Ignorar vulnerabilidades de lógica porque no aparecen en escáneres.

18.24 Qué debes recordar de este tema

  • Una vulnerabilidad es una debilidad con impacto de seguridad posible.
  • Memoria, validación de entrada y lógica insegura son fuentes comunes de fallas.
  • Reproducir responsablemente significa demostrar impacto con mínimo daño.
  • La severidad depende de exposición, privilegios, impacto, explotabilidad y controles existentes.
  • Mitigar implica corregir causa, reducir exposición y validar el resultado.

18.25 Conclusión

Comprender vulnerabilidades es esencial para evaluar riesgo real. Una falla técnica solo se vuelve relevante cuando se conecta con impacto, condiciones de explotación, exposición y controles defensivos.

En el próximo tema estudiaremos buffer overflow, control de flujo, stack, heap y condiciones de explotación, profundizando en una de las familias clásicas de vulnerabilidades de memoria.