feat(recon): grupo de reconocimiento de red + servicios + fingerprint web
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>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
---
|
||||
name: rdap_lookup
|
||||
kind: function
|
||||
lang: py
|
||||
domain: cybersecurity
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def rdap_lookup(target: str, timeout_s: int = 30) -> dict"
|
||||
description: "Lookup RDAP de un dominio, IP o ASN via el CLI `rdap` (openrdap, ~/go/bin/rdap). RDAP es el reemplazo moderno de WHOIS sobre HTTP/JSON. Resuelve el binario con shutil.which y fallback a ~/go/bin/rdap, ejecuta `rdap --json <target>`, captura el JSON crudo en raw y lo parsea a dict. Extrae handle y ldhName. Devuelve siempre un dict {status: ok|error}; nunca lanza excepciones. OSINT pasivo: datos de registro estructurados de dominios, redes IP y autonomous systems."
|
||||
tags: [recon, rdap, osint-passive, cybersecurity]
|
||||
params:
|
||||
- name: target
|
||||
desc: "Dominio (ej. google.com), direccion IP, o ASN con prefijo AS (ej. AS15169). Vacio devuelve status error."
|
||||
- name: timeout_s
|
||||
desc: "Segundos maximo de espera del subproceso rdap (default 30)."
|
||||
output: "dict. En exito: {status: 'ok', target, raw (JSON crudo como string, SIEMPRE presente), data (dict parseado o None), handle (data['handle'] o None), ldhName (data['ldhName'] o None)}. Si el JSON no parsea: status 'ok' con data=None y clave 'warning'. En fallo de ejecucion (binario ausente, timeout, salida vacia): {status: 'error', error: str, target}."
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_py_core"
|
||||
imports: []
|
||||
tested: true
|
||||
tests: ["test_target_vacio_devuelve_error", "test_parseo_json_sample", "test_estructura_dict_de_error"]
|
||||
test_file_path: "python/functions/cybersecurity/rdap_lookup_test.py"
|
||||
file_path: "python/functions/cybersecurity/rdap_lookup.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from cybersecurity import rdap_lookup
|
||||
|
||||
info = rdap_lookup("google.com")
|
||||
if info["status"] == "ok":
|
||||
print(info["handle"]) # '2138514_DOMAIN_COM-VRSN'
|
||||
print(info["ldhName"]) # 'GOOGLE.COM'
|
||||
print(info["data"]["status"]) # ['client transfer prohibited', ...]
|
||||
# info["raw"] tiene el JSON RDAP completo para guardar en OSINT
|
||||
else:
|
||||
print("fallo:", info["error"])
|
||||
|
||||
# Tambien acepta IPs y ASNs:
|
||||
rdap_lookup("8.8.8.8")
|
||||
rdap_lookup("AS15169")
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Usala cuando quieras datos de registro **estructurados (JSON)** de un dominio,
|
||||
una IP o un ASN: handle, ldhName, eventos de registro/expiracion, entidades,
|
||||
nameservers, estado. RDAP es mas limpio y parseable que el texto WHOIS, asi que
|
||||
preferela para enriquecer entidades OSINT programaticamente. Combina con
|
||||
`whois_lookup_py_cybersecurity` cuando el TLD no tenga RDAP desplegado y
|
||||
necesites caer al WHOIS clasico (texto crudo).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- IMPURA: hace red via el bootstrap RDAP. Sujeta a latencia y rate-limit del
|
||||
servidor RDAP autoritativo; por eso hay `timeout_s` (default 30) y los fallos
|
||||
devuelven `{"status": "error", ...}` sin lanzar.
|
||||
- **RDAP no cubre todos los TLDs**: muchos ccTLDs y algunos gTLDs aun no lo
|
||||
tienen desplegado. En esos casos `rdap` falla y conviene caer a
|
||||
`whois_lookup_py_cybersecurity`.
|
||||
- El binario `rdap` (openrdap) suele NO estar en el PATH de un subproceso: se
|
||||
resuelve con `shutil.which("rdap")` y fallback a `~/go/bin/rdap`. Si no se
|
||||
encuentra, devuelve status error con instruccion de instalacion
|
||||
(`go install github.com/openrdap/rdap/cmd/rdap@latest`).
|
||||
- El flag es `--json` (equivalente corto `-j`). Se usa `--json`.
|
||||
- Si la salida no es JSON parseable (error textual del CLI capturado como
|
||||
stdout), devuelve `status: ok` con `data=None`, `handle=None`, `ldhName=None`
|
||||
y una clave `warning`; el JSON/texto crudo siempre esta en `raw`.
|
||||
- El registrante personal suele estar redactado por privacy/GDPR en las
|
||||
entidades RDAP.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v1.0.0 (2026-06-14) — version inicial. Wrapper del CLI openrdap `rdap`, acepta
|
||||
dominios/IPs/ASNs, estilo dict `{status: ok|error}` sin excepciones.
|
||||
Reference in New Issue
Block a user