Una intrusión en Azure, paso a paso (caso ficticio)
Una intrusión ficticia en Azure investigada de principio a fin: secreto filtrado, rol autoasignado, Run Command, token de identidad robado, Key Vault y blobs.
En resumen. Este caso es ficticio. Kestrel Freight no existe; su tenant, sus identidades y sus direcciones IP (rangos de documentación RFC 5737) son inventados, y los logs se generaron en los formatos reales de exportación de Azure para el botón Probar un ejemplo del analizador. En 41 minutos de un domingo por la noche, una entidad de servicio de CI/CD con el secreto filtrado se asigna Contributor, ejecuta un script en una VM, reutiliza el token de la identidad administrada de la VM, se añade a la directiva de acceso de un Key Vault, lee los 12 secretos, genera una SAS de cuenta, descarga 330 copias de seguridad de la base de datos (unos 48,6 GB) y después elimina la configuración de diagnóstico del almacén y la exportación del Activity Log. El analizador devuelve Comprometido con 11 hallazgos de gravedad alta.
Los incidentes reales son caóticos, parciales y confidenciales. Uno sintético me permite enseñar cada paso con las pruebas delante. Cárgalo tú mismo: abre el analizador Azure Forensics y pulsa Probar un ejemplo. La página muestra un aviso recordando que es el ejemplo ficticio.
El contexto
Kestrel Freight (ficticia) tiene un portal web en vm-app-01, dentro de rg-prod-app. La VM tiene una identidad administrada asignada por el sistema que lee cada hora su cadena de conexión a la base de datos en el Key Vault kv-kestrel-prod y su configuración en la cuenta de almacenamiento stkestrelbackups, donde también se guardan las copias nocturnas de la base de datos. Una entidad de servicio de CI/CD, sp-gh-deploy, despliega el portal cada mañana desde dos IP de runners. Con privilegios excesivos por comodidad, tiene User Access Administrator.
La exportación cubre del 2026-09-07 al 2026-09-14: una semana de actividad normal (el periodo de aprendizaje) y después el incidente. Contiene:
| Archivo / carpeta | Fuente | Formato |
|---|---|---|
insights-activity-logs/…/PT1H.json | Activity Log | Exportación a almacenamiento, JSON Lines |
activity-log-az-cli.json | Activity Log, día del incidente | az monitor activity-log list (esquema REST) |
insights-logs-auditevent/… | Key Vault AuditEvent | JSON Lines |
insights-logs-storageread/…, …storagewrite/… | Logs de blobs | JSON Lines |
insights-logs-flowlogflowevent/… | Flow logs de VNet | {"records": […]} |
insights-logs-networksecuritygroupflowevent/… | Flow logs de NSG v2 | {"records": […]} |
defender-alerts.json | Defender for Cloud | REST {"value": […]} |
La exportación a almacenamiento y la de la CLI se solapan el día del incidente: el analizador fusiona 11 eventos duplicados.
Primero, la cobertura
Están las cinco fuentes. El Activity Log tiene 99 eventos, Key Vault 186, almacenamiento 509, flujos 88 y Defender 1. El periodo de aprendizaje es suficiente, así que se ejecutan las reglas de primera aparición. Buena señal: un veredicto sobre estos datos tiene sentido tanto para el plano de control como para el de datos.
La cronología, minuto a minuto (UTC, 2026-09-14)
| Hora | Evento | Fuente | Hallazgo(s) |
|---|---|---|---|
| 02:14:05 | sp-gh-deploy llama a ARM desde 203.0.113.66, nunca vista antes, y se asigna Contributor en la suscripción a sí misma | Activity Log | AZ-ID-001, AZ-RBAC-002, AZ-RBAC-003 |
| 02:19:40 | runCommand/action en vm-app-01, misma entidad, misma IP | Activity Log | AZ-VM-001 |
| 02:20:05 | La VM 10.10.1.4 conecta con 203.0.113.66:80 (812 B enviados, 46 338 B recibidos) y después con :443 | Flow log de VNet | AZ-NET-004 |
| 02:22:10 | La identidad administrada de la VM lee db-conn-string desde 203.0.113.66 con curl/8.5.0 | Key Vault | AZ-ID-002 |
| 02:23:30 | La entidad escribe la directiva de acceso del almacén (get / list de secretos para sí misma) | Activity Log + Key Vault | AZ-KV-003 |
| 02:24:10–02:25:14 | SecretList y después 12 SecretGet distintos de la entidad, SDK de Python | Key Vault | AZ-KV-001, AZ-KV-002 |
| 02:25:03 | Alerta de Defender for Cloud sobre la VM (hora de generación; la hora de inicio de la alerta es 02:21) | Defender | AZ-DEF-001 |
| 02:31:02 | listAccountSas/action en stkestrelbackups: blob, lectura + listado, válida 7 días | Activity Log | AZ-ST-001 |
| 02:33:00–02:51:29 | 330 blobs de copia de seguridad distintos descargados con esa SAS desde 203.0.113.66, user agent de AzCopy, ~48,6 GB | Almacenamiento | AZ-ST-005 |
| 02:55:12 | Configuración de diagnóstico kv-audit-to-storage del Key Vault eliminada | Activity Log | AZ-DE-001 |
| 02:55:40 | Configuración de diagnóstico de la suscripción export-activity-to-storage eliminada | Activity Log (solo exportación de la CLI) | AZ-DE-002 |
Algunas cosas merecen atención, porque se repiten en los casos reales.
El primer evento es la autoasignación, no el inicio de sesión. El Activity Log empieza donde el atacante toca ARM por primera vez. Cómo se filtró el secreto de la entidad es una cuestión de Entra ID (inicios de sesión de entidades de servicio, cambios de credenciales) para m365forensics.com.
El token de la identidad administrada aparece dos minutos después del Run Command. El script consultó el Instance Metadata Service y envió el token fuera. El único rastro visible es el mismo object ID, vinculado a vm-app-01 por su claim xms_mirid, llamando a Key Vault desde la IP del atacante en lugar de la 10.10.1.4 de la VM. Es AZ-ID-002, explicado en abuso de identidades administradas.
La escalada mediante directiva de acceso no necesita ningún rol extra. Con Contributor bastó para añadir una directiva de acceso. Ver logs de auditoría de Key Vault.
La SAS es la entidad de la descarga. Las 330 solicitudes GetBlob no llevan ni usuario ni aplicación, solo autenticación SAS y el hash de la firma de la SAS. El analizador las muestra como una sola entidad sas:… con una IP y un total de bytes (exfiltración en almacenamiento).
La exportación del Activity Log muere a las 02:55:40; el Activity Log, no. El Activity Log exportado a almacenamiento no tiene nada después de las 02:55:40. La eliminación de la propia exportación solo se ve porque el investigador también ejecutó az monitor activity-log list, que lee la copia de 90 días de Azure (evasión de defensas).
Una advertencia honesta sobre el ejemplo: su evento de Run Command incluye el cuerpo de la solicitud con el script. Las entradas reales del Activity Log para Run Command no suelen incluir el contenido del script, como muestra la investigación de Mandiant; tendrías que recuperarlo de la VM (ataques con Run Command).
El veredicto
Once hallazgos de gravedad alta (AZ-RBAC-002, AZ-RBAC-003, AZ-VM-001, AZ-NET-004, AZ-ID-002, AZ-KV-001, AZ-KV-002, AZ-ST-001, AZ-ST-005, AZ-DE-001, AZ-DE-002) y tres medios (AZ-ID-001, AZ-KV-003, AZ-DEF-001): Comprometido. Hay además un hallazgo bajo de la semana de aprendizaje: la administradora de la plataforma listando las claves de la cuenta de almacenamiento el 2026-09-09 (AZ-ST-002). Es legítimo, y el veredicto lo ignora: un buen recordatorio de que los hallazgos bajos son contexto, no acusaciones.
La vista de entidades
Pivotar sobre 203.0.113.66 en la pestaña Entidades reúne todos los eventos de esa dirección: las llamadas a ARM de la entidad, la lectura de Key Vault de la identidad administrada, las lecturas de secretos de la entidad y las descargas con la SAS. La fila de la IP también muestra los totales de flujo de los flow logs de VNet. Ese único filtro es el incidente.
Pivotar sobre el object ID de la entidad muestra el contraste con su referencia: una semana de despliegues diarios a las 10:00 desde dos IP de runners y después una ráfaga de 41 minutos desde una IP nueva, haciendo cosas que nunca había hecho.
La lista de remediación generada
La pestaña Remediación ordena los pasos a partir de los hallazgos:
- Eliminar las asignaciones de roles creadas durante el incidente; revisar quién tiene Owner / User Access Administrator.
- Rotar las credenciales de la entidad y revocar sesiones; investigar la parte de identidad en Entra ID.
- Aislar
vm-app-01, hacer snapshots de sus discos y reconstruirla; revisar las extensiones y el historial de Run Command. - Bloquear 203.0.113.66 y buscarla en otros sitios.
- Rotar los 12 secretos leídos en
kv-kestrel-prod; pasar el almacén a Azure RBAC; eliminar la directiva de acceso maliciosa. - Rotar las dos claves de la cuenta de almacenamiento (lo que invalida la SAS); determinar con exactitud qué copias salieron, para la notificación.
- Restaurar las configuraciones de diagnóstico eliminadas y protegerlas con Azure Policy.
- Investigar la alerta de Defender.
Lo que este caso no muestra
- El acceso inicial. La filtración del secreto queda fuera de estos logs.
- Lo que hizo el script en la VM, más allá de los flujos de red y del uso del token. Para eso hace falta el disco.
- Nada posterior a las 02:55:12 en Key Vault. El registro del almacén desaparece en ese momento; si el atacante hubiera vuelto a las 03:10, el log de Key Vault no lo diría.
Para el proceso que rodea a un caso así, empieza por la guía de respuesta a incidentes; para la herramienta, por la guía paso a paso.