Saltar al contenido
Volver a proyectos
Proyecto personal

Herramienta de evaluación de vulnerabilidades (Python + CVSS)

Herramienta de evaluación de vulnerabilidades (Python + CVSS)

Evaluación de vulnerabilidades Tenable SecurityCenter — resumen ejecutivo, clasificación por severidad y remediación mapeada a CVE.

Contexto

El plan inicial preveía un informe basado en un escaneo Nessus simulado contra una red ficticia. En la práctica, construí mi propio escáner en lugar de reproducir la salida de una herramienta existente — una señal más fuerte para un puesto SOC/Pentest/AppSec: la capacidad de diseñar y programar una herramienta de evaluación de vulnerabilidades (arquitectura de checks, motor de puntuación CVSS, generación de informes), no solo leer la salida de Nessus.

Metodología — 3 familias de checks

  • Network: escaneo de puertos concurrente (ThreadPoolExecutor, 1-1024), detección de servicios de riesgo (SMB/445, Telnet/23, Redis/6379 sin autenticación, RDP/3389), intento de transferencia de zona DNS (AXFR)
  • System: inspecciona la máquina que ejecuta la herramienta (no el objetivo) — versión del SO, configuración SSH (sshd_config), archivos con permisos de escritura global en /tmp
  • Web: cabeceras de seguridad ausentes (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy), validez del certificado TLS

El motor CVSS v3.1

Cada hallazgo lleva un vector CVSS (vector de ataque, complejidad, privilegios requeridos, interacción del usuario, impacto en confidencialidad/integridad/disponibilidad). La puntuación no es una constante elegida a mano: se calcula mediante la fórmula oficial del estándar (Exploitability × Impact, con el algoritmo Roundup de la especificación CVSS). Ejemplo real — un servicio SMB expuesto sin autenticación calcula CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8 (Crítico). La severidad se deriva después de la puntuación calculada, no se asigna por separado, lo que elimina cualquier riesgo de incoherencia entre la puntuación y la severidad mostrada.

Errores encontrados y corregidos durante la revisión de código

  • El check TLS nunca se activaba: getpeercert() devuelve {} cuando verify_mode=CERT_NONE, por lo que la detección de certificados expirados nunca funcionaba, de forma silenciosa. Corregido leyendo el certificado en formato DER (binary_form=True) y analizándolo con cryptography — verificado contra expired.badssl.com, que detecta correctamente un certificado expirado desde 2015
  • Escaneo de puertos secuencial: 1024 puertos × 0,5 s de timeout, hasta 8-9 minutos por escaneo. Corregido con ThreadPoolExecutor (escaneo concurrente) — 8,5 min → 6,4 s medido en real contra localhost
  • Puntuación CVSS codificada a mano: el README anunciaba un cálculo CVSS v3.1 pero las puntuaciones eran constantes elegidas manualmente. Implementación de la fórmula real (Exploitability, Impact, Roundup)
  • Confusión de alcance: los checks system analizaban la máquina local, no el objetivo --target, sin documentarlo en ningún sitio. IDs renombrados a LOCAL-*, con docstrings, notas en el README y un aviso en consola explícitos
  • Sin garantía de autorización: la herramienta escaneaba cualquier objetivo sin confirmación. Se añadió un aviso de confirmación interactivo más un flag --i-am-authorized para uso no interactivo/CI

Resultados de pruebas reales

Escaneo de localhost
6,4 s(SMB/445 → Crítico (9.8), MSRPC/135 → Medio (5.3) — frente a 8,5 min antes de la corrección de concurrencia)
Certificado TLS expirado
Detectado correctamente(expired.badssl.com — expirado desde el 12/04/2015)
Cabeceras de seguridad
5 cabeceras ausentes detectadas(example.com — HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy)

Resultados

Stack
Python 3.11+, Jinja2, cryptography(Sin binarios de escaneo externos (nmap, Nessus...))
Tests
12 tests pytest(Motor CVSS + modelos de datos)
Salida
Informe HTML autónomo + exportación JSON(Compatible con SIEM/ticketing)
Marco legal
Garantía de autorización integrada(Confirmación requerida, o --i-am-authorized)