Volver a la wiki

Sesión 107: Auditoría Suprema — monitoring sub-área 2 (protocolos SNMP·ping·HTTP)

Descripción general

Sesión 107 de la Auditoría Suprema del dominio monitoring: auditoría y remediación de la sub-área 2 (protocolos de sondeo — SNMP, ping, HTTP). Hallazgos: 36 confirmados (4 ALTA, 17 MEDIA, 15 BAJA). Se corrigen todos los hallazgos de seguridad (ALTA) y las correcciones de bajo riesgo / correctness en una tanda única (Regla 22).

Contexto

CreaRack monitoriza dispositivos de cliente a través del Local Agent (para objetivos privados) y mediante sondeos del servidor (para objetivos públicos). Estos sondeos ejecutan HTTP (descarga de página), ping (latencia ICMP) y SNMP (métricas de interfaz) desde el propio servidor CreaRack. La auditoría halló que los sondeos no validaban correctamente sus destinos.

Hallazgos corregidos (ALTA)

1. SSRF en probes HTTP (monitoring/services/http_service.py)

Vulnerabilidad: El endpoint /targets/{id}/http/check validaba target.ip_address (público) pero sondeaba config["http_url"] (controlado por usuario). Un atacante podría:

Corrección: Nuevo guard compartido net_guard.py que:

2. Endpoints SNMP sin gate de permisos (monitoring/api/snmp.py)

Vulnerabilidad: Los 3 endpoints SNMP (snmp/test, snmp/interfaces, snmp/poll) no tenían require_perm(request, "observatory", "edit"). Cualquier usuario autenticado (incluido readonly) podía dispararlos.

Corrección: Añadido require_perm a los 3 endpoints. Usuario sin permiso recibe 403.

3. Escaneo SNMP de red interna (monitoring/api/snmp.py)

Vulnerabilidad: snmp/test e snmp/interfaces no tenían el guard is_private_ip que ya usa snmp/poll. Permitían sondear IPs internas arbitrarias (vector de escaneo de red privada).

Corrección: Añadido is_private_ip() a los 2 endpoints faltantes. Devuelven {"skipped": True, "reason": "private_ip"} sin tocar la red.

4. Inyección PromQL en grupos (monitoring/services/group_service.py)

Vulnerabilidad: query_group_metric interpolaba metric, tenant_id y target_ids en la query MetricsQL sin validar. Un metric malicioso (cpu"}} or snmp_bandwidth_in_mbps{tenant_id="99) podría romper la query y leer datos de otro tenant (cross-tenant read).

Corrección: Validación contra allowlist _VALID_METRIC_NAME (regex ^[a-zA-Z_:][a-zA-Z0-9_:]*$) para metric; .isdigit() para tenant_id y target_ids. La query no puede romperse.

Correctness + fuga de información

snmp/poll devuelve estado inválido

Problema: En caso de fallo SNMP, devolvía {"status": "error"} — pero "error" no está en STATUS_CHOICES del modelo.

Corrección: Ahora devuelve "down" (estado válido).

DoS de memoria en HTTP probe

Problema: El probe descargaba el body completo sin límite. Un servidor malicioso o un archivo grande podía agotar la RAM del worker.

Corrección:

Excepción SNMP silenciosa

Problema: get_single, walk, get_interface_traffic y test_connection tragaban excepciones sin logging. Invisible para debugging.

Corrección:

Log expone credenciales SNMP v3

Problema: network/services/device_discovery/snmp_auth.py registraba el username SNMP v3.

Corrección: Log solo muestra auth= y priv=, sin username.

Backlog (Etapa 3 — Regla 22)

Carve-outs documentados para tanda futura:

  1. Probes síncronos → async/Huey: SNMP walks, ping y HTTP bloquean el worker ASGI.
  2. Cifrado de credenciales SNMP v3: Hoy en texto plano en el config del modelo.
  3. IP-pinning anti-DNS-rebinding: net_guard hoy resuelve + rechaza; el fix de “pinning” (usar la IP resuelta en el transport, no volver a resolver) es una defensa más fuerte.
  4. Defensa en profundidad en ping_service: El caller ya guarda; considerar guard también en el servicio.
  5. Delegación en webhook validator: validate_webhook_url (ITSM sub-área 4) podría delegar en net_guard.
  6. Correlation service: Subnet IPv6, N+1 KnownIssue.
  7. ThreadPoolExecutor por request en group_service: Hoy global; considerar por request para seguridad en multi-tenant.

Testing

Cambios a nivel de API

Endpoints SNMP: nuevos esquemas de respuesta

snmp/test, snmp/interfaces:

snmp/poll:

HTTP check: error es genérico

http_service.check/check_async: En caso de excepción o bloqueo SSRF, devuelve {"status": "down", "error": "HTTP check failed"} (no expone el mensaje de excepción interno).

Véase también

Subir