Files
fn_registry/python/functions/cybersecurity/enum_subdomains_crtsh.py
T
egutierrez eb8dbf66a1 feat(infra): auto-commit con 88 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-11 00:16:46 +02:00

69 lines
2.4 KiB
Python

"""Enumeracion OSINT pasiva de subdominios via Certificate Transparency (crt.sh).
Funcion IMPURA: consulta los logs publicos de Certificate Transparency a
traves de crt.sh y extrae los subdominios que han aparecido en certificados
emitidos para el dominio. Es OSINT pasivo: no toca al dominio objetivo, solo
consulta registros CT publicos.
"""
import os
import sys
sys.path.insert(
0, os.path.join(os.path.dirname(__file__), "..", "..", "functions")
)
from infra.http_get_json import http_get_json # noqa: E402
def enum_subdomains_crtsh(dominio: str, timeout_s: float = 20.0) -> list:
"""Enumera subdominios de un dominio desde Certificate Transparency.
Consulta ``https://crt.sh/?q=%25.<dominio>&output=json`` (``%25`` = ``%``,
el wildcard de crt.sh) usando ``http_get_json`` del registry. crt.sh
devuelve un array JSON de certificados; de cada uno se toma el campo
``name_value`` (que puede contener varios nombres separados por saltos de
linea, uno por SAN). Se separan, deduplican, se filtran los wildcards
(``*.``) y se devuelve la lista ordenada de subdominios unicos.
Args:
dominio: Dominio base a enumerar (ej. ``"organic-machine.com"``).
timeout_s: Segundos maximo de espera de la peticion HTTP (default 20).
Returns:
Lista ordenada de subdominios unicos (sin wildcards). Lista vacia si
crt.sh no devuelve resultados.
Raises:
RuntimeError: Si el dominio esta vacio o la peticion HTTP falla.
"""
if not dominio or not dominio.strip():
raise RuntimeError("enum_subdomains_crtsh: dominio vacio")
dom = dominio.strip().lower()
# %25 es el wildcard '%' de crt.sh: busca cualquier nombre que termine en .<dominio>
url = f"https://crt.sh/?q=%25.{dom}&output=json"
data = http_get_json(url, timeout=timeout_s)
if not isinstance(data, list):
raise RuntimeError(
f"enum_subdomains_crtsh: respuesta crt.sh inesperada "
f"(tipo {type(data).__name__})"
)
found: set = set()
for cert in data:
if not isinstance(cert, dict):
continue
name_value = cert.get("name_value", "")
for raw_name in name_value.split("\n"):
name = raw_name.strip().lower()
if not name:
continue
if name.startswith("*."):
continue
found.add(name)
return sorted(found)