935008ec3f
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>
5.4 KiB
5.4 KiB
name, kind, lang, domain, version, purity, signature, description, tags, params, output, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path
| name | kind | lang | domain | version | purity | signature | description | tags | params | output | uses_functions | uses_types | returns | returns_optional | error_type | imports | tested | tests | test_file_path | file_path | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| grab_service_banner | function | py | cybersecurity | 1.0.0 | impure | def grab_service_banner(host: str, port: int, timeout_s: float = 3.0, send_probe: bool = True) -> dict | Captura el banner de un servicio TCP y lo identifica heuristicamente sin nmap -sV. Abre un socket TCP a host:port, opcionalmente envia un probe (HEAD / HTTP/1.0 para puertos web), lee hasta ~4096 bytes con timeout y reconoce el servicio (ssh, ftp, smtp, http, mysql/mariadb, redis, pop3, imap, telnet, ...) por heuristica sobre el banner, extrayendo producto y version best-effort. Complementa a un port scan: el scan dice si el puerto esta abierto, esta funcion dice QUE servicio y version hablan detras. Solo stdlib (socket, re, struct). NO lanza: devuelve dict status ok/error con campo raw (repr del banner crudo). |
|
|
dict de estado. ok: {status:'ok', host, port:int, service:str (ssh|ftp|smtp|http|mysql|redis|pop3|imap|telnet|ftp-or-smtp|unknown), product:str (best-effort, p.ej. OpenSSH/nginx/Postfix/MySQL; '' si no se extrae), version:str (best-effort, p.ej. '8.9p1'; '' si no se extrae), banner:str (banner decodificado y .strip()), raw:str (repr() del banner crudo en bytes, seguro para guardar)}. error: {status:'error', error:str, host, port}. Nunca lanza excepciones. | false | error_py_core | true |
|
python/functions/cybersecurity/grab_service_banner_test.py | python/functions/cybersecurity/grab_service_banner.py |
Ejemplo
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from cybersecurity import grab_service_banner
# 1) Identificar el servicio SSH del host oficial de pruebas de nmap (legal).
res = grab_service_banner("scanme.nmap.org", 22, timeout_s=5)
if res["status"] == "ok":
print(res["service"]) # "ssh"
print(res["product"]) # "OpenSSH"
print(res["version"]) # "8.9p1" (o similar)
print(res["banner"]) # "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.1"
else:
print("error:", res["error"])
# 2) Identificar un servidor web: el probe HTTP provoca respuesta con Server:.
res = grab_service_banner("scanme.nmap.org", 80, timeout_s=5)
print(res["service"], res["product"], res["version"]) # http nginx 1.18.0
Tambien via fn run tras indexar:
./fn run grab_service_banner_py_cybersecurity
(El smoke del modulo sondea scanme.nmap.org:22 y tolera fallos de red.)
Cuando usarla
Usala cuando YA sabes que un puerto esta abierto (p.ej. tras un escaneo de
puertos) y quieres identificar el servicio y su version de forma rapida para un
puerto concreto, sin levantar nmap -sV. Encaja como segundo paso de recon:
primero localizas los puertos abiertos de un host, luego compones esta funcion
sobre cada puerto interesante para etiquetar QUE habla detras (ssh, http, mysql,
redis, ...) y guardar el banner como evidencia en la nota OSINT.
Gotchas
- Funcion impura: abre una conexion TCP real al objetivo. Solo sondea hosts propios o con autorizacion explicita; conectar a servicios de terceros sin permiso puede ser ilegal.
- TLS/HTTPS implicito (443, 993, 995, 465, ...): el servicio espera un handshake
TLS antes de hablar, asi que el banner plano que captura esta funcion NO
funciona ahi — devolvera bytes binarios ilegibles o timeout, con
service:"unknown". Para esos puertos hay que envolver el socket en TLS (ssl.SSLSocket) primero; esta funcion no lo hace. - Banner pasivo no garantizado: algunos servicios no emiten nada hasta completar
un handshake especifico del protocolo. Para esos casos
bannerpuede venir vacio yservice:"unknown"aunque el puerto este abierto. El probe HTTP solo cubre los puertos web listados en el mapa interno; otros protocolos quedarian sin probe activo. - Decodificacion best-effort: el banner se decodifica utf-8 y cae a latin-1, lo
que puede dar mojibake en bytes no textuales (handshakes binarios como MySQL).
Por eso
rawguarda elrepr()de los bytes crudos como fuente fiable. - La identificacion es heuristica (regex/substring): puede equivocarse o quedar
como
service:"unknown".product/versionson best-effort y pueden ser "". - Nunca lanza: revisa siempre
res["status"]antes de leerservice/banner. Puerto cerrado/filtrado/inalcanzable devuelvestatus:"error".