Escalada de privilegios y persistencia IAM en CloudTrail
Cómo persisten los atacantes en AWS con IAM: usuarios de puerta trasera, claves extra, políticas de administrador, confianza de roles y su rastro en CloudTrail.
En resumen. Tras la filtración de una clave, la prioridad del atacante es dejar de depender de esa clave. Los movimientos habituales, todos visibles en CloudTrail bajo iam.amazonaws.com: CreateUser → AttachUserPolicy (AdministratorAccess) → CreateAccessKey y CreateLoginProfile para ese usuario. Variantes más discretas: una segunda clave en un usuario existente, un principal adicional en la política de confianza de un rol, un nuevo proveedor SAML/OIDC, una Lambda pública o unos datos de usuario de EC2 modificados. Lea requestParameters para conocer el objetivo y responseElements para obtener los ID de las claves nuevas, y elimine todos y cada uno de estos elementos antes de dar el incidente por cerrado.
Revocar la credencial filtrada es la parte fácil de un incidente en AWS. Lo que sale mal es la puerta trasera que no se encontró: la que permite al mismo actor volver a entrar una semana después con una clave que usted nunca llegó a ver. Este artículo repasa las técnicas de persistencia y de escalada de privilegios en IAM que aparecen una y otra vez en los registros, y qué aspecto tiene cada una en CloudTrail.
Los eventos de IAM son globales y se registran en us-east-1
IAM es un servicio global; como la mayoría de los eventos de servicios globales, sus eventos de CloudTrail se registran con awsRegion igual a us-east-1. Si solo extrajo el historial de eventos de la región donde se ejecutan sus cargas de trabajo, es posible que se le hayan escapado todos los cambios de IAM. Revise esa región de forma explícita.
Usuarios de puerta trasera
La versión ruidosa, y aun así la más habitual:
{"eventSource": "iam.amazonaws.com", "eventName": "CreateUser",
"requestParameters": {"userName": "backup-admin"}}
{"eventName": "AttachUserPolicy",
"requestParameters": {"userName": "backup-admin",
"policyArn": "arn:aws:iam::aws:policy/AdministratorAccess"}}
{"eventName": "CreateAccessKey",
"requestParameters": {"userName": "backup-admin"},
"responseElements": {"accessKey": {"accessKeyId": "AKIA..."}}}
{"eventName": "CreateLoginProfile",
"requestParameters": {"userName": "backup-admin", "passwordResetRequired": false}}
Lo que lo delata:
- Las cuatro llamadas llegan con segundos de diferencia desde la misma clave y la misma IP.
- El nombre se elige para pasar desapercibido:
backup,support,svc-…,terraform, algo que parezca una cuenta de servicio. passwordResetRequired: falseen un perfil de inicio de sesión creado por un script.- A continuación, el usuario inicia sesión en la consola sin MFA (
ConsoleLoginconadditionalEventData.MFAUsed = "No").
ATT&CK: T1136.003 Create Account: Cloud Account, T1098.003 Additional Cloud Roles.
Credenciales adicionales en identidades existentes
Más discreto: en lugar de crear un usuario, el atacante añade una segunda clave de acceso a uno existente (los usuarios pueden tener dos) o establece una contraseña de consola en un usuario de servicio que nunca la tuvo.
CreateAccessKeyen el querequestParameters.userNameno coincide con el nombre de usuario de quien hace la llamada: que un principal genere una clave para otra persona es poco frecuente en el funcionamiento normal.CreateLoginProfileoUpdateLoginProfilesobre un usuario que solo debería tener acceso programático.
El informe de credenciales ayuda en este punto: access_key_2_active = true en un usuario que siempre ha tenido una sola clave, o password_enabled = true en una cuenta de servicio, merecen una pregunta.
ATT&CK: T1098.001 Additional Cloud Credentials.
Permisos de administrador: asociados, insertados o a través de un grupo
| Técnica | Eventos | Qué leer |
|---|---|---|
| Política de administrador administrada | AttachUserPolicy, AttachRolePolicy, AttachGroupPolicy | policyArn = …:policy/AdministratorAccess o IAMFullAccess |
Política insertada *:* | PutUserPolicy, PutRolePolicy, PutGroupPolicy | policyDocument con Action: "*" y Resource: "*" |
| Nueva versión de política | CreatePolicyVersion (a menudo con setAsDefault: true) | La misma comprobación del documento; el nombre de la política puede parecer inofensivo |
| Pertenencia a un grupo de administradores | AddUserToGroup | groupName como Admins |
CreatePolicyVersion merece atención porque cambia lo que concede una política existente y de confianza sin cambiar su nombre ni sus asociaciones. SetDefaultPolicyVersion puede conseguir lo mismo volviendo a una versión anterior más permisiva.
Confianza de roles y federación
Los roles son más difíciles de detectar que los usuarios, porque no aparece nada nuevo en la lista de usuarios.
UpdateAssumeRolePolicyreescribe quién puede asumir un rol. El atacante añade su propio ID de cuenta de AWS o un principal externo. Compare el nuevopolicyDocumentcon el anterior (historial de AWS Config, infraestructura como código o unGetRoleprevio).CreateSAMLProvider,CreateOpenIDConnectProvider,AddClientIDToOpenIDConnectProvider,UpdateOpenIDConnectProviderThumbprint: quien controle el proveedor de identidad puede obtener credenciales de roles en la cuenta mediante AssumeRoleWithSAML / AssumeRoleWithWebIdentity. ATT&CK: T1484.002 Trust Modification.
Cuando la organización federa sus identidades a través de un proveedor de identidad externo, el atacante puede haber entrado por él en lugar de por IAM; para el acceso respaldado por Okta, consulte oktaforensics.com.
Persistencia basada en cómputo
| Técnica | Eventos | Por qué persiste |
|---|---|---|
| Lambda pública | AddPermission con principal *; CreateFunctionUrlConfig con authType: NONE | Cualquiera puede invocar código que se ejecuta con el rol de la función |
| Código de Lambda nuevo o modificado | CreateFunction, UpdateFunctionCode desde una clave interactiva | Código bajo el control del atacante, con los permisos del rol |
| Datos de usuario de EC2 | ModifyInstanceAttribute con userData | El script se ejecuta como root en el siguiente arranque |
| Pares de claves SSH | CreateKeyPair, ImportKeyPair | Acceso a las instancias lanzadas con ese par |
Los despliegues de código de Lambda desde CI son normales. El mismo evento procedente de la clave de larga duración de una persona, a una hora inusual, no lo es.
Cómo asegurarse de haberlos encontrado todos
- Pivote sobre cada principal que controló el atacante (el usuario de la clave filtrada, los usuarios creados, los roles asumidos) y enumere sus escrituras exitosas (
readOnly = false, sinerrorCode). - Extraiga cada ID de clave nueva de las respuestas de
CreateAccessKeyy pivote también sobre ellos. - Compare el estado actual de IAM con el anterior: el informe de credenciales, la salida de
aws iam get-account-authorization-detailso el estado de su infraestructura como código. - Busque los intentos fallidos: un
AccessDeniedenCreateUserle indica lo que intentó el atacante y si un éxito posterior procedió de otro principal.
En el analizador
AWS Forensics tiene una regla para cada una de las técnicas anteriores («Usuario de IAM creado», «Clave de acceso creada para otro usuario», «Contraseña de consola establecida para un usuario», «Política de confianza de rol modificada», «Proveedor de identidad añadido o modificado», «Usuario añadido a un grupo de administradores», «Función Lambda expuesta públicamente», «Función Lambda creada o código actualizado», «Datos de usuario de EC2 modificados», «Par de claves SSH creado o importado», «Política de administrador asociada», «Política que concede acceso total (:)»), y la lista de remediación indica los usuarios, las claves y los roles exactos que hay que limpiar. La referencia de eventos que vigilar los enumera con sus identificadores de ATT&CK, y el recorrido por un incidente ficticio muestra cómo se crea y se descubre un administrador de puerta trasera.