feat(infra): auto-commit con 88 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user