Saltar al contenido

Temas

5 técnicas cloud y los logs de AWS que las detectan

Mapeo práctico de cinco técnicas de ATT&CK a eventos concretos de CloudTrail y hallazgos de GuardDuty, con consultas, reglas, falsos positivos y respuesta.

IntermedioEn progreso 7 min de lectura1 oct 2026#mitre-attack#aws#cloudtrail#guardduty#deteccion#eventbridge

“Tenemos CloudTrail activado” no es una estrategia de detección. Es tener las cámaras grabando sin que nadie mire las pantallas. Lo que convierte logs en detección es un mapeo explícito: para cada técnica que te preocupa, qué evento exacto deja, en qué fuente, con qué regla lo conviertes en alerta y qué haces cuando salta. En esta nota mapeamos cinco técnicas de la matriz Cloud · IaaS contra la app de referencia Citas.

Antes de empezar: qué registra AWS y qué no#

Ninguna regla detecta lo que no se registra. Revisa esto antes de escribir una sola consulta:

  • Eventos de gestión (management events): las operaciones del plano de control, como crear un usuario, parar un trail o describir instancias. Se registran por defecto, y el historial de eventos de la consola guarda 90 días.
  • Eventos de datos (data events): operaciones sobre los datos, como GetObject en S3. No se registran por defecto, son de alto volumen y cuestan dinero. Actívalos solo para los recursos sensibles (en Citas, citas-adjuntos).
  • Servicios globales: IAM, STS (endpoint global) y CloudFront se registran en us-east-1. Usa un trail multi-región y despliega en us-east-1 las reglas de EventBridge sobre IAM.
  • GuardDutyAmazon GuardDutyServicio gestionado de detección de amenazas de AWS que analiza CloudTrail, VPC Flow Logs y DNS y genera hallazgos (findings). analiza CloudTrail (gestión), VPC Flow Logs y DNS. Con S3 Protection también analiza eventos de datos de S3 sin que los actives en tu trail. Tus propias consultas y tu forense sí los necesitan en el trail.
  • EventBridge recibe eventos de escritura con reglas en estado ENABLED. Los de solo lectura (List*, Describe*, Get*) solo llegan a reglas en estado ENABLED_WITH_ALL_CLOUDTRAIL_MANAGEMENT_EVENTS, y los de datos solo si el trail los captura.
log-archive/trail.tf
resource "aws_cloudtrail" "org" {
name = "citas-org-trail"
s3_bucket_name = aws_s3_bucket.cloudtrail.id # cuenta log-archive, Object Lock
kms_key_id = aws_kms_key.cloudtrail.arn
is_organization_trail = true # las cuentas miembro no pueden pararlo
is_multi_region_trail = true
include_global_service_events = true
enable_log_file_validation = true # detecta logs borrados o alterados
advanced_event_selector {
name = "Eventos de gestión"
field_selector {
field = "eventCategory"
equals = ["Management"]
}
}
# Eventos de datos SOLO para el bucket con PII (coste controlado)
advanced_event_selector {
name = "S3 data events: citas-adjuntos"
field_selector {
field = "eventCategory"
equals = ["Data"]
}
field_selector {
field = "resources.type"
equals = ["AWS::S3::Object"]
}
field_selector {
field = "resources.ARN"
starts_with = ["arn:aws:s3:::citas-adjuntos/"]
}
}
}
De la técnica al log: cómo se detecta en AWS
Atacanteclave filtradaAPI de AWSsts · s3 · rdsCloudTrailtrail organizacionalDetecciónEventBridge · AthenaAlertaSOC / on-call

Técnica → evento → detección

eventomatch

Paso 1 de 7Credencial filtrada

El atacante prueba la access key filtrada con sts:GetCallerIdentity. Para AWS es una llamada válida, pero CloudTrail la registra con IP, identidad y hora.

El mapa: técnica → log → detección#

# Técnica (ATT&CK v19) Táctica Fuente eventSource → eventName GuardDuty
1 T1078.004 Valid Accounts: Cloud Accounts Initial Access (+ Persistence, PrivEsc, Stealth) CloudTrail · gestión signin → ConsoleLogin · sts → GetCallerIdentity (y cualquier API con la clave) InitialAccess:IAMUser/AnomalousBehavior, UnauthorizedAccess:IAMUser/MaliciousIPCaller, CredentialAccess:IAMUser/CompromisedCredentials
2 T1580 Cloud Infrastructure Discovery Discovery CloudTrail · gestión (lectura) s3 → ListBuckets · rds → DescribeDBInstances · ec2 → DescribeInstances Discovery:IAMUser/AnomalousBehavior, Recon:IAMUser/MaliciousIPCaller
3 T1530 Data from Cloud Storage Collection CloudTrail · datos de S3 s3 → GetObject (eventCategory: Data) Exfiltration:S3/AnomalousBehavior, Exfiltration:S3/MaliciousIPCaller
4 T1685.002 Disable or Modify Cloud Log (antes T1562.008) Defense Impairment CloudTrail · gestión cloudtrail → StopLogging, DeleteTrail, UpdateTrail, PutEventSelectors · ec2 → DeleteFlowLogs Stealth:IAMUser/CloudTrailLoggingDisabled, DefenseEvasion:IAMUser/AnomalousBehavior
5 T1098.001 Account Manipulation: Additional Cloud Credentials Persistence, Privilege Escalation CloudTrail · gestión (us-east-1) iam → CreateAccessKey, CreateLoginProfile · ec2 → ImportKeyPair · sts → GetFederationToken Persistence:IAMUser/AnomalousBehavior

Las cinco cuentan una historia coherente: entrar con una credencial válida, mirar alrededor, asegurarse el acceso, cegar a los defensores y llevarse los datos. Vamos una por una.

1. Cuentas cloud válidas · T1078.004#

En Citas: queda un usuario IAM heredado, ci-deploy-legacy, de antes de migrar GitHub Actions a OIDC. Su access key aparece en un repositorio público. Lo primero que hace el atacante es el clásico aws sts get-caller-identity para saber de quién es la clave.

CloudTrail · gestión
{
"userIdentity": {
"type": "IAMUser",
"arn": "arn:aws:iam::111122223333:user/ci-deploy-legacy",
"accessKeyId": "AKIA…7QXZ",
"userName": "ci-deploy-legacy"
},
"eventTime": "2026-10-11T03:12:44Z",
"eventSource": "sts.amazonaws.com",
"eventName": "GetCallerIdentity",
"awsRegion": "us-east-1",
"sourceIPAddress": "198.51.100.66",
"userAgent": "aws-cli/2.x Python/3.x Linux/…",
"readOnly": true,
"eventCategory": "Management"
}

La señal no es la llamada en sí, sino el contexto: una clave de CI usada a las 03:12 desde una IP que no es de GitHub, con un user agent de CLI interactiva.

Pares clave–IP nunca vistos en 30 días
WITH recent AS (
SELECT useridentity.accesskeyid AS access_key, sourceipaddress AS ip, min(eventtime) AS first_seen
FROM cloudtrail_logs
WHERE from_iso8601_timestamp(eventtime) > current_timestamp - interval '1' day
AND useridentity.type = 'IAMUser'
GROUP BY 1, 2
),
baseline AS (
SELECT DISTINCT useridentity.accesskeyid AS access_key, sourceipaddress AS ip
FROM cloudtrail_logs
WHERE from_iso8601_timestamp(eventtime)
BETWEEN current_timestamp - interval '30' day AND current_timestamp - interval '1' day
)
SELECT r.*
FROM recent r
LEFT JOIN baseline b ON r.access_key = b.access_key AND r.ip = b.ip
WHERE b.ip IS NULL;
Login de consola sin MFA
{
"detail-type": ["AWS Console Signin via CloudTrail"],
"detail": {
"eventName": ["ConsoleLogin"],
"additionalEventData": { "MFAUsed": ["No"] },
"responseElements": { "ConsoleLogin": ["Success"] }
}
}

Falsos positivos: desarrolladores viajando, cambios de proveedor de CI, VPNs corporativas con salida variable. Enriquece con ASN y geolocalización, y mantén una lista de rangos esperados. Respuesta: desactiva la clave (aws iam update-access-key --status Inactive), revisa todo lo que hizo esa accessKeyId en CloudTrail y elimina el usuario. La mitigación definitiva es arquitectónica: sin usuarios IAM con claves de larga duración.

2. Descubrimiento de infraestructura · T1580#

En Citas: con la clave válida, el atacante enumera qué hay: ListBuckets, GetBucketPolicy, DescribeDBInstances, DescribeInstances… La mitad le devuelve AccessDenied, y eso también es información para él.

Cada llamada es normal; lo anómalo es el patrón: muchas lecturas, de muchos servicios distintos, en pocos minutos, desde una identidad que normalmente hace tres cosas.

Ráfagas de lectura multiservicio por identidad
SELECT userIdentity.arn, sourceIPAddress,
COUNT(*) AS calls,
COUNT(DISTINCT eventSource) AS services,
SUM(CASE WHEN errorCode IS NOT NULL THEN 1 ELSE 0 END) AS errors
FROM <event-data-store-id>
WHERE eventTime > '2026-10-11 00:00:00'
AND readOnly = true
AND (eventName LIKE 'List%' OR eventName LIKE 'Describe%' OR eventName LIKE 'Get%')
GROUP BY userIdentity.arn, sourceIPAddress
HAVING COUNT(*) > 100 AND COUNT(DISTINCT eventSource) >= 3
ORDER BY calls DESC;

Activa GuardDuty en toda la organización y enruta Discovery:IAMUser/AnomalousBehavior y Recon:IAMUser/MaliciousIPCaller a tu canal de triaje. El modelo de anomalías aprende la línea base de cada identidad: es justo el tipo de detección que cuesta mantener a mano.

Falsos positivos: herramientas de inventario y CSPM (Config, Security Hub, escáneres de terceros), Terraform plan. Exclúyelas por rol, no por IP. Respuesta: por sí sola es severidad baja o media. Su valor está en correlacionarla: discovery seguida de CreateAccessKey o GetObject masivo es una intrusión en curso.

3. Datos de almacenamiento cloud · T1530#

En Citas: el bucket citas-adjuntos guarda informes de pacientes. El atacante descarga miles de objetos con GetObject. Sin eventos de datos activados en el trail, no queda rastro en tus logs.

CloudTrail · datos (S3)
{
"eventCategory": "Data",
"eventSource": "s3.amazonaws.com",
"eventName": "GetObject",
"requestParameters": {
"bucketName": "citas-adjuntos",
"key": "clinica-042/paciente-1187/informe.pdf"
},
"userIdentity": { "type": "IAMUser", "userName": "ci-deploy-legacy" },
"sourceIPAddress": "198.51.100.66",
"additionalEventData": { "bytesTransferredOut": 482113 }
}

En Citas, la API lee el bucket con su task role y a través de un VPC endpoint. Cualquier GetObject de otro principal, o sin vpcEndpointId, ya es sospechoso.

Descargas masivas fuera del rol de la API
SELECT useridentity.arn, sourceipaddress, vpcendpointid,
count(*) AS objects,
sum(CAST(json_extract_scalar(additionaleventdata, '$.bytesTransferredOut') AS bigint)) AS bytes_out
FROM cloudtrail_logs
WHERE eventsource = 's3.amazonaws.com'
AND eventname = 'GetObject'
AND json_extract_scalar(requestparameters, '$.bucketName') = 'citas-adjuntos'
AND useridentity.arn NOT LIKE '%:assumed-role/citas-api-task/%'
AND from_iso8601_timestamp(eventtime) > current_timestamp - interval '1' hour
GROUP BY 1, 2, 3
HAVING count(*) > 50;

Con S3 Protection activo, Exfiltration:S3/AnomalousBehavior (severidad alta) salta cuando una identidad accede a S3 de forma distinta a su línea base, y Exfiltration:S3/MaliciousIPCaller cuando la IP está en listas de amenazas.

Falsos positivos: procesos de backup o migración, soporte descargando un adjunto puntual. Identifica los roles legítimos y trátalos como excepción explícita. Respuesta: revoca la credencial, cuantifica qué objetos se leyeron (la lista sale de la propia consulta) y activa el proceso de notificación de brechas: hay PII de pacientes.

4. Desactivar o modificar logs cloud · T1685.002#

En Citas: antes de llevarse los datos, el atacante intenta StopLogging. Como el trail es organizacional, una cuenta miembro no puede pararlo: la llamada falla, pero el intento queda registrado. Un trail local de cuenta sí habría caído.

Patrón de EventBridge · tiempo real
{
"source": ["aws.cloudtrail"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["cloudtrail.amazonaws.com"],
"eventName": [
"StopLogging",
"DeleteTrail",
"UpdateTrail",
"PutEventSelectors",
"PutInsightSelectors"
]
}
}

Añade también ec2:DeleteFlowLogs y cambios en la política o el ciclo de vida del bucket de logs. GuardDuty genera Stealth:IAMUser/CloudTrailLoggingDisabled cuando un trail se borra o se actualiza para dejar de registrar.

Falsos positivos: cambios legítimos del equipo de plataforma. Deberían llegar solo vía IaC desde un rol concreto; cualquier otro origen es alerta. Respuesta: aws cloudtrail start-logging, investiga el principal y, como prevención, una SCP que deniegue estas acciones a todo rol salvo el de break-glass.

scp/proteger-logging.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLogTampering",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"cloudtrail:UpdateTrail",
"cloudtrail:PutEventSelectors",
"ec2:DeleteFlowLogs"
],
"Resource": "*",
"Condition": {
"ArnNotLike": { "aws:PrincipalArn": "arn:aws:iam::*:role/security-break-glass" }
}
}
]
}

5. Credenciales cloud adicionales · T1098.001#

En Citas: sabiendo que la clave filtrada acabará rotada, el atacante crea una segunda con CreateAccessKey sobre el mismo usuario, o un perfil de consola con CreateLoginProfile.

CloudTrail · gestión (us-east-1)
{
"eventSource": "iam.amazonaws.com",
"eventName": "CreateAccessKey",
"awsRegion": "us-east-1",
"userIdentity": { "type": "IAMUser", "userName": "ci-deploy-legacy", "accessKeyId": "AKIA…7QXZ" },
"sourceIPAddress": "198.51.100.66",
"requestParameters": { "userName": "ci-deploy-legacy" },
"responseElements": {
"accessKey": { "userName": "ci-deploy-legacy", "accessKeyId": "AKIA…9KDM", "status": "Active" }
}
}

Esta es la detección de mayor fidelidad de la lista, y es gracias a la arquitectura. En Citas las personas entran con IAM Identity Center y las cargas de trabajo usan roles, así que nadie debería crear access keys nunca. Cualquier CreateAccessKey es una alerta.

Patrón de EventBridge · desplegar en us-east-1
{
"source": ["aws.iam"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["iam.amazonaws.com"],
"eventName": ["CreateAccessKey", "CreateLoginProfile", "UpdateLoginProfile"]
}
}

Falsos positivos: prácticamente ninguno si la política es “sin usuarios IAM”. Si aún quedan, documenta cada excepción. Respuesta: desactiva todas las claves del usuario (la nueva y la vieja), revisa si se usó GetFederationToken (esas credenciales sobreviven a la desactivación de la clave) y elimina el usuario.

Errores habituales#

Tu turno

Mapea 5 técnicas cloud a logs de AWS que las detectarían

Ya tienes cinco mapeadas. Ahora valídalas y amplíalas en una cuenta sandbox, nunca en producción.

  1. Detona cada técnica con Stratus Red Team y comprueba que tu regla salta. Por ejemplo aws.defense-evasion.cloudtrail-stop (T1685.002), aws.persistence.iam-backdoor-user (T1098.001) o aws.initial-access.console-login-without-mfa (T1078.004).
  2. Mide el tiempo desde la detonación hasta la alerta. ¿Minutos? ¿Horas?
  3. Mapea 5 técnicas más de la matriz IaaS. Ideas: T1537 (compartir snapshots: ModifySnapshotAttribute, ModifyDBSnapshotAttribute), T1552.005, T1555.006 (GetSecretValue), T1535 (actividad en regiones no usadas), T1496.001.
sandbox
stratus list --platform aws
stratus detonate aws.defense-evasion.cloudtrail-stop
stratus cleanup aws.defense-evasion.cloudtrail-stop
plantilla.md
| Técnica (v19) | Qué haría en mi entorno | Fuente | eventSource → eventName | Regla / consulta | ¿Probada? (fecha) | Tiempo a alerta |
| ------------- | ----------------------- | ------ | ----------------------- | ---------------- | ----------------- | --------------- |
| | | | | | | |

Reto

Tu trail registra solo eventos de gestión. ¿Cuál de las cinco técnicas no verías en tus consultas?

▸Mostrar solución

T1530: GetObject es un evento de datos y no se registra por defecto. GuardDuty S3 Protection sí podría alertarte, porque consume esos eventos por su cuenta, pero tú no tendrías el detalle para investigar qué objetos se llevaron.

Reto

¿Por qué tu regla de EventBridge para CreateAccessKey desplegada en eu-west-1 nunca salta?

▸Mostrar solución

Porque IAM es un servicio global y sus eventos se registran en us-east-1. La regla tiene que estar en esa región (o reenviarse desde ella).

En resumen#

  • Detección = técnica → evento exacto → regla → respuesta, escrito y probado.
  • La mayoría de técnicas cloud dejan eventos de gestión en CloudTrail. La exfiltración de S3 necesita eventos de datos activados.
  • Trail organizacional, multi-región, con validación de integridad y centralizado en una cuenta de logs aislada.
  • GuardDuty cubre las anomalías por identidad que cuestan mantener a mano. Tus reglas cubren lo que es inaceptable por política (CreateAccessKey, StopLogging).
  • La mejor detección la habilita la arquitectura: sin usuarios IAM, sin claves de larga duración y con datos solo accesibles vía VPC endpoint.

Referencias#

Notas relacionadas

ESC
↑↓ para navegar↵ para abriresc para cerrar