Añade el capability group `recon` (dominio cybersecurity + pipelines, Python),
con la política de archivado OSINT y página madre docs/capabilities/recon.md.
Lookups y sondeo (wrappers de CLI):
- whois_lookup, rdap_lookup, dns_records, ping_host, traceroute_host, nmap_scan
- save_scan_to_osint (sink común) + recon_osint (pipeline one-shot scan+archivado)
Escaneo de puertos/servicios nativo (stdlib, sin nmap ni sudo):
- scan_tcp_ports: connect-scan TCP concurrente (open/closed/filtered)
- grab_service_banner: banner grab + identificación de servicio/versión real
- identify_port_service: puro, puerto -> servicio IANA esperado (~120 puertos)
- scan_port_services: pipeline one-shot (scan -> identify + banner por puerto abierto)
Fingerprint de tecnología web (estilo Wappalyzer), patrón pura/impura:
- fetch_http_fingerprint: GET stdlib, recoge headers/html/cookies (solo nombres)
- detect_web_tech: puro, matchea ~50 firmas regex -> tecnologías por categoría
- fingerprint_web_stack: pipeline one-shot url -> tecnologías
Todas devuelven dict {status} sin lanzar. Tests: 43 verdes, sin red externa.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
16 KiB
Capability: recon
Reconocimiento de red para OSINT desde el registry: lookups de registro (WHOIS/RDAP), DNS, sondeo de disponibilidad y ruta (ping/traceroute), escaneo de puertos y servicios, y fingerprint de la tecnologia web de un sitio (estilo Wappalyzer). El escaneo de puertos tiene dos caminos: el wrapper pesado de nmap (perfiles, scripts NSE, versiones), y un camino nativo en Python puro (scan_tcp_ports + grab_service_banner + identify_port_service, solo stdlib, sin nmap ni sudo) para escaneo rapido y portable. El fingerprint web sigue el mismo patron pura/impura: fetch_http_fingerprint recoge las señales (headers, html, cookies) y detect_web_tech (pura) matchea firmas para identificar servidor, CMS, frameworks JS, analytics y CDN. La mayoria de funciones son Python impuras, wrappean CLIs del sistema (whois, rdap, dig, ping, traceroute, nmap) o usan sockets/urllib stdlib, y devuelven siempre un dict {status: ok|error} sin lanzar excepciones. El grupo cierra el bucle con un sink comun que archiva cada escaneo en el ecosistema OSINT (nota Obsidian + registro DuckDB) y pipelines one-shot que escanean y guardan en una sola llamada.
Comparte tag y dominio (cybersecurity) con el grupo osint-passive (recoleccion no intrusiva desde fuentes publicas), del que reutiliza primitivas. La regla de operacion es la misma del project osint: todo escaneo se archiva en OSINT.
Funciones
| ID | Firma | Que hace |
|---|---|---|
whois_lookup_py_cybersecurity |
whois_lookup(target, timeout_s=30) -> dict |
Lookup WHOIS via el CLI whois. Captura el raw completo y parsea best-effort registrar, registrant_country, creation_date, expiry_date, updated_date, name_servers. Acepta dominio o IP. |
rdap_lookup_py_cybersecurity |
rdap_lookup(target, timeout_s=30) -> dict |
Lookup RDAP (reemplazo JSON moderno de WHOIS) via el CLI openrdap rdap. Devuelve data (dict JSON), handle, ldhName y el raw. Acepta dominio, IP o ASN (AS15169). |
dns_records_py_cybersecurity |
dns_records(domain, record_types=None, timeout_s=20) -> dict |
Registros DNS via dig +short (default A, AAAA, MX, NS, SOA, TXT, CNAME). Devuelve records (dict por tipo) y raw legible por bloque para el vault. |
ping_host_py_cybersecurity |
ping_host(host, count=4, timeout_s=30) -> dict |
Sondeo ICMP via ping. Devuelve loss_pct, rtt_avg_ms (y min/max), packets_sent/recv, raw. Host filtrado = status:ok con loss_pct=100, no error. |
traceroute_host_py_cybersecurity |
traceroute_host(host, max_hops=30, timeout_s=60) -> dict |
Traza la ruta via traceroute. Devuelve hops (lista de {hop, hosts:[{name, ip, rtt_ms}]}) y raw. Hops filtrados (* * *) = hosts: []. |
nmap_scan_py_cybersecurity |
nmap_scan(target, profile="quick", ports=None, extra_args=None, out_dir=None, timeout_s=1800) -> dict |
Escaneo de puertos/servicios via nmap por perfiles (salida XML parseada). Devuelve open_ports, hosts_up, xml_path, raw, elapsed_s. Funcion estrella del grupo. |
scan_tcp_ports_py_cybersecurity |
scan_tcp_ports(host, ports="common", timeout_s=1.0, workers=100) -> dict |
Connect-scan TCP nativo (stdlib, sin nmap ni sudo). Escanea puertos en paralelo con threads y clasifica cada uno en open/closed/filtered. ports acepta lista, preset "common", rango "1-1024" o CSV. Devuelve open (lista de ints), ip, raw. NO detecta version de servicio. |
grab_service_banner_py_cybersecurity |
grab_service_banner(host, port, timeout_s=3.0, send_probe=True) -> dict |
Banner grab nativo (stdlib, sin nmap -sV). Abre socket TCP, lee el banner e identifica el servicio real (ssh, http, ftp, smtp, mysql, redis, pop3, imap, telnet...) extrayendo product y version best-effort. Dice QUE habla detras de un puerto abierto. TLS/HTTPS no da banner plano. |
identify_port_service_py_cybersecurity |
identify_port_service(port, proto="tcp") -> dict |
Pure. Mapea un puerto a su servicio IANA well-known esperado por convencion ({service, description, known}) desde una tabla embebida (~120 puertos). No sondea en vivo: dice que se ESPERA, no que hay. |
save_scan_to_osint_py_cybersecurity |
save_scan_to_osint(target, scan_type, raw, summary=None, vault_dir="~/Obsidian/osint", service_url="http://127.0.0.1:8771", tool=None) -> dict |
Sink OSINT. Archiva un scan: nota Markdown tipada en el vault (capa critica) + POST a osint_db para registro DuckDB (best-effort). Devuelve note_path, registered, scan_id. |
recon_osint_py_pipelines |
recon_osint(target, scan_type="whois", save=True, profile="quick", ...) -> dict |
Pipeline one-shot. Ejecuta un scan del tipo pedido y lo archiva en OSINT en una sola llamada (compone la funcion de scan + save_scan_to_osint). El camino canonico para recon + archivado. |
scan_port_services_py_pipelines |
scan_port_services(host, ports="common", timeout_s=1.0, workers=100, grab_banners=True, banner_timeout_s=3.0, save=True) -> dict |
Pipeline one-shot nativo. Escanea puertos y, por cada abierto, devuelve servicio esperado (IANA) + servicio/version real del banner. Compone scan_tcp_ports + identify_port_service + grab_service_banner (+ sink OSINT). Reemplaza el patron scan→identify→grab sin nmap. |
fetch_http_fingerprint_py_cybersecurity |
fetch_http_fingerprint(url, timeout_s=15.0, verify_tls=True, max_html_bytes=500000, user_agent=None) -> dict |
Fetch de señales web (stdlib). GET con UA de navegador, sigue redirects, descomprime gzip. Devuelve headers (lowercase), cookies (solo NOMBRES, sin valores), html, title, server, status_code, final_url, raw. Capa impura del fingerprint web. |
detect_web_tech_py_cybersecurity |
detect_web_tech(headers, html="", cookies=None, final_url="") -> dict |
Pure. Detector de tecnologia web estilo Wappalyzer. Matchea ~50 firmas embebidas (regex) contra headers/html/cookies → technologies[{name, category, version, confidence, evidence}], by_category, count. Cubre server, lenguaje, CMS, frameworks JS, librerias, analytics, CDN, e-commerce, WAF. |
fingerprint_web_stack_py_pipelines |
fingerprint_web_stack(url, timeout_s=15.0, verify_tls=True, max_html_bytes=500000, save=True) -> dict |
Pipeline one-shot = Wappalyzer del registry. url → tecnologias detectadas. Compone fetch_http_fingerprint + detect_web_tech (+ sink OSINT). El camino canonico para fingerprint web. |
OSINT pasivo relacionado
Estas funciones llevan tambien el tag recon (y osint-passive): recoleccion no intrusiva desde fuentes publicas, sin tocar al objetivo. Utiles antes o junto al escaneo de red. Pagina madre completa: docs/capabilities/osint-passive.md.
| ID | Firma | Que hace |
|---|---|---|
build_search_dorks_py_cybersecurity |
build_search_dorks(target, tipo="persona", extra_domains=None) -> list |
Pure. Genera dorks de buscador (frase exacta, site:, filetype:, leaks/pastebin) segun el tipo de target. Sin red. |
enum_subdomains_crtsh_py_cybersecurity |
enum_subdomains_crtsh(dominio, timeout_s=20.0) -> list |
Enumera subdominios desde Certificate Transparency (crt.sh). Dedup, ordenado, sin wildcards. |
enumerate_username_sites_py_cybersecurity |
enumerate_username_sites(username, timeout_s=8.0, sites=None) -> list |
Comprueba si un username existe en ~12 sitios publicos (estilo sherlock ligero) por codigo HTTP. |
guess_email_formats_py_cybersecurity |
guess_email_formats(nombre, apellidos, dominio) -> list |
Pure. Genera candidatos de email comunes (nombre.apellido, inicial+apellido, ...). Sin red. |
enrich_org_passive_py_cybersecurity |
enrich_org_passive(dominio) -> dict |
Orquestador: perfil pasivo de una organizacion componiendo whois + dns + subdominios crt.sh. |
Ejemplo canonico end-to-end
1. One-shot (preferido): escanear y archivar en una llamada. El pipeline corre el scan y lo guarda en OSINT (nota + registro DuckDB) por ti.
cd /home/enmanuel/fn_registry
./fn run recon_osint ejemplo.com whois
Equivalente desde Python (cuando necesitas el dict de resultado):
python/.venv/bin/python3 - <<'PYEOF'
import sys
sys.path.insert(0, "python/functions")
from pipelines.recon_osint import recon_osint
res = recon_osint("ejemplo.com", scan_type="whois", save=True)
print(res["status"], res.get("note_path"), res.get("registered"))
PYEOF
2. Manual atomico + sink. Cuando quieres controlar el scan (perfil, puertos, summary propio) y guardarlo aparte. La funcion de scan se importa, no se reescribe.
cd /home/enmanuel/fn_registry
python/.venv/bin/python3 - <<'PYEOF'
import sys
sys.path.insert(0, "python/functions")
from cybersecurity import dns_records
from cybersecurity.save_scan_to_osint import save_scan_to_osint
scan = dns_records("ejemplo.com") # 1. escanear
if scan["status"] == "ok":
saved = save_scan_to_osint( # 2. archivar en OSINT
"ejemplo.com",
"dns",
scan["raw"],
summary={"A": scan["records"].get("A"), "MX": scan["records"].get("MX")},
tool="dig",
)
print(saved["note_path"], "registered:", saved["registered"])
PYEOF
3. nmap largo en segundo plano. Los perfiles pesados tardan de minutos a horas: lanzalos en background con out_dir (conserva el XML) y timeout_s alto, y archiva al terminar.
cd /home/enmanuel/fn_registry
# El pipeline one-shot tambien sirve para nmap; lanzar en background por la duracion:
nohup ./fn run recon_osint scanme.nmap.org nmap --profile full-tcp --timeout-s 7200 \
> /tmp/recon-fulltcp.log 2>&1 &
scanme.nmap.orges el host oficial de pruebas de nmap (legal escanear). Cualquier otro objetivo de terceros exige autorizacion.
4. Escaneo nativo de servicios de puertos (sin nmap), one-shot. Cuando no quieres depender de nmap/sudo o buscas un barrido rapido y portable: el pipeline scan_port_services escanea los puertos y, por cada abierto, dice el servicio esperado por convencion (IANA) y el servicio/version real leido del banner.
cd /home/enmanuel/fn_registry
python/.venv/bin/python3 - <<'PYEOF'
import sys
sys.path.insert(0, "python/functions")
from pipelines.scan_port_services import scan_port_services
res = scan_port_services("scanme.nmap.org", ports="common", save=True)
print(res["status"], "abiertos:", res.get("open_ports"))
for s in res.get("services", []):
print(f" {s['port']}: esperado={s['expected_service']} real={s.get('actual_service')} version={s.get('version')}")
PYEOF
Las primitivas tambien sirven sueltas: scan_tcp_ports(host, ports) para solo el estado de los puertos, grab_service_banner(host, port) para identificar un servicio concreto, e identify_port_service(port) (pura) para el servicio esperado por convencion.
5. Fingerprint de tecnologia web (Wappalyzer del registry), one-shot. Identifica el stack de un sitio — servidor, lenguaje, CMS, frameworks JS, analytics, CDN — desde el HTML + cabeceras + cookies, sin ejecutar JS. El pipeline fingerprint_web_stack hace fetch + matching de firmas en una llamada.
cd /home/enmanuel/fn_registry
python/.venv/bin/python3 - <<'PYEOF'
import sys
sys.path.insert(0, "python/functions")
from pipelines.fingerprint_web_stack import fingerprint_web_stack
res = fingerprint_web_stack("https://example.com", save=True)
print(res["status"], "->", res.get("count"), "tecnologias")
for t in res.get("technologies", []):
print(f" {t['name']} [{t['category']}] v={t['version']!r} ({t['confidence']})")
PYEOF
Las dos capas tambien sueltas: fetch_http_fingerprint(url) para inspeccionar cabeceras+html+cookies crudos de una URL, y detect_web_tech(headers, html, cookies) (pura) para matchear firmas sobre señales ya recogidas (testeable sin red).
Limite: un fetch estatico NO ejecuta JavaScript. Una SPA que monta su framework en runtime (React/Vue con HTML inicial vacio) puede no detectarse. Para esos casos, recoger el DOM renderizado via el grupo
browser(CDP) y pasar ese html adetect_web_tech.
Integracion OSINT
Cada escaneo guardado acaba en dos sitios, y por eso save_scan_to_osint (y el pipeline recon_osint) son el cierre obligatorio del grupo:
- Nota Markdown en el vault
~/Obsidian/osintbajodominios/<slug>/recon/<scan_type>-<YYYYMMDD-HHMM>.md. Frontmatter tipado (tipo: scan-red,scan_tipo,target,slug,fecha,herramienta,tags: [scan-red, <scan_type>, recon]) y elrawdel scan en un bloque de codigo. Es la capa critica: si falla, el sink devuelvestatus:error. - Fila en la tabla DuckDB
network_scans(schemamain) del serviceosint_db, viaPOST http://127.0.0.1:8771/api/scan. Columnas:id, target, target_slug, scan_type, tool, scan_ts, note_path, summary(JSON), created_at. Es la capa best-effort: si el service esta caido o no expone el endpoint, el sink degrada a solo-nota conregistered=False+register_warning, sin romper. El re-ingest del vault NO borra esta tabla.
REGLA: todo escaneo se guarda en OSINT. No hay scans "sueltos". O usas el
pipeline recon_osint (scan + archivado en 1 call), o llamas la funcion de scan
atomica y a continuacion save_scan_to_osint con su raw. El slug del target se
deriva con re.sub(r"[^a-z0-9._-]+", "-", target.lower()).
Escaneos nmap utiles para segundo plano
Los perfiles pesados de nmap_scan deben lanzarse en background (& / nohup / run_in_background) por su duracion. Pasa out_dir para conservar el XML y sube timeout_s.
| Perfil | Flags nmap | Cuando usarlo | Duracion |
|---|---|---|---|
full-tcp |
-p- -T4 |
Mapear los 65535 puertos TCP (no solo el top 1000). Cuando buscas servicios en puertos no estandar. | Minutos a horas → background |
vuln |
-sV --script vuln -T4 |
Correr los scripts NSE de vulnerabilidades sobre los servicios detectados. Fase posterior a un service scan. | Largo, ruidoso → background |
udp-top |
-sU --top-ports 100 -T4 |
Descubrir servicios UDP (DNS, SNMP, NTP...). UDP es lento y suele requerir sudo. | Largo → background |
service |
-sV -sC -T4 |
Deteccion de version + scripts default sobre puertos abiertos. A veces tolerable en primer plano. | Medio (puede ir a background) |
aggressive |
-A -T4 |
OS + version + scripts + traceroute de golpe. Muy detectable; el -O interno puede pedir sudo. |
Largo, ruidoso → background |
Perfiles ligeros que SI corren bien en primer plano: quick (-T4 -F, top 100), top1000 (-T4), discovery (-sn, ping sweep de una subred → puebla hosts_up), os (-O, requiere sudo).
Prerequisitos
- CLIs instaladas en el PATH:
whois(apt install whois),rdap(openrdap, normalmente en~/go/bin/rdap—go install github.com/openrdap/rdap/cmd/rdap@latest),dig(dnsutils/bind-utils),ping(iputils-ping),traceroute,nmap. Si falta el binario, la funcion devuelvestatus:errorcon la instruccion de instalacion, nunca lanza. - Privilegios: los perfiles de nmap
os(-O),udp-top(-sU) y parte deaggressiverequieren sudo/root; sin privilegios nmap cae a connect-scan TCP y esos modos quedan incompletos (estas funciones no usan sudo). - Service
osint_dbvivo enhttp://127.0.0.1:8771para el registro estructurado ennetwork_scans. Si esta caido, los scans siguen guardandose como nota (solo se pierde la fila DuckDB hasta el siguiente re-registro). Ver memoriaosint-duckdb-stack.
Fronteras (que NO cubre)
- No es un framework de explotacion. Es reconocimiento: identifica superficie (puertos, servicios, versiones, registro, ruta). No explota vulnerabilidades, no hace fuerza bruta de credenciales, no entrega payloads. Para eso, herramientas dedicadas fuera del registry.
- Solo hosts autorizados o propios. Escanear infraestructura de terceros sin permiso explicito puede ser delito.
scanme.nmap.orges el unico host de terceros legal por defecto (es el host oficial de pruebas de nmap). - No evade deteccion. No implementa tecnicas de evasion de IDS/WAF, fragmentacion, decoys ni timing de sigilo;
-T4es ruidoso a proposito. Un objetivo que defienda activamente puede detectar y filtrar el escaneo. - No cubre OSINT pasivo de personas (dorks, usernames, emails) mas alla de listar las funciones afines: esas viven en el grupo
osint-passive. El render BD→nota y el grafo del vault son deobsidian/duckdb.