El módulo anterior terminó señalando una palabra que apareció en sus seis lecciones sin desarrollarse nunca: verificar. El registro de riesgos afirma que el puerto 5432 está expuesto, el catálogo de controles promete un escaneo externo mensual que nadie ha ejecutado (C-10, «planificado») y el riesgo R-07 habla de «servicios olvidados» sin que nadie sepa cuántos hay hoy. Esta lección convierte esas afirmaciones en mediciones: vas a aprender a encontrar lo que está expuesto, decidir qué se arregla primero y demostrar que se arregló, con herramientas de coste cero que caben en el presupuesto de Nimbus.
⚠️ Advertencia legal y de autorización — léela antes de ejecutar nada
Todo lo que hay en esta lección se ejecuta exclusivamente sobre sistemas propios o con autorización escrita, explícita y vigente.
- Escanear puertos o lanzar un escáner de vulnerabilidades contra una máquina ajena sin autorización puede constituir delito en España (arts. 197 bis y 264 del Código Penal). La curiosidad no es una eximente.
- En la nube debes cumplir además la política de pruebas del proveedor, y si el sistema lo opera un tercero —la consultora de A-19, el proveedor de correo, la pasarela—, la autorización viene de quien lo opera, no solo de quien lo contrata.
Todo el material trabaja sobre el rango propio de Nimbus (
10.20.0.0/16en oficina,10.30.0.0/16en la nube) y su dominionimbusreservas.example. No hay exploits ni payloads: cada hallazgo va con su corrección. (La interpretación penal concreta depende del caso; ante una prueba con impacto sobre terceros, consulta asesoría jurídica.)
Contenido
- La gestión de vulnerabilidades como proceso continuo
- El mapa de herramientas: qué encuentra cada familia
- Descubrimiento de red con nmap
- Escáner de vulnerabilidades: Greenbone/OpenVAS
- Dependencias y contenedores: pip-audit y trivy
- Análisis estático de código y escaneo de secretos
- Priorización: CVSS, EPSS, KEV y exposición
- Falsos positivos, falsos negativos y validación
- Integración en el ciclo y métricas del proceso
- El informe de vulnerabilidades
- La gestión de vulnerabilidades como proceso continuo
Casi todas las PYMES que «hacen gestión de vulnerabilidades» hacen en realidad escaneo puntual: una vez al año alguien lanza una herramienta, exporta un PDF de 300 páginas y lo archiva. Eso no reduce el riesgo: genera un documento. La diferencia es un ciclo cerrado con verificación.
flowchart LR
I["0. INVENTARIO\nQue tengo (A-01..A-22).\nSin esto no hay cobertura"] --> D["1. DESCUBRIR\nnmap, escaner, SCA,\nSAST, secretos, cloud"]
D --> P["2. PRIORIZAR\nCVSS + EPSS + KEV\n+ exposicion + criticidad"]
P --> R["3. REMEDIAR\nParche, configuracion,\nmitigacion o aceptacion"]
R --> V["4. VERIFICAR\nReescanear y CERRAR\ncon evidencia"]
V --> N["5. INFORMAR\nMetricas y tendencia\n(KPI de 04-03)"]
N --> D
V -.->|"si no se corrige"| E["EXCEPCION con caducidad\nal registro de riesgos 04-01"]
Cinco reglas separan el proceso del teatro:
- El paso 0 no es opcional. Un escaneo sobre 12 máquinas cuando tienes 18 no encuentra nada en las otras 6: la cobertura es la primera métrica, no la última.
- Lo alimentan varias herramientas, no una. Ninguna familia ve más del 30 % del problema.
- Priorizar no es ordenar por CVSS. Es la parte que más valor aporta y la que casi nadie hace bien (§7).
- Un hallazgo se cierra cuando el reescaneo ya no lo encuentra, no cuando alguien dice que lo arregló: esa es la evidencia auditable de 04-03. Y lo que no se corrige se convierte en excepción con caducidad (04-02), no en una fila que envejece en silencio.
Precisión de 01-01: una versión de OpenSSL con CVE es una vulnerabilidad; que ese servicio escuche en Internet es la exposición; el riesgo combina ambas con la criticidad del activo. Una crítica en una máquina apagada no es una urgencia; una media en la API pública que llega a A-01 sí.
- El mapa de herramientas: qué encuentra cada familia
| Familia | Qué encuentra / qué no ve | Libres | Comercial | Dónde |
|---|---|---|---|---|
| Descubrimiento de red | Hosts, puertos, servicios y versiones · no ve nada dentro de la aplicación | nmap, masscan |
Runzero, Censys | §3 y 05-04 |
| Escáner de infraestructura | CVE de sistema y servicios · no ve fallos de negocio ni código propio | Greenbone/OpenVAS, Nuclei | Nessus, Qualys | §4 |
| Escáner web dinámico (DAST) | Inyecciones, XSS, cabeceras · no ve código no alcanzable por la interfaz | OWASP ZAP, Nikto, testssl.sh |
Burp Pro, Invicti | 05-05 y 05-03 |
| Composición de software (SCA) | CVE en dependencias · no ve fallos en tu propio código | pip-audit, grype, osv-scanner |
Snyk, Mend | §5 |
| Análisis estático (SAST) | Patrones inseguros en el código propio · no ve lo que depende del entorno | semgrep, bandit, CodeQL |
Checkmarx, Fortify | §6 y 05-05 |
| Escáner de secretos · de contenedores | Claves en el historial de git · CVE de la imagen y malas prácticas del Dockerfile |
gitleaks · trivy, grype |
GitGuardian · Aqua | §5-§6, 05-05 y 05-07 |
| Configuración cloud e IaC | Buckets públicos, permisos excesivos, cifrado ausente · no ve la aplicación | prowler, ScoutSuite, checkov, tfsec |
Wiz, Orca | 05-07 |
| Configuración del sistema | Desviación frente a una línea base CIS · no ve CVE de aplicación | lynis, OpenSCAP |
Tenable | 05-06 |
La columna importante es «qué no ve». El IDOR que Nimbus corrigió con WHERE tenant_id no lo encuentra ninguna de estas familias: no es una versión antigua ni un patrón evidente, es un fallo de autorización que exige entender el negocio. Por eso el escaneo se complementa con revisión de código (05-05) y pruebas manuales (05-03), y por eso ningún escáner puede firmar que un sistema es seguro.
- Descubrimiento de red con nmap
nmap responde a la pregunta que Nimbus no sabe contestar: ¿qué hay escuchando ahí fuera y ahí dentro?
# 1) Que maquinas estan vivas en la VLAN de usuarios de Valencia
sudo nmap -sn 10.20.10.0/24 -oA /var/log/nimbus-scan/oficina-hosts
# 2) Superficie completa de la VPC, ejecutado DESDE el bastion
sudo nmap -sS -sV --version-intensity 5 -p- --max-retries 2 -T4 --open \
-oA /var/log/nimbus-scan/vpc-interno 10.30.10.0/24 10.30.20.0/24 10.30.90.0/24
# 3) La misma infraestructura vista desde INTERNET
nmap -Pn -sV --top-ports 1000 --reason -oA /var/log/nimbus-scan/externo \
api.nimbusreservas.example preprod.nimbusreservas.example| Opción | Qué hace | Por qué importa aquí |
|---|---|---|
-sn / -sS |
Descubrir hosts sin escanear puertos / SYN scan que no completa la conexión | El primero se compara con el inventario de 01-04; el segundo es rápido y fiable, y requiere privilegios |
-sV |
Interroga el servicio para deducir producto y versión | Convierte «5432 abierto» en «PostgreSQL 14.7», que es lo que se cruza con las CVE |
-p- / --top-ports 1000 |
Los 65.535 puertos / los más usados | El python -m http.server escuchaba en 8000, fuera del top 1000; pero un -p- externo tarda horas y se reserva para la pasada mensual |
-Pn |
No comprobar si el host vive antes de escanear | Obligatorio desde Internet: casi todo bloquea ICMP y sin -Pn no encontrarías nada |
-T4 |
Plantilla de temporización agresiva (0-5) | Equilibrio en red propia; T5 pierde precisión y T1-T2 son para no disparar detecciones |
--reason / -oA |
Por qué clasifica así cada puerto / guarda en los tres formatos | Distingue «filtrado» de «cerrado»; y sin la salida anterior no hay diferencial, que es el 90 % del valor |
Salida real del escaneo externo:
Nmap scan report for preprod.nimbusreservas.example (203.0.113.47)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.1
443/tcp open ssl/http syn-ack nginx 1.18.0 (Ubuntu)
5432/tcp open postgresql syn-ack PostgreSQL DB 14.7 - 14.9
6379/tcp open redis syn-ack Redis key-value store 6.0.16
8000/tcp open http syn-ack SimpleHTTPServer 0.6 (Python 3.10.6)
Nmap scan report for api.nimbusreservas.example (203.0.113.20)
443/tcp open ssl/http syn-ack nginx 1.24.0
22/tcp filtered ssh no-responseLos hallazgos de 01-04, ahora medidos y con fecha: 5432 accesible desde Internet confirma R-03 (solo lo protege una contraseña); 6379 con Redis sin autenticación es R-07; 8000 es el python -m http.server olvidado 94 días; y el contraste entre 22/tcp open en preproducción y filtered en producción demuestra que en producción sí hay una regla y en preproducción no. A-22 es hoy el eslabón más débil de Nimbus.
Hacen falta los dos puntos de vista y miden cosas distintas. El externo (mensual automatizado, control C-10) mide la superficie que ve un atacante de Internet, es decir, la exposición. El interno (trimestral, desde el bastión y desde la VLAN de usuarios) mide lo que alcanza quien ya está dentro o un portátil comprometido, y por tanto revela fallos de segmentación y movimiento lateral: es el que habría descubierto, antes del incidente, que desde la red de administración se alcanzaba la zona de datos sin control intermedio (día 1-4 de 02-06).
- Escáner de vulnerabilidades: Greenbone/OpenVAS
nmap dice qué hay; el escáner dice qué le pasa a lo que hay. Greenbone Community Edition (el antiguo OpenVAS) es gratuito y suficiente para Nimbus. Solo hace dos cosas, y conviene no atribuirle magia:
- Comparar versiones contra una base de vulnerabilidades. Es rápido y es la fuente de casi todos los falsos positivos: las distribuciones parchean sin subir el número visible (backporting).
- Comprobaciones activas: envía una petición y observa la respuesta —si acepta TLS 1.0, si un panel responde con credenciales por defecto—. Más lento y mucho más fiable.
# Definir objetivo y tarea, y lanzarla; todo automatizable desde cron
gvm-cli socket --xml '<create_target><name>VPC produccion</name>
<hosts>10.30.10.0/24,10.30.20.0/24</hosts></create_target>'
gvm-cli socket --xml '<create_task><name>Mensual autenticado</name>
<config id="daba56c8-73ec-11df-a475-002264764cea"/><target id="TARGET_ID"/></create_task>'
gvm-cli socket --xml '<start_task task_id="TASK_ID"/>'El config id es la plantilla de escaneo (Full and fast equilibra cobertura y tiempo). Un escáner que hay que lanzar a mano se lanza dos veces al año: se programa o no existe.
Autenticado frente a no autenticado
| No autenticado | Autenticado | |
|---|---|---|
| Cómo funciona | Sondea desde fuera y deduce | Entra por SSH y lee el sistema por dentro |
| Qué ve | Servicios expuestos y sus banners | Todos los paquetes, parches, configuración, usuarios |
| Hallazgos por servidor Linux | 8-15 | 60-150 |
| Falsos positivos | Muchos (por backporting) | Pocos: compara la versión real del paquete |
| Riesgo | Ninguno | La credencial del escáner es un activo crítico |
Encuentra mucho más porque deja de adivinar: sin credenciales no ve una biblioteca vulnerable que no escucha en ningún puerto, y la mayoría de las vulnerabilidades del sistema son exactamente eso. Para Nimbus: cuenta svc-scanner sin sudo, clave Ed25519 dedicada (03-06), origen restringido y rotación semestral.
== Informe Greenbone · Escaneo mensual autenticado · 2026-04-06 ==
6 hosts analizados · 1h42m · 3 Alto · 11 Medio · 24 Bajo · 63 Log
[10.0] 10.30.90.7 Redis sin autenticacion accesible en red
Comprobacion ACTIVA: se ejecuto INFO sin credenciales QoD 99%
Solucion: requirepass + bind 127.0.0.1 + grupo de seguridad
[9.8] 10.30.20.5 PostgreSQL accesible desde 0.0.0.0/0
Comprobacion ACTIVA: conexion establecida desde origen externo QoD 98%
[7.5] 10.30.10.11 OpenSSL 3.0.2-0ubuntu1.9 - CVE-2026-1000
Comprobacion de VERSION del paquete (escaneo autenticado) QoD 97%
[5.3] 10.30.10.11 nginx 1.18.0 - multiples CVE
Comprobacion de VERSION por banner remoto QoD 30%
^-- baja confianza: probable backport de la distribucionTres claves de lectura: QoD (Quality of Detection) es el campo más útil y el más ignorado —99 % con comprobación activa es un hecho, 30 % por banner es una hipótesis, así que se empieza por QoD alto y no por CVSS alto—; los 63 «Log» no son ruido, son inventario para 01-04; y un informe sin hallazgos solo significa que el escáner no encontró nada de lo que sabe buscar: el IDOR de A-04 nunca aparecerá aquí.
- Dependencias y contenedores
El 80 % del código que ejecuta la API no lo escribió Iván: son dependencias. Es la superficie que más crece y la más barata de medir.
--requirement audita las dependencias fijadas del proyecto (sin ella auditas la máquina) y --strict falla también si algo no se pudo analizar: tratar un «no lo sé» como «está bien» es la raíz de los falsos negativos.
Found 3 known vulnerabilities in 2 packages
Name Version ID Fix Versions
jinja2 3.1.2 GHSA-h5c8-rqwp-cp95 3.1.3
requests 2.28.1 GHSA-j8r2-6x86-q33q 2.31.0
requests 2.28.1 GHSA-9wx4-h78v-vm56 2.32.0La de requests es la relevante: la API llama a la pasarela y al proveedor de correo con esa biblioteca. La de jinja2 solo afecta a plantillas del panel interno. Misma severidad nominal, prioridad muy distinta.
trivy image --severity HIGH,CRITICAL --ignore-unfixed \
--scanners vuln,secret,misconfig --format table \
registry.nimbus.example/api:2026.04.1--severity HIGH,CRITICAL filtra el ruido (una imagen base típica arroja 300 hallazgos bajos, e incluirlos garantiza que no se mire ninguno); --ignore-unfixed oculta lo que aún no tiene parche, y es la opción más discutible —política de Nimbus: usarla en el CI para no bloquear por algo irresoluble y no usarla en el informe mensual—; y --scanners vuln,secret,misconfig añade secretos en las capas y malas prácticas del Dockerfile: tres herramientas por el precio de una.
registry.nimbus.example/api:2026.04.1 (debian 12.4) Total: 14 (HIGH 12, CRITICAL 2)
┌───────────┬───────────────┬──────────┬───────────────┬──────────────┐
│ libssl3 │ CVE-2026-1000 │ CRITICAL │ 3.0.11-1 │ 3.0.13-1 │
│ zlib1g │ CVE-2026-1001 │ HIGH │ 1:1.2.13.dfsg │ 1:1.2.13-1+u1│
│ perl-base │ CVE-2026-1002 │ HIGH │ 5.36.0-7 │ (no fijado) │
└───────────┴───────────────┴──────────┴───────────────┴──────────────┘
Secret api/.env.sample AWS Access Key ID (linea 4) <-- revisarVulnerabilidad presente ≠ vulnerabilidad explotable. perl-base está en la imagen porque lo arrastra la base de Debian, pero la API nunca ejecuta Perl: está presente y no es alcanzable. Dos conceptos lo formalizan:
- Alcanzabilidad: ¿hay un camino de ejecución desde el código de Nimbus hasta la función vulnerable? Analizarlo descarta hasta el 70 % de los hallazgos.
- VEX (Vulnerability Exploitability eXchange): documento firmado en el que declaras, por CVE y producto, si te afecta (
affected,not_affected,fixed,under_investigation) y por qué.
Nimbus emite su VEX junto al SBOM de 04-04: cuando una clínica pregunte por una CVE famosa, la respuesta será un documento y no una llamada de urgencia. La respuesta a un hallazgo no explotable no es ignorarlo, es documentarlo. Y la vía más eficaz para reducir su número es cambiar a una imagen base mínima o distroless (05-07), que elimina de golpe el 80 % de estas líneas.
- Análisis estático de código y escaneo de secretos
bandit -r app/ -ll -f json -o /tmp/bandit.json
semgrep --config=p/python --config=p/security-audit --sarif -o /tmp/semgrep.sarif app/-ll limita a severidad media o superior; --sarif produce el formato estándar que GitHub muestra en su pestaña de seguridad. Hallazgo real en el código de Nimbus:
>> Issue: [B501:request_with_no_cert_validation] Requests call with verify=False
Severity: High Confidence: High CWE-295 app/integrations/pasarela.py:44# ANTES — el `verify=False` que apareció en el módulo 2. Desactiva la validación
# del certificado: cualquiera en la ruta puede interponerse y leer o alterar la
# peticion de pago. TLS sin validacion no protege de nada (03-05).
r = requests.post(URL_PASARELA, json=payload, verify=False, timeout=10)
# DESPUÉS — validacion activa y confianza acotada de forma explicita.
r = requests.post(
URL_PASARELA,
json=payload,
verify="/etc/ssl/certs/ca-certificates.crt", # cadena de confianza explicita
timeout=(3.05, 10), # conexion y lectura por separado
)
r.raise_for_status()El SAST acierta aquí porque verify=False es un patrón textual inequívoco, y falla con el IDOR porque saber que falta WHERE tenant_id exige entender el modelo de datos. Regla: encuentra errores de patrón, no errores de razonamiento. En 05-05 escribirás una regla semgrep propia que sí detecta el patrón concreto de Nimbus.
--log-opts="--all" es la opción crítica: sin ella solo mira el árbol actual; con ella recorre todos los commits y ramas. Un secreto borrado al día siguiente sigue en el historial y sigue siendo válido.
Finding: DATABASE_URL=postgresql://nimbus_api:[email protected]:5432/nimbus
RuleID: postgres-connection-string
File: deploy/docker-compose.override.yml
Commit: a91f3c7 (2024-11-02) Author: [email protected]Es el riesgo R-06 y la escalada del día 5 de 02-06. Corrección en este orden: (1) rotar la credencial hoy —está comprometida desde 2024 y borrar el fichero no la invalida; es el paso urgente y el que casi todos posponen—; (2) moverla al gestor de secretos (03-06); (3) reescribir el historial con git filter-repo, que es cosmética comparada con el paso 1; y (4) gitleaks como hook de pre-commit y paso bloqueante del CI (control C-12).
- Priorización: CVSS, EPSS, KEV y exposición
Aquí el proceso se gana el sueldo. Un escaneo de Nimbus produce ~180 hallazgos y Lucía tiene 440 h/año para todo. Ordenar por CVSS descendente es el error más extendido del sector.
| Grupo CVSS | Qué mide | Quién lo calcula |
|---|---|---|
| Base | Gravedad intrínseca e invariable | El fabricante o el NVD (9.8 por ejecución remota sin autenticación) |
| Temporal (Amenaza en v4) | Si hay exploit público y si hay parche | Se actualiza con el tiempo: 9.8 baja a 8.5 sin exploit conocido |
| Ambiental | Tu entorno: criticidad del activo y controles presentes | Solo tú: 9.8 en una máquina aislada baja a 4.0 |
El grupo ambiental es el que convierte una lista genérica en una lista tuya, y el único que nadie puede calcular por ti. A él se suman dos señales externas:
- EPSS (FIRST): probabilidad de que una CVE sea explotada en los próximos 30 días, de 0 a 1, actualizada a diario. Más del 90 % de las CVE tienen EPSS < 0,05; una minoría concentra casi toda la explotación real.
- KEV (CISA): catálogo de vulnerabilidades con explotación confirmada en el mundo real. No es predicción, es un hecho observado; la lista es corta y consultarla es gratis.
Regla operativa de Nimbus: todo lo que esté en KEV y sea accesible se trata como crítico, tenga el CVSS que tenga. Una de 7.5 en KEV es más urgente que una de 9.8 con EPSS 0,001.
| Prioridad | Criterio | Plazo |
|---|---|---|
| P0 Emergencia | En KEV y expuesto a Internet, o compromiso activo | 24 h, fuera de ventana si hace falta |
| P1 Crítica | CVSS ≥ 9.0 o EPSS ≥ 0,10 sobre activo crítico accesible | 7 días (coincide con C-16) |
| P2 Alta | CVSS 7.0-8.9 sobre activo crítico, o KEV no expuesto | 30 días |
| P3 Media | CVSS 4.0-6.9, o alta sobre activo no crítico | 90 días |
| P4 Baja | CVSS < 4.0 o no alcanzable (documentado en VEX) | Siguiente ciclo o excepción con caducidad |
Los plazos cuentan desde el descubrimiento, no desde la publicación de la CVE. Y si un P1 no llega a plazo no se reetiqueta a P2: se abre una excepción firmada (04-02). Rebajar la prioridad para que el cuadro de mando quede verde es la forma más común de corromper el proceso.
"""Ordena hallazgos combinando gravedad, explotacion real y exposicion."""
HALLAZGOS = [ # id, cvss, epss, kev, expuesto, activo, criticidad(1-5)
("CVE-2026-1000", 9.8, 0.72, True, True, "A-04 API", 5),
("CVE-2026-1002", 8.1, 0.004, False, False, "A-04 (perl)", 5),
("REDIS-SIN-AUTH",10.0, 0.90, True, True, "A-22 preprod", 2),
("CVE-2026-1010", 7.5, 0.31, True, False, "A-01 BD", 5),
("CVE-2026-1044", 9.1, 0.002, False, False, "A-14 portatiles",3),
]
def prioridad(cvss, epss, kev, expuesto, criticidad):
base = cvss / 10.0 # 1) gravedad normalizada
explotacion = 1.0 if kev else min(1.0, epss * 3) # 2) KEV es HECHO; EPSS, matiz
exposicion = 3.0 if expuesto else 1.0 # 3) alcanzable triplica urgencia
importancia = criticidad / 5.0 # 4) inventario de 01-04
return round(base * (0.3 + 0.7 * explotacion) * exposicion * importancia, 3)
filas = [(prioridad(c, e, k, x, cr), i, a) for i, c, e, k, x, a, cr in HALLAZGOS]
for p, ident, activo in sorted(filas, reverse=True):
plazo = "24 h" if p >= 2.0 else "7 dias" if p >= 1.0 else "30 dias" if p >= 0.4 else "90 dias"
print(f"{p:>6} {ident:<16} {activo:<18} -> {plazo}") 2.940 CVE-2026-1000 A-04 API -> 24 h
2.250 CVE-2026-1010 A-01 BD -> 24 h
1.200 REDIS-SIN-AUTH A-22 preprod -> 7 dias
0.257 CVE-2026-1002 A-04 (perl) -> 90 dias
0.230 CVE-2026-1044 A-14 portatiles -> 90 diasLo que revela el resultado: REDIS-SIN-AUTH tiene el CVSS más alto (10.0) y cae al tercer puesto por vivir en un activo de criticidad 2; CVE-2026-1044 tiene 9.1 —más que la 1010, de 7.5— y queda última porque ni está en KEV, ni es alcanzable, ni afecta a un activo crítico. Ordenar por CVSS habría puesto a Lucía a trabajar tres días en las dos vulnerabilidades menos urgentes. Aviso honesto: que A-22 tenga criticidad 2 es la clasificación documentada, y el inventario admite que está «a revisar». Si preproducción tiene copia de datos reales, su criticidad es 5 y el Redis sube al primer puesto: revisar esa celda es más rentable que cualquier escaneo.
- Falsos positivos, falsos negativos y validación
| Definición | Coste | Ejemplo en Nimbus | |
|---|---|---|---|
| Falso positivo | Reporta algo que no existe o no aplica | Tiempo y pérdida de credibilidad del proceso | nginx 1.18.0 marcado pese al backport de Ubuntu |
| Falso negativo | No reporta algo que sí existe | Riesgo real no gestionado | El IDOR, que ningún escáner detectó |
Validación de un hallazgo, en orden de coste: (1) comprobar la versión real del paquete (dpkg -l | grep nginx) resuelve el 60 % de los falsos positivos de infraestructura; (2) leer el aviso de la distribución (USN de Ubuntu, DSA de Debian), que dice si esa versión ya está corregida; (3) comprobar la alcanzabilidad; (4) reproducir de forma no destructiva solo si persiste la duda —verificar que un puerto responde o que falta una cabecera, nunca explotar en producción: esa conversación es de 05-03—; y (5) documentar la decisión, apta o no, porque un falso positivo cerrado sin registrar reaparece cada mes y cuesta lo mismo cada vez.
Un escáner nunca sustituye al criterio. No sabe que A-01 contiene historiales que revelan información de salud, ni que A-19 tiene acceso permanente, ni que preproducción quizá tenga datos reales, ni puede encontrar un fallo de autorización. Mide versiones y configuraciones: el riesgo lo pone el contexto, y el contexto lo pone una persona. Eso se escribe en la declaración de limitaciones del informe (§10).
- Integración en el ciclo y métricas del proceso
| Momento | Qué se ejecuta | Duración | ¿Bloquea? |
|---|---|---|---|
| Cada pull request | gitleaks, semgrep, pip-audit |
< 3 min | Sí: secretos y críticas nuevas |
| Cada despliegue | trivy sobre la imagen final |
< 2 min | Sí, según umbral |
| Semanal | ZAP baseline contra preproducción (05-05) | 20 min | No: informa |
| Mensual (C-10) | nmap externo + Greenbone autenticado + prowler (05-07) |
2-4 h | No: hallazgos con dueño |
| Tras cambios de infra. | nmap externo diferencial |
10 min | No: alerta de puerto nuevo |
El último es el más barato y el más infravalorado: comparar el escaneo de hoy con el de ayer y avisar solo de lo nuevo es lo que habría detectado el http.server el mismo día, y no 94 días después.
# .github/workflows/seguridad.yml
name: Analisis de seguridad
on:
pull_request:
push: { branches: [main] }
schedule: [{ cron: "0 5 * * 1" }] # lunes: captura CVE nuevas SIN cambios de codigo
permissions: { contents: read, security-events: write }
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # historial COMPLETO: sin esto gitleaks no ve el pasado
- uses: gitleaks/gitleaks-action@v2 # BLOQUEANTE: un secreto nunca se negocia
- name: Dependencias Python
run: |
pip install pip-audit
pip-audit -r requirements.txt --strict --format json -o pip-audit.json || true
# `|| true` deja que el umbral lo aplique NUESTRA politica, no el binario
- run: python ci/umbral.py pip-audit.json --fallar-si CRITICAL,HIGH-KEV
- run: docker build -t nimbus/api:${{ github.sha }} .
- uses: aquasecurity/trivy-action@master
with:
image-ref: nimbus/api:${{ github.sha }} # la imagen de ESTE commit, no :latest
severity: CRITICAL,HIGH
ignore-unfixed: true # no bloquear por lo que aun no tiene parche
exit-code: "1" # 1 = build roto si queda algo sobre el umbral
format: sarif
output: trivy.sarif
- if: always() # publicar TAMBIEN cuando el paso anterior falla
uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: trivy.sarif }El principio de diseño: bloquear lo accionable e informar de lo que no lo es. Un pipeline que rompe el build por hallazgos que nadie puede corregir termina desactivado en dos semanas, y entonces no protege de nada. Y el criterio de fallo lo decide Nimbus (ci/umbral.py), no una herramienta que cambia de versión: externalizarlo es ceder el gobierno del riesgo.
| Métrica | Tipo | Objetivo | Qué revela al fallar |
|---|---|---|---|
| Cobertura del escaneo | KPI | 100 % | Mírala primero: el resto de métricas mienten si no es 100 %. Es la que más sorpresas da: suele revelar que el 30 % no cubierto era preproducción |
| MTTR por prioridad | KRI | P1 ≤ 7 d · P2 ≤ 30 d | Capacidad insuficiente o proceso de parcheo roto |
| Críticas abiertas fuera de plazo | KRI | 0 | Es la cifra del comité: si crece, hay que invertir o aceptar formalmente |
| Tasa de reapertura y % cerrados con reescaneo | KPI | < 5 % · 100 % | Se cierra sin verificar: «cerrado» significa «alguien dijo que sí» |
- El informe de vulnerabilidades
| Destinatario | Qué necesita | Extensión |
|---|---|---|
| Marta (dirección) | Riesgo de negocio, tendencia y qué decisión se le pide | 1 página: semáforo, 3 cifras, 1 petición |
| Lucía (sistemas) | Qué toca, en qué máquina, con qué comando y para cuándo | Tabla ordenada por prioridad |
| Iván (desarrollo) | Fichero, línea, corrección y prueba de regresión | Issues en el repositorio, no un PDF |
| Cliente o auditor (06-04) | Que existe proceso, cadencia y evidencia | 1-2 páginas sin detalle explotable |
Estructura del informe mensual: resumen ejecutivo, alcance y limitaciones, metodología y versiones de las herramientas, hallazgos priorizados, tendencia, cerrados y verificados, y anexo técnico. Las limitaciones son lo que protege honestamente al lector: dicen qué no se escaneó y qué fallos estas herramientas no encuentran.
### VUL-2026-014 · PostgreSQL de produccion accesible desde Internet
- **Prioridad:** P0 (KEV no · CVSS 9.8 · **expuesto** · activo A-01, criticidad 5)
- **Activo:** `db-prod-1` (10.30.20.5) · **Riesgo asociado:** R-03 (04-01)
- **Descubierto:** 2026-04-06, escaneo externo mensual (C-10) · **Plazo:** 2026-04-07
**Descripcion.** El grupo de seguridad permite 5432/tcp desde `0.0.0.0/0`. Cualquier
equipo de Internet puede intentar autenticarse; la unica proteccion es la contrasena
del rol `nimbus_api`, sin limite de intentos.
**Evidencia.**
$ nmap -Pn -p 5432 -sV 203.0.113.47
5432/tcp open postgresql PostgreSQL DB 14.7 - 14.9 (syn-ack)
**Impacto en el negocio.** Acceso a los datos de 40 clinicas, incluidos historiales
que revelan indirectamente informacion de salud. Equivale al dia 5 de 02-06. Brecha
notificable bajo RGPD (06-03).
**Correccion.** Restringir la regla de entrada a `10.30.10.0/24`. Sin ventana de
mantenimiento: la API conecta por la ruta interna. **Esfuerzo: 20 minutos.**
**Verificacion.** Reescaneo externo de 5432; estado esperado `filtered`, mas prueba
de humo de la API. **Dueno:** Lucia · **Estado:** AbiertoLos cinco elementos que convierten un hallazgo en accionable: evidencia reproducible, impacto de negocio y no solo técnico, corrección concreta con esfuerzo estimado, criterio de verificación explícito y un dueño con nombre. El error más frecuente es entregar el volcado de la herramienta: 300 páginas sin priorizar que garantizan que no se corrija nada, porque nadie sabe por dónde empezar.
Errores Comunes y Consejos
- Escanear una vez al año y llamarlo gestión de vulnerabilidades. El inventario cambia cada semana; mejor mensual, automatizado y revisado.
- Ordenar por CVSS y empezar por arriba. Sin exposición, EPSS/KEV y criticidad del activo dedicarás el tiempo a lo que menos importa. Es el error más caro de la lección.
- Escanear sin credenciales «para no molestar». Pierdes entre el 70 y el 85 % de los hallazgos del sistema; el escaneo autenticado es la mejora individual más rentable.
- Olvidar preproducción. A-22 tiene hoy más puertos abiertos que producción. El atacante no distingue entornos: distingue puertas.
- Bloquear el CI con umbrales imposibles, o cerrar hallazgos sin verificar. Lo primero acaba con el pipeline desactivado; lo segundo convierte «cerrado» en «alguien dijo que sí». Vigila la tasa de reapertura.
- Consejo: empieza por el diferencial. Antes de montar Greenbone, automatiza un
nmapexterno semanal que compare con el anterior y guarda siempre la salida cruda con fecha (-oA, JSON, SARIF): es tu serie histórica, y sin tendencia no hay conversación con dirección. Media hora de trabajo que habría evitado dos de los cuatro hallazgos de 01-04. - Consejo: si solo recuerdas una regla, que sea esta. Una CVE en KEV y expuesta se trata hoy.
Ejercicios
Ejercicio 1 — Interpretar un escaneo y decidir el orden de trabajo
Lucía lanza el primer escaneo externo mensual y obtiene:
Nmap scan report for pruebas-2019.nimbusreservas.example (203.0.113.61)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
443/tcp open ssl/http Apache httpd 2.4.29
3306/tcp open mysql MySQL 5.7.33- ¿Qué hay que averiguar sobre
pruebas-2019antes incluso de mirar las versiones? - Ordena las acciones de la primera semana justificando el orden con los criterios de §7.
- ¿Qué le falta a este escaneo para que el proceso sea completo?
Ejercicio 2 — Priorizar cinco hallazgos
Ordena y asigna plazo según la política de §7, justificando cada decisión:
| # | Hallazgo | CVSS | EPSS | KEV | Expuesto | Activo |
|---|---|---|---|---|---|---|
| A | RCE en biblioteca de imágenes del panel interno | 9.8 | 0.02 | No | No | A-04 (crítico) |
| B | Redis sin autenticación en preproducción | 10.0 | 0.90 | Sí | Sí | A-22 (a revisar) |
| C | TLS 1.0 en un subdominio de marketing | 5.3 | 0.01 | No | Sí | Web estática |
| D | Credencial de PostgreSQL en el historial de git desde 2024 | — | — | — | — | A-10, A-01 |
| E | Escalada local en el kernel de los portátiles | 7.8 | 0.15 | Sí | No | A-14 |
Ejercicio 3 — Corregir un pipeline
Identifica al menos cinco problemas en la propuesta de Iván y explica cómo se corrige cada uno.
name: seguridad
on: { workflow_dispatch: {} }
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: gitleaks detect --source .
- run: trivy image nimbus/api:latest --exit-code 1
- run: pip-auditSoluciones
Ejercicio 1
(1) La primera pregunta no es técnica, es de inventario: ¿qué es pruebas-2019, quién lo puso, qué datos contiene y sigue haciendo falta? Ese nombre sugiere un entorno de hace siete años que nadie mantiene y que no está en el inventario de 01-04 ni en el alcance de ningún parcheo. Si nadie lo sabe, la corrección no es parchearlo: es apagarlo tras confirmar que nada depende de él, conservando una copia. Apagar es la corrección más barata, más rápida y más definitiva que existe, y la que menos se considera.
(2) Orden de la primera semana:
- MySQL 3306 expuesto (P0, 24 h). Es el patrón de R-03 pero peor: base de datos accesible desde Internet en un host sin mantenimiento desde 2019, con credenciales probablemente débiles. Se cierra en el firewall hoy, antes de investigar nada.
- Determinar si contiene datos personales reales (P0, en paralelo). Si los contiene y llevaba años expuesto, deja de ser un hallazgo técnico: es una posible brecha con obligaciones del RGPD (06-03) y activación del plan de 04-05.
- Apagar el host (P1, 7 días) una vez confirmado que nada depende de él. Apache 2.4.29 acumula años de CVE: parchearlo es invertir en algo que debe desaparecer.
- Añadirlo al inventario y revisar el DNS buscando más subdominios olvidados: que apareciera en un escaneo y no en el inventario significa que la cobertura no era del 100 %.
(3) Qué falta: el escaneo solo mira los puertos habituales de nombres que alguien recordaba. Faltan la enumeración de subdominios desde la zona DNS, un -p- mensual (el http.server del 8000 no sale en --top-ports 1000), escaneo UDP básico, escaneo interno desde la VLAN de usuarios y desde la VPC para medir la segmentación, y las capas que nmap no cubre: escáner autenticado, SCA, SAST y configuración cloud. nmap es el 15 % del proceso.
Ejercicio 2
| Orden | # | Prioridad | Plazo | Justificación |
|---|---|---|---|---|
| 1.º | D | P0 | 24 h | No tiene CVSS porque no es una CVE, y es lo más grave: una credencial válida de la base de datos crítica, expuesta desde 2024. No hay que explotar nada, basta con usarla. Es R-06 y el día 5 de 02-06. Rotar hoy; limpiar el historial puede esperar |
| 2.º | B | P0 | 24 h | KEV + EPSS 0,90 + expuesto: los tres factores al máximo. La baja criticidad nominal de A-22 no lo rescata, porque está «a revisar» y probablemente comparte red o datos con producción. Cerrar el puerto son minutos |
| 3.º | E | P2 | 30 días | Está en KEV, la explotación es real, pero es escalada local: exige que el atacante ya esté en el portátil. Es el segundo eslabón de la cadena, no el primero. Se agrupa con el parcheo gestionado del parque (05-06) |
| 4.º | A | P2 | 30 días | 9.8 sobre activo crítico, pero no expuesto y EPSS 0,02. Aquí es donde ordenar por CVSS falla: parece la primera y es la cuarta. Conviene confirmar la alcanzabilidad; si el panel no procesa imágenes de usuario, baja a P3 y se documenta en VEX |
| 5.º | C | P3 | 90 días | Expuesto pero de bajo impacto: web estática, sin datos ni sesiones. Una línea de nginx (03-05) en el siguiente mantenimiento. Tratarlo como urgente «porque sale en rojo» es justo el error que la política evita |
Observación transversal: los dos primeros no requieren parche, sino un cambio de configuración y una rotación de credencial, ambos gratuitos y de minutos. Lo más urgente casi nunca es lo más caro.
Ejercicio 3
workflow_dispatchcomo único disparador: solo se ejecuta a mano, es decir, casi nunca. Faltanpull_request,pushamainy unscheduleque capture CVE nuevas sin cambios de código.checkoutsinfetch-depth: 0:gitleakssolo ve el último commit, así que los secretos del historial —el caso real de Nimbus— pasan desapercibidos indefinidamente.trivy image nimbus/api:latest: escanea una etiqueta que no es la imagen que este cambio construye. Se valida una imagen y se despliega otra; hay que construir y escanear por SHA del commit.--exit-code 1sin--severity: bloquea con cualquier hallazgo, incluidos los informativos y los que no tienen parche. Se desactivará en dos semanas.pip-auditsin-r requirements.txt: audita el entorno del runner, no el proyecto; puede pasar en verde con dependencias vulnerables.- No se publica ningún resultado y no hay
permissionsexplícitas: sin SARIF ni artefactos no hay historial, tendencia ni evidencia para 04-03, y el token opera con más permisos de los necesarios, contra el mínimo privilegio de 01-03.
La versión corregida es la del apartado 9, con fetch-depth: 0, los tres disparadores, permissions acotadas, umbral propio en ci/umbral.py, imagen etiquetada por SHA y publicación SARIF con if: always().
Conclusión
Has convertido el «verificar» del módulo 4 en un proceso medible. Sabes que la gestión de vulnerabilidades es un ciclo —inventariar, descubrir, priorizar, remediar, verificar e informar— y no un PDF anual, y que el paso 0 manda: sin inventario no hay cobertura, y sin cobertura las demás métricas mienten. Conoces el mapa de las nueve familias de herramientas y, sobre todo, qué no ve ninguna: el IDOR de Nimbus no aparece en ningún escáner, porque estas herramientas detectan errores de patrón y no errores de razonamiento.
Manejas nmap opción a opción y sabes por qué el escaneo externo y el interno miden cosas distintas; con él has reencontrado con fecha y evidencia los cuatro hallazgos de 01-04. Sabes qué hace realmente un escáner de vulnerabilidades, por qué el escaneo autenticado encuentra entre cinco y diez veces más, y a leer un informe empezando por el QoD. Con pip-audit y trivy distingues vulnerabilidad presente de vulnerabilidad explotable, con la alcanzabilidad y el documento VEX como forma correcta de decir «no nos afecta» sin perder trazabilidad. Con semgrep, bandit y gitleaks has cerrado el verify=False y has encontrado la credencial de PostgreSQL en el historial, cuya corrección empieza por rotarla y no por borrar el fichero. Y te llevas la parte que separa un proceso útil de una hoja de cálculo inútil: priorizar con CVSS base/temporal/ambiental, EPSS como probabilidad y KEV como hecho observado, la política de plazos P0-P4 y un cálculo que reordena la lista hasta dejar la CVE de 9.1 en el último puesto; validar falsos positivos en cinco pasos; integrarlo todo en un pipeline que bloquea lo accionable e informa del resto; y redactar un hallazgo accionable con evidencia, impacto de negocio, corrección estimada, verificación y dueño.
Pero fíjate en el límite de todo lo anterior: este proceso encuentra puertas mal cerradas; no ve a nadie entrando por ellas. Si mañana un atacante usa la credencial de la consultora a las 22:14, ningún escáner de esta lección se enterará: el puerto está legítimamente abierto y la credencial es válida. Ese es el hueco que dejó veinte días de silencio en el incidente de 02-06 y que el catálogo de 04-03 refleja con ocho controles detectivos de los que solo dos están implantados. En Técnicas de Monitoreo y Detección (05-02) construimos por fin esos controles: qué registrar, dónde centralizarlo, cómo escribir detecciones que se disparen con lo que importa y callen con lo que no, y cómo reducir el tiempo de permanencia del atacante de veinte días a una mañana.
Curso de Fundamentos de Seguridad Informática
Módulo 1: Introducción a la Seguridad Informática
- Conceptos Básicos de Seguridad Informática
- Tipos de Amenazas y Vulnerabilidades
- Principios de la Seguridad Informática
- Activos, Superficie de Ataque y Actores de Amenaza
Módulo 2: Ciberseguridad
- Definición y Alcance de la Ciberseguridad
- Tipos de Ataques Cibernéticos
- Ingeniería Social y Phishing
- Medidas de Protección en Ciberseguridad
- Identidad, Autenticación y Control de Acceso
- Casos de Estudio de Incidentes de Ciberseguridad
Módulo 3: Criptografía
- Introducción a la Criptografía
- Criptografía Simétrica
- Criptografía Asimétrica
- Funciones Hash, HMAC y Almacenamiento de Contraseñas
- Protocolos Criptográficos
- Gestión de Claves, Certificados y PKI
- Aplicaciones de la Criptografía
Módulo 4: Gestión de Riesgos y Medidas de Protección
- Evaluación de Riesgos
- Políticas de Seguridad
- Controles de Seguridad
- Riesgo de Terceros y Cadena de Suministro
- Plan de Respuesta a Incidentes
- Recuperación ante Desastres y Continuidad de Negocio
Módulo 5: Herramientas y Técnicas de Seguridad
- Herramientas de Análisis de Vulnerabilidades
- Técnicas de Monitoreo y Detección
- Pruebas de Penetración
- Seguridad en Redes
- Seguridad en Aplicaciones
- Hardening de Sistemas y Seguridad del Endpoint
- Seguridad en la Nube y en Contenedores
Módulo 6: Buenas Prácticas y Normativas
- Buenas Prácticas en Seguridad Informática
- Normativas y Estándares de Seguridad
- Protección de Datos Personales y RGPD en la Práctica
- Cumplimiento y Auditoría
- Formación y Concienciación
- Ética, Aspectos Legales y Divulgación Responsable
