Teoria vs Practica Cloud Red Team
Teoría vs Práctica — Cloud Red Teaming (AWS / Azure / GCP)
Este documento conecta los conceptos teóricos de seguridad en cloud con lo que realmente hicimos en cada laboratorio. El objetivo es que entiendas por qué cada paso funciona y cómo se aplica la teoría en un entorno real.
Índice
- El Trío de la Explotación Cloud
- OSINT y Reconocimiento
- Fuga de Código Fuente (.git)
- SSRF + RCE — El Caballo de Troya Web
- Instance Metadata Service (IMDS)
- IAM / RBAC / Cloud IAM
- Storage Buckets
- APIs de Gestión Cloud
- Glosario Rápido
1. El Trío de la Explotación Cloud
Los tres labs comparten la misma cadena de ataque con adaptaciones específicas de cada proveedor:
Fuga de información
↓
Puerto de entrada (app web con SSRF + RCE)
↓
Metadata Service (http://169.254.169.254/)
↓
Credenciales temporales
↓
Enumeración de recursos cloud
↓
Extracción de datos sensibles
| Proveedor | IMDS Header | Formato de credenciales | API de gestión |
|---|---|---|---|
| AWS | Ninguno (IMDSv1) | AccessKeyId + SecretAccessKey + Token | AWS CLI / API |
| Azure | Metadata: true |
access_token (JWT) | Azure REST API |
| GCP | Metadata-Flavor: Google |
access_token (OAuth2) | Cloud Resource Manager API |
2. OSINT y Reconocimiento
Teoría
El OSINT (Open Source Intelligence) en cloud consiste en descubrir recursos expuestos sin necesidad de credenciales. Las empresas suelen nombrar sus recursos con patrones predecibles (prod, dev, staging, test, etc.).
Práctica
| Lab | Herramienta | Concepto | Lo que pasó |
|---|---|---|---|
| AWS | cloud_enum |
Brute-force de naming permutations | El bucket cwl-metatech-prod estaba público. cloud_enum prueba cientos de combinaciones (cwl-metatech-{prod,dev,test,1,2,...}) contra S3. |
| Azure | gobuster dns |
Enumeración de subdominios | internal.meta-tech.cloud resolvió a una IP de Azure. Un subdominio "internal" que debería ser privado estaba expuesto. |
| GCP | GitHub search | Supply chain recon / secret leakage | El repo público cwl-metatech/production-data contenía una key de service account en base64 dentro de un pipeline CI/CD. |
Conexión teoría-práctica
OSINT cloud:
├── Buckets S3 → cloud_enum, bucketkicker
├── Subdominios → gobuster, subfinder, amass
├── Repos GitHub → búsqueda manual, trufflehog, git-secrets
└── Certificates → crt.sh, censys
3. Fuga de Código Fuente (.git)
Teoría
Por defecto, los servidores web sirven archivos estáticos. Si el directorio .git (repositorio de Git) está accesible, cualquier persona puede descargar todo el historial del proyecto, incluyendo:
- Código fuente completo
- Credenciales hardcodeadas (aunque se hayan "eliminado" en commits posteriores)
- Configuraciones de infraestructura
- Keys de API
Práctica
Tanto AWS como Azure tenían .git expuesto en la raíz del servidor web. Usamos git-dumper para clonar el repositorio remoto.
git-dumper http://IP/.git /tmp/gitdump
Esto nos permitió leer process.php y descubrir las vulnerabilidades SSRF y RCE.
Diferencia clave entre Git y Cloud: El .git es una mala práctica de desarrollo, no un problema de cloud. Pero es el vector de ataque inicial que permite acceder al cloud.
4. SSRF + RCE — El Caballo de Troya Web
Teoría
SSRF (Server-Side Request Forgery): Vulnerabilidad que permite a un atacante hacer que el servidor web haga peticiones HTTP a destinos arbitrarios. En cloud, el destino más valioso es http://169.254.169.254/ — la IP mágica del Metadata Service.
RCE (Remote Code Execution): Permite ejecutar comandos arbitrarios en el servidor. Útil para ejecutar curl contra el metadata service y obtener credenciales.
Práctica
Los tres labs tenían el mismo process.php:
$ip = $_POST['ip'];
$content = file_get_contents($ip); // SSRF
$org = $_POST['organization'];
$org_output = system($org); // RCE
echo $org_output, $content;
| Campo | Uso normal | Uso malicioso |
|---|---|---|
ip |
Validar IP del site | http://169.254.169.254/... (SSRF) |
organization |
Nombre de la organización | curl -s http://169.254.169.254/... (RCE) |
Conexión teoría-práctica
Servidor web vulnerable
├── El parámetro "ip" se pasa a file_get_contents()
│ → No hay validación → SSRF
│ → Podemos pedirle al servidor que consulte cualquier URL
│
├── El parámetro "organization" se pasa a system()
│ → No hay sanitización → RCE
│ → Podemos ejecutar cualquier comando del sistema
│
└── Metadata Service (169.254.169.254)
→ Es una IP link-local, solo accesible desde la máquina
→ Devuelve credenciales temporales de la instancia
→ AWS: sin header | Azure: Metadata:true | GCP: Metadata-Flavor:Google
5. Instance Metadata Service (IMDS)
Teoría
El Metadata Service es un endpoint HTTP interno en 169.254.169.254 que todas las instancias cloud tienen. Proporciona:
- Información de la instancia (IP, hostname, zona)
- Credenciales temporales del IAM role / managed identity asociado
Esto es por diseño: las aplicaciones dentro de la instancia necesitan credenciales sin tener que almacenarlas.
Práctica
| Concepto | AWS | Azure | GCP |
|---|---|---|---|
| URL base | /latest/meta-data/ |
/metadata/instance?api-version=2021-02-01 |
/computeMetadata/v1/ |
| Header requerido | ❌ Ninguno | ✅ Metadata: true |
✅ Metadata-Flavor: Google |
| Credenciales | /latest/meta-data/iam/security-credentials/{role} |
/metadata/identity/oauth2/token?resource={api}&api-version=2018-02-01 |
/computeMetadata/v1/instance/service-accounts/default/token |
| Formato | JSON plano | JWT | OAuth2 token |
| Lo que obtuvimos | AccessKeyId + SecretAccessKey + Token | access_token (JWT) | access_token |
Ejemplo de cómo se ve cada uno:
// AWS
{
"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-.../resourceGroups/.../it-vm"
}
// GCP
{
"access_token": "ya29.c.c0AZ4bNpa...",
"expires_in": 3599,
"token_type": "Bearer"
}
Por qué esto es crítico
SSRF + Metadata Service = credenciales cloud en 3 pasos:
1. Encuentra un SSRF en la app web
2. Apunta a http://169.254.169.254/<ruta según proveedor>
3. Obtén credenciales que te permiten usar la API de cloud
Diferencia clave: IMDSv1 vs IMDSv2
AWS tiene dos versiones:
- IMDSv1 (la que usamos): No requiere header → vulnerable a SSRF simple
- IMDSv2: Requiere header
X-aws-ec2-metadata-tokenobtenido mediante PUT request → más seguro
El lab usaba IMDSv1. En un entorno real con IMDSv2, el ataque requiere un paso extra (primero obtener el token PUT).
6. IAM / RBAC / Cloud IAM
Teoría
Cada proveedor tiene su sistema de identidad y permisos:
| 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 to User/Role | Role Assignment | IAM Policy Binding |
| Scope | ARN (recurso específico) | Scope (subscription, RG, resource) | Project, Folder, Organization |
| Política administrada | AWS Managed Policy | Built-in Role | Predefined Role |
Práctica
AWS — IAM Enumeration
Después de obtener las credenciales de EC2:
aws iam list-users # emp001, emp002, emp003, int001
aws iam list-groups # employees, interns
aws iam get-group --group-name interns # int001
aws iam list-groups-for-user --user-name emp003 # employees
aws iam list-roles # crossaccount-role, dev-role, devops-role, ec2-role
aws iam list-user-policies --user-name emp001 # s3-administrator-Policy
aws iam list-attached-group-policies --group-name employees
Lo que aprendimos de IAM en AWS:
- Los roles tienen Trust Policies que definen QUIÉN puede asumirlos
crossaccount-rolepermitía al usuariomanagerde otra cuenta (058264439561) asumirlodev-rolepermitía adevops-roleasumirlo (chain de roles)- Las inline policies están pegadas directamente al usuario (emp001)
- Las managed policies se附an a grupos (employees → AmazonDevOpsGuruFullAccess)
Azure — RBAC + Graph API
Con el token JWT de Azure:
# Management API: consultar role assignments
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'"
# Microsoft Graph API: consultar Entra ID
curl -H "Authorization: Bearer $GRAPH_TOKEN" \
"https://graph.microsoft.com/v1.0/groups?\$filter=displayName+eq+'IT+Ops'"
curl -H "Authorization: Bearer $GRAPH_TOKEN" \
"https://graph.microsoft.com/v1.0/applications?\$filter=displayName+eq+'dev-app'"
Lo que aprendimos de Azure:
- Managed Identity asigna un Service Principal a la VM
- El role assignment dice qué rol tiene esa identidad a cierto scope
- Los custom roles definen permisos específicos (ej:
Microsoft.Resources/subscriptions/resourceGroups/read) - Microsoft Graph API permite enumerar Entra ID: grupos, usuarios, aplicaciones y sus permisos
- Dos tokens distintos: Management API (Azure resources) y Graph API (Entra ID)
GCP — Cloud IAM
Con el token de la VM:
# Leer IAM policy del proyecto
curl -H "Authorization: Bearer $VM_TOKEN" \
-X POST -H "Content-Type: application/json" \
"https://cloudresourcemanager.googleapis.com/v1/projects/mcrta-exam:getIamPolicy" -d "{}"
# Leer definición de un custom role
curl -H "Authorization: Bearer $VM_TOKEN" \
"https://iam.googleapis.com/v1/projects/mcrta-exam/roles/VMReadgek"
Lo que aprendimos de GCP:
- Las service accounts son el equivalente a IAM roles en AWS
- Los custom roles definen permisos específicos (
compute.instances.list) - Los bindings asocian miembros (service accounts) a roles
- Cloud Resource Manager API expone la política IAM completa
- Distintas SAs tienen distintos niveles de acceso:
dev-service-account: solo VMReadgek (list instances)vm-service-account: roles/reader a nivel proyecto + acceso a storageterraform-automation: accesso administrativo completo
Jerarquía de permisos en cada cloud
AWS:
Cuenta → IAM User/Role → Policy (JSON con Effect/Action/Resource)
Azure:
Tenant → Subscription → Resource Group → Resource
↓
Managed Identity + Role Definition + Scope = Permiso efectivo
GCP:
Organization → Folder → Project → Resource
↓
Service Account + IAM Role + Binding = Permiso efectivo
7. Storage Buckets
Teoría
Los buckets de almacenamiento cloud son contenedores de objetos. Por defecto son privados, pero las malas configuraciones los dejan públicos.
| Proveedor | Servicio | Acceso público | Autenticación alternativa |
|---|---|---|---|
| AWS | S3 | --no-sign-request |
AWS SigV4 |
| Azure | Blob Storage | Allow anonymous access |
SAS tokens, RBAC |
| GCP | GCS (Cloud Storage) | allUsers / allAuthenticatedUsers |
OAuth2 tokens |
Práctica
| Lab | Bucket | Contenido | Cómo accedimos |
|---|---|---|---|
| AWS | cwl-metatech-prod |
dev-server-ip.txt, prod-data.txt, staging-data.txt |
Público, sin credenciales |
| GCP | stag-storage-metatech-prod11 |
license-key.txt |
Token de VM (autenticación) |
AWS: El bucket estaba completamente público — ni siquiera necesitábamos credenciales.
GCP: El bucket requería autenticación, pero el token de la VM tenía permisos roles/reader y roles/storage.admin para acceder.
8. APIs de Gestión Cloud
Teoría
Cada cloud tiene una API REST para gestionar recursos. Con credenciales válidas, podemos llamar a estas APIs para enumerar y modificar recursos.
Práctica
AWS usamos AWS CLI (que internamente llama a las APIs):
aws iam list-users # → GET /?Action=ListUsers
aws s3 ls s3://bucket # → GET /bucket
Azure usamos curl directamente contra las REST APIs:
# Management API
https://management.azure.com/subscriptions/{id}/...?api-version=2022-04-01
# Graph API
https://graph.microsoft.com/v1.0/groups/...
https://graph.microsoft.com/v1.0/applications/...
GCP mezclamos gcloud CLI y curl:
gcloud compute instances list
gcloud compute instances describe
# Cloud Resource Manager API
https://cloudresourcemanager.googleapis.com/v1/projects/{id}:getIamPolicy
# IAM API
https://iam.googleapis.com/v1/projects/{id}/roles/{role}
# Storage API
https://storage.googleapis.com/storage/v1/b/{bucket}/o
Diferencia clave:
- AWS CLI maneja automáticamente el firmado de peticiones (SigV4)
- Azure REST API usa el token JWT directamente como Bearer token
- GCP el token OAuth2 también se usa como Bearer
9. Glosario Rápido
Conceptos generales
| Término | Significado |
|---|---|
| IMDS | Instance Metadata Service — endpoint interno que da info de la instancia |
| SSRF | Server-Side Request Forgery — hacer que un servidor web pida URLs arbitrarias |
| RCE | Remote Code Execution — ejecutar comandos en un servidor remoto |
| OSINT | Open Source Intelligence — recopilación de información de fuentes públicas |
| IAM | Identity and Access Management — quién puede hacer qué en cloud |
| RBAC | Role-Based Access Control — control de acceso basado en roles |
AWS
| Término | Significado |
|---|---|
| S3 | Simple Storage Service — almacenamiento de objetos |
| IAM Role | Identidad con permisos que puede asumir un servicio (EC2, Lambda, etc.) |
| IAM User | Identidad permanente para personas o aplicaciones |
| IAM Policy | Documento JSON que define permisos |
| Trust Policy | Política que define quién puede asumir un rol |
| Inline Policy | Política embebida directamente en un usuario/rol |
| Managed Policy | Política reutilizable creada por AWS o el usuario |
| ARN | Amazon Resource Name — identificador único de un recurso AWS |
| STS | Security Token Service — servicio que emite credenciales temporales |
Azure
| Término | Significado |
|---|---|
| Managed Identity | Identidad automática asignada a un recurso Azure (similar a IAM Role) |
| Service Principal | Identidad de una aplicación en Entra ID |
| JWT | JSON Web Token — formato del token de acceso |
| Tenant ID (tid) | Identificador del inquilino de Entra ID |
| Subscription ID | Identificador de la suscripción de Azure |
| Scope | Alcance donde se aplica un role assignment |
| Role Definition | Conjunto de permisos (similar a IAM Policy) |
| Role Assignment | Asignación de un rol a un principal en un scope |
| Entra ID | Directorio de identidades de Microsoft (antes Azure AD) |
| Microsoft Graph | API unificada para acceder a Entra ID, O365, etc. |
GCP
| Término | Significado |
|---|---|
| Service Account | Identidad para aplicaciones y VMs (similar a IAM Role) |
| Project ID | Identificador único del proyecto GCP |
| Custom Role | Rol personalizado con permisos específicos |
| Binding | Asociación de un miembro a un rol en la política IAM |
| GCS | Google Cloud Storage — almacenamiento de objetos |
| Cloud Resource Manager | API para gestionar proyectos y políticas IAM |
| OAuth2 token | Formato del token de acceso de GCP |
Mapa Mental del Ataque
┌─────────────────────────┐
│ OSINT / Reconocimiento │
│ ┌──────┬──────┬──────┐ │
│ │ AWS │Azure │ GCP │ │
│ │S3 │DNS │GitHub│ │
│ └──────┴──────┴──────┘ │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ App Web Vulnerable │
│ (.git expuesto) │
│ ┌───────────────────┐ │
│ │ process.php │ │
│ │ SSRF: ip param │ │
│ │ RCE: org param │ │
│ └───────────────────┘ │
└───────────┬─────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│AWS IMDS │ │Azure IMDS│ │GCP IMDS │
│No header │ │Metadata │ │Metadata- │
│ │ │: true │ │Flavor: │
│ │ │ │ │Google │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│Credenciales AWS │JWT Token │ │OAuth2 │
│(AK+SAK+Token)│ │ Azure │ │Token GCP │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│IAM Enum │ │Azure REST│ │GCP CRM │
│AWS CLI │ │+ Graph │ │+ Storage │
│ │ │ API │ │ API │
└──────────┘ └──────────┘ └──────────┘
Conclusión
Los tres labs demuestran el mismo principio fundamental: el Metadata Service (169.254.169.254) es el "santo grial" del hacking cloud porque convierte una vulnerabilidad web (SSRF) en acceso completo a la nube.
Las diferencias entre proveedores son superficiales:
- Cambian los headers requeridos
- Cambian los formatos de las credenciales
- Cambian los nombres de los conceptos (IAM Role vs Managed Identity vs Service Account)
- Cambian las APIs para enumerar
Pero el flujo de ataque es idéntico:
Encontrar recurso expuesto → Explotar SSRF → Robar credenciales IMDS → Enumerar cloud
Y la defensa también es la misma para los tres:
- No exponer
.gitni información sensible - Validar inputs contra SSRF
- Usar IMDSv2 (AWS) / headers restrictivos
- Principio de mínimo privilegio en IAM
- Buckets privados por defecto