Compromiso de GCP comentado paso a paso (caso ficticio)
Un incidente ficticio de Google Cloud de principio a fin: clave de CI filtrada, Owner para un Gmail, script de inicio, bucket público y sink borrado.
En resumen. Este es un incidente ficticio: la empresa, las personas, el proyecto, las claves y las direcciones IP son inventados (las IP proceden de los rangos de documentación del RFC 5737). Es el conjunto de datos que carga Probar un ejemplo en la página de la herramienta. Se filtra una clave de una cuenta de servicio de CI creada para una prueba local; seis días después se usa desde un VPS, que enumera, concede roles/owner a una cuenta de Gmail, instala un script de inicio, descarga 140 objetos, hace público el bucket y borra el sink que alimenta el SIEM, todo en 55 minutos. Cada paso que sigue es un hallazgo real que el analizador produce sobre ese ejemplo.
El objetivo de un caso comentado es mostrar el razonamiento, no la herramienta. Cada paso indica el campo del registro que contiene la prueba, para que pueda reproducirlo sobre sus propios datos con Logs Explorer si lo prefiere.
El contexto
«Northwind Analytics» (ficticia) gestiona un proyecto nw-analytics-prod con:
- una cuenta de servicio de CI,
ci-deployer@…, que usa Terraform; - una VM de ETL,
etl-worker-1enus-central1-a, que se ejecuta comoetl-runner@…y lee exportaciones diarias; - un bucket
nw-analytics-exportscon extracciones de clientes; - un sink
nw-audit-to-siemque exporta los registros de auditoría a Pub/Sub para el SIEM; - los registros Data Access habilitados y VPC Flow Logs en la subred por defecto.
La exportación es lo que se obtiene al copiar un bucket de sink: 26 fragmentos horarios en JSON lines bajo cloudaudit.googleapis.com/… y compute.googleapis.com/vpc_flows/…, más una descarga de Logs Explorer. El analizador lee 215 entradas de auditoría y 65 registros de flujo, y aparta 3 entradas de GKE para Kubernetes Forensics.
El veredicto
Comprometido, con 16 hallazgos: 3 críticos, 8 altos y 5 medios. El primer motivo es la correlación «cadena de ataque: acceso robado y después toma de control», que cubre de las 02:03 a las 02:57 UTC del 14 de septiembre.
Un veredicto es una afirmación; el resto del artículo la comprueba.
8 de septiembre: nace la clave
09:14:22 alex.martin@… google.iam.admin.v1.CreateServiceAccountKey from 198.51.100.24 (gcloud, macOS)
sa_key_created (media). Alex crea una clave JSON para ci-deployer para probar Terraform en local. Minutos después la clave se usa desde la misma IP de la oficina con un user agent Terraform/1.9.5: serviceAccountKeyName termina en …/keys/6f1c2d9e…. Eso activa sa_key_used_external (media): la clave se usa desde fuera de Google Cloud. Por sí solo, es algo corriente. Se vuelve relevante porque la IP de la oficina pasa a ser la primera IP conocida de la clave.
Los días siguientes son rutinarios y no producen hallazgos: la cuenta de servicio de ETL lee cuatro objetos cada mañana desde la IP interna de la VM; Priya lista instancias, modifica una regla de cortafuegos para el rango de IAP y concede roles/viewer a un compañero; Google migra en vivo la VM (una entrada System Event de system@google.com). Esta referencia es lo que hace destacar el día siguiente. Exporte una referencia siempre que pueda.
14 de septiembre, 02:03: la clave se usa desde otro lugar
02:03:11 ci-deployer@… GetIamPolicy from 203.0.113.66 (gcloud, Linux) key 6f1c2d9e…
sa_key_new_ip (alta, acceso inicial, T1078.004). La misma clave, una IP pública nueva, un cliente nuevo: gcloud en Linux en lugar de Terraform en macOS, a las dos de la madrugada. La clave se ha copiado. El artículo sobre la clave filtrada explica cómo distinguir esto del ruido de la CI.
De 02:04 a 02:08: enumeración
24 llamadas en cuatro minutos, todas con status.code: 7 (PERMISSION_DENIED): acceso al secreto prod-db-password, lectura de la política de IAM de la organización y de las políticas de organización, la cuenta de facturación, las configuraciones de notificación de Security Command Center, las cuentas de servicio de otro proyecto. permission_denied_burst (media, descubrimiento). Es el atacante aprendiendo lo que la clave puede hacer, y descubriendo que no puede hacer gran cosa a nivel de organización pero tiene setIamPolicy sobre el proyecto.
02:11: Owner para una cuenta de Gmail
02:11:07 ci-deployer@… SetIamPolicy ADD roles/owner user:nw.ops.backup@gmail.com
Tres hallazgos sobre una sola entrada: owner_to_consumer (crítica), owner_editor_granted (alta), consumer_account_granted (alta). El nombre se eligió para parecer una cuenta interna de copias de seguridad; el dominio lo delata. Siete minutos después, esa cuenta de Gmail lista instancias desde la misma IP del VPS, en un navegador: el atacante se ha pasado a una identidad que sobrevive a la inhabilitación de la clave. Vea abuso de SetIamPolicy.
De 02:24 a 02:26: puerta trasera en la VM
02:24:40 nw.ops.backup@gmail.com v1.compute.instances.setMetadata +startup-script etl-worker-1
02:25:10 nw.ops.backup@gmail.com v1.compute.projects.setCommonInstanceMetadata +ssh-keys -enable-oslogin
02:26:02 nw.ops.backup@gmail.com v1.compute.instances.reset etl-worker-1
startup_script_changed (alta), ssh_key_added (media), oslogin_changed (alta). Un script de inicio se ejecuta como root en el arranque; el reinicio hace que se ejecute ya. Una clave SSH para todo el proyecto más OS Login eliminado dan acceso por shell a todas las VM. El registro de auditoría nombra las claves, no el script: una investigación real haría una instantánea del disco y leería los metadatos. Vea abuso de Compute Engine.
A partir de las 02:27: la red lo confirma
VPC Flow Logs muestra una sesión SSH entrante desde 203.0.113.66 hacia la VM por el puerto 22 a las 02:27 y después 36 flujos HTTPS salientes de etl-worker-1 hacia la misma IP hasta las 02:54, unos 1,9 GiB en total, con el destino geolocalizado en los Países Bajos.
flow_large_egress (media) y flow_ioc_match (alta): la IP que usó la clave filtrada es también el interlocutor de la VM con la puerta trasera. Este es el vínculo entre el plano de control y lo que la VM hizo realmente. Vea análisis de VPC Flow Logs.
De 02:33 a 02:40: el bucket
140 storage.objects.get sobre nw-analytics-exports, objetos a partir de customers/2026/q3/customer-extract-0000.csv.gz, en seis minutos y medio, por la cuenta de Gmail: bulk_object_reads (alta). Después:
02:40:15 nw.ops.backup@gmail.com storage.setIamPermissions ADD roles/storage.objectViewer allUsers
public_access_granted (crítica). Desde las 02:40 el bucket es público; las lecturas de usuarios anónimos no aparecerían en los registros de auditoría. El informe debe indicar una ventana de exposición, no solo las 140 lecturas demostradas. Vea exfiltración de GCS y BigQuery.
02:57: borrar las huellas
02:57:42 nw.ops.backup@gmail.com google.logging.v2.ConfigServiceV2.DeleteSink nw-audit-to-siem
sink_deleted (alta). A partir de aquí, el SIEM no recibe nada. El propio borrado está en el bucket _Required, igual que todas las entradas Admin Activity anteriores y posteriores. Vea evasión de defensas.
Los pivotes que lo unen todo
- IP 203.0.113.66: 173 entradas de auditoría con dos principales (la cuenta de servicio de CI y luego la cuenta de Gmail), más los registros de flujo. Un clic en la pestaña Entidades filtra la tabla de eventos por ella.
- Clave 6f1c2d9e…: creada por Alex, usada desde dos IP, la segunda hostil.
- Principal nw.ops.backup@gmail.com: 147 entradas, todas desde el VPS, vista por primera vez a las 02:18.
La lista que genera la herramienta
En orden: declarar un incidente y preservar los registros; bloquear la IP; quitar la vinculación de IAM y restringir los dominios de los miembros; volver a hacer privado el bucket y evaluar la exposición de datos; inhabilitar la clave y rotar lo que la cuenta de servicio de CI podía leer; hacer una instantánea, inspeccionar y reconstruir la VM; volver a aplicar OS Login; restaurar el sink; prohibir la creación de claves; revisar la enumeración; eliminar las claves SSH. Las acciones de contención van primero porque el atacante todavía tiene dos identidades.
Qué enseña este caso
- La filtración no fue el ataque; el ataque empezó seis días después. Los eventos de creación de claves merecen revisarse por sí mismos.
- El atacante cambió de identidad en ocho minutos. Pivote sobre las IP, no solo sobre los principales.
- Los registros Data Access y los registros de flujo convirtieron un «quizá» en «140 archivos y 1,9 GiB». Sin ellos, se aplica el artículo sobre limitaciones.
Para reproducirlo, abra el analizador, pulse Probar un ejemplo y siga la guía paso a paso.
Lecturas recomendadas
- Google Cloud comprometido: guía de respuesta a incidentes.
- Responder a credenciales de Google Cloud comprometidas — documentación de Google Cloud.
- Matriz IaaS de MITRE ATT&CK.