Files
fn_registry/python/functions/cybersecurity/detect_web_tech.md
T
egutierrez 935008ec3f 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>
2026-06-14 15:12:07 +02:00

6.2 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
detect_web_tech function py cybersecurity 1.0.0 pure def detect_web_tech(headers: dict, html: str = '', cookies: list[str] | None = None, final_url: str = '') -> dict Detector de tecnologia web estilo Wappalyzer: identifica el stack tecnologico de un sitio (web fingerprint) matcheando una tabla de firmas regex embebida contra las cabeceras HTTP, el HTML, los nombres de cookies y la URL final. Detecta servidor (nginx, Apache, IIS, LiteSpeed, Caddy), lenguaje (PHP, ASP.NET, Java, Python, Ruby, Node.js), CMS (WordPress, Drupal, Joomla, Shopify, Wix, Squarespace, Ghost), frameworks JS (React, Vue, Angular, Svelte, Next.js, Nuxt), librerias (jQuery, Bootstrap, Lodash, Modernizr), analytics/tag (Google Analytics, GTM, Facebook Pixel, Hotjar, Matomo), CDN (Cloudflare, Fastly, Akamai, CloudFront, jsDelivr, unpkg), ecommerce (WooCommerce, Magento, PrestaShop, Shopify) y WAF/seguridad (Cloudflare, Sucuri, Imperva Incapsula). Pieza pura del detector: no toca la red, recibe las senales ya recogidas por fetch_http_fingerprint.
recon
cybersecurity
web-recon
wappalyzer
fingerprint
tech-detection
cms
stack
name desc
headers dict de cabeceras de respuesta HTTP con claves en minusculas (tal como las devuelve fetch_http_fingerprint en su campo headers). Valores string. Si las claves vienen en mayusculas se normalizan internamente.
name desc
html HTML de la pagina como string. Default '' para detectar solo por cabeceras y cookies. De aqui se extraen meta generator y src de los <script>.
name desc
cookies lista de NOMBRES de cookies (no valores). Default None -> []. Ej: ['PHPSESSID', 'wordpress_logged_in'].
name desc
final_url URL final tras redirects, para firmas basadas en host/path. Opcional, default ''.
dict con technologies (lista de {name, category, version, confidence, evidence} ordenada deterministicamente por categoria y nombre), by_category (dict categoria -> lista de nombres) y count (entero). confidence es 'high' para match directo de header/meta/cookie/url y 'medium' para HTML generico, script src o tecnologia implicada. version es best-effort (a menudo ''). Para entrada vacia devuelve technologies [], by_category {}, count 0. Nunca lanza.
false
true
test_nginx_por_header_con_version
test_wordpress_por_html_y_meta_implica_php
test_php_por_cookie
test_cloudflare_por_header
test_entrada_vacia
test_entrada_vacia_explicita_headers_y_html
test_determinismo
test_count_y_by_category_consistentes
test_headers_claves_mayusculas_se_normalizan
test_jquery_por_script_src_es_medium
python/functions/cybersecurity/detect_web_tech_test.py python/functions/cybersecurity/detect_web_tech.py

Ejemplo

from cybersecurity import detect_web_tech

# Senales fake de un sitio WordPress sobre nginx.
headers = {
    "server": "nginx/1.24.0",
    "x-powered-by": "PHP/8.2",
}
html = (
    '<html><head>'
    '<meta name="generator" content="WordPress 6.4">'
    '</head><body><link href="/wp-content/themes/x/style.css"></body></html>'
)
cookies = ["PHPSESSID", "wordpress_logged_in_abc"]

result = detect_web_tech(headers, html=html, cookies=cookies)
# result["count"] == 3
# result["by_category"] == {
#     "cms": ["WordPress"],
#     "programming-language": ["PHP"],
#     "web-server": ["nginx"],
# }
# nginx -> version "1.24.0", confidence "high", evidence "header server: nginx/1.24.0"
# WordPress -> version "6.4", confidence "high", evidence "meta generator: WordPress 6.4"
# PHP -> version "8.2", confidence "high", evidence "header x-powered-by: PHP/8.2"

Flujo real componiendo con la capa impura hermana (recoleccion -> matching):

from cybersecurity import fetch_http_fingerprint, detect_web_tech

# Capa impura: recoge las senales con un GET real (red).
fp = fetch_http_fingerprint("https://example.com")
# fp = {"headers": {...lowercase...}, "html": "...", "cookies": [...], "final_url": "..."}

# Capa pura: identifica el stack sobre las senales recogidas (sin red).
tech = detect_web_tech(
    fp["headers"],
    html=fp.get("html", ""),
    cookies=fp.get("cookies"),
    final_url=fp.get("final_url", ""),
)
for t in tech["technologies"]:
    print(t["category"], t["name"], t["version"], t["confidence"])

Cuando usarla

Cuando ya tienes los headers + html (+ cookies/URL) de una URL — recogidos por fetch_http_fingerprint_py_cybersecurity — y quieres saber el stack tecnologico del sitio: servidor, lenguaje, CMS, frameworks JS, librerias, analytics, CDN, ecommerce y WAF. Usala como pieza de matching pura y testeable. Para el flujo one-shot url -> tecnologias (recoger + detectar en una llamada) usa el pipeline fingerprint_web_stack.

Gotchas

  • La tabla SIGNATURES es un subconjunto curado de lo que cubre Wappalyzer (~50 tecnologias), no es exhaustiva. Para ampliarla, anade entradas nuevas a la constante SIGNATURES del modulo siguiendo el formato documentado en el codigo (matchers headers/html/meta_generator/cookies/script_src/url, opcionales version_group e implies).
  • La deteccion por HTML generico puede dar falsos positivos: un sitio que mencione "wordpress" o "woocommerce" en su texto/blog puede matchear sin usarlo realmente. Por eso esos matches tienen confidence: "medium" mientras que header/meta/cookie directos son "high".
  • Las SPAs cargan los frameworks por JS en runtime. Un fetch estatico (sin ejecutar JavaScript) ve el HTML inicial, que en muchas SPAs esta casi vacio (<div id="root"></div>). React/Vue/Angular pueden NO detectarse si el HTML servido no contiene aun sus marcadores. Para esos casos hace falta renderizar con un navegador headless, fuera del alcance de esta funcion pura.
  • Las versiones son best-effort: solo se extraen cuando el regex que disparo tiene un group de version y este matcheo. A menudo quedan en "".
  • Es PURA y determinista: misma entrada -> misma salida. Para entrada vacia (headers={}, html="") devuelve technologies: [], count: 0 y NUNCA lanza ni reporta status/error.