Técnicas Prácticas de Enumeración en AWS
Este apunte está diseñado para pentesters y red teamers que buscan identificar recursos en AWS de manera efectiva y ética. Incluye técnicas externas e internas, ejemplos prácticos y comandos específicos para maximizar su utilidad.
1. Enumeración Externa: Sin Credenciales
1.1. Descubrimiento de Subdominios
- Objetivo: Encontrar subdominios asociados al dominio objetivo (ej.,
example.com
). - Comando:
dnsenum example.com --threads 50
- Resultado Esperado: Lista de subdominios como
app.example.com
odev.example.com
. - Valor: Revela servicios expuestos (EC2, S3, etc.) vinculados a subdominios.
Ejemplo de offsec:
❯ sudo nano /etc/resolv.conf
❯ sudo systemctl restart NetworkManager
❯ host www.offseclab.io 3.208.18.82
Using domain server:
Name: 3.208.18.82
Address: 3.208.18.82#53
Aliases:
www.offseclab.io has address 54.90.147.109
❯ host -t ns offseclab.io
offseclab.io name server ns-1536.awsdns-00.co.uk.
offseclab.io name server ns-1024.awsdns-00.org.
offseclab.io name server ns-512.awsdns-00.net.
offseclab.io name server ns-0.awsdns-00.com.
❯ dnsenum offseclab.io --threads 100
dnsenum VERSION:1.3.1
----- offseclab.io -----
Host's addresses:
__________________
offseclab.io. 60 IN A 54.90.147.109
Name Servers:
______________
Mail (MX) Servers:
___________________
Trying Zone Transfers and getting Bind Versions:
_________________________________________________
unresolvable name: ns-0.awsdns-00.com at /usr/bin/dnsenum line 892 thread 5.
Trying Zone Transfer for offseclab.io on ns-0.awsdns-00.com ...
AXFR record query failed: no nameservers
unresolvable name: ns-1024.awsdns-00.org at /usr/bin/dnsenum line 892 thread 6.
Trying Zone Transfer for offseclab.io on ns-1024.awsdns-00.org ...
AXFR record query failed: no nameservers
unresolvable name: ns-1536.awsdns-00.co.uk at /usr/bin/dnsenum line 892 thread 7.
Trying Zone Transfer for offseclab.io on ns-1536.awsdns-00.co.uk ...
AXFR record query failed: no nameservers
unresolvable name: ns-512.awsdns-00.net at /usr/bin/dnsenum line 892 thread 8.
Trying Zone Transfer for offseclab.io on ns-512.awsdns-00.net ...
AXFR record query failed: no nameservers
Brute forcing with /usr/share/dnsenum/dns.txt:
_______________________________________________
mail.offseclab.io. 60 IN A 54.90.147.109
www.offseclab.io. 60 IN A 54.90.147.109
1.2. Identificación de Buckets S3 Públicos
- Técnica: Buscar buckets accesibles probando nombres predecibles.
- Comando Manual:
curl http://example-lab-assets-public.s3.amazonaws.com/
- Respuesta XML = bucket público.
- “Access Denied” = bucket existe pero está protegido.
- “NoSuchBucket” = bucket no existe.
- Automatización con
cloud_enum
:cloud_enum -k example-lab -qs --disable-azure --disable-gcp
- Valor: Encuentra almacenamiento público con datos sensibles (ej., backups, configs).
Ejemplo de offsec
kali@kali:~$ cloud_enum -k offseclab-assets-public-axevtewi --quickscan --disable-azure --disable-gcp
...
Keywords: offseclab-assets-public-axevtewi
Mutations: NONE! (Using quickscan)
Brute-list: /usr/lib/cloud-enum/enum_tools/fuzz.txt
[+] Mutated results: 1 items
++++++++++++++++++++++++++
amazon checks
++++++++++++++++++++++++++
[+] Checking for S3 buckets
OPEN S3 BUCKET: http://offseclab-assets-public-axevtewi.s3.amazonaws.com/
FILES:
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/offseclab-assets-public-axevtewi
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/amethyst-expanded.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/amethyst.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/logo.svg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/pic02.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/pic05.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/pic13.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/ruby-expanded.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/ruby.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/saphire-expanded.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/saphire.jpg
Elapsed time: 00:00:00
[+] Checking for AWS Apps
[*] Brute-forcing a list of 1 possible DNS names
Elapsed time: 00:00:00
[+] All done, happy hacking!
Hay muchas formas en las que podríamos lograr esto. Usaremos un script de Bash para ejecutar un bucle en una sola línea que itera sobre algunas palabras clave y muestra la palabra clave, insertando un prefijo (offseclab-assets) y un sufijo (-axevtewi) alrededor de ella. Finalmente, usaremos el comando tee para mostrar el resultado en la consola, así como en el archivo /tmp/keyfile.txt. Como resultado, tendremos el archivo clave con los nombres de los buckets para validar si existen.
kali@kali:~$ for key in "public" "private" "dev" "prod" "development" "production"; do echo "offseclab-assets-$key-axevtewi"; done | tee /tmp/keyfile.txt
offseclab-assets-public-axevtewi
offseclab-assets-private-axevtewi
offseclab-assets-dev-axevtewi
offseclab-assets-prod-axevtewi
offseclab-assets-development-axevtewi
offseclab-assets-production-axevtewi
Ahora podemos volver a ejecutar cloud_enum
con el archivo de claves que acabamos de crear:
kali@kali:~$ cloud_enum -kf /tmp/keyfile.txt -qs --disable-azure --disable-gcp
...
Keywords: offseclab-assets-public-axevtewi, offseclab-assets-private-axevtewi, offseclab-assets-dev-axevtewi, offseclab-assets-prod-axevtewi, offseclab-assets-development-axevtewi, offseclab-assets-production-axevtewi
Mutations: NONE! (Using quickscan)
Brute-list: /usr/lib/cloud-enum/enum_tools/fuzz.txt
[+] Mutated results: 6 items
++++++++++++++++++++++++++
amazon checks
++++++++++++++++++++++++++
[+] Checking for S3 buckets
OPEN S3 BUCKET: http://offseclab-assets-public-axevtewi.s3.amazonaws.com/
FILES:
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/offseclab-assets-public-axevtewi
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/amethyst-expanded.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/amethyst.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/logo.svg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/pic02.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/pic05.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/pic13.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/ruby-expanded.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/ruby.jpg
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/saphire-expanded.png
->http://offseclab-assets-public-axevtewi.s3.amazonaws.com/sites/www/images/saphire.jpg
Protected S3 Bucket: http://offseclab-assets-private-axevtewi.s3.amazonaws.com/
Elapsed time: 00:00:06
[+] Checking for AWS Apps
[*] Brute-forcing a list of 6 possible DNS names
Elapsed time: 00:00:00
[+] All done, happy hacking!
A partir del resultado, podemos confirmar que hay otro bucket, pero está protegido, lo que significa que no es públicamente legible. También podríamos intentar validar si existen otros buckets utilizando otra información que encontramos durante la fase de reconocimiento. Por ejemplo, podrían ser buckets que incluyan el nombre de los proyectos de offseclab como offseclab-assets-ruby-axevtewi o offseclab-ruby-axevtewi. Dejaremos esto como un ejercicio para el lector.
1.3. Análisis DNS y WHOIS
- Comando DNS:
host -t ns example.com
- Salida:
ns-1536.awsdns-00.co.uk
(indica Route53).
- Salida:
- Comando WHOIS:
whois example.com | grep "Registrant Organization"
- Valor: Confirma uso de AWS y expone infraestructura asociada.
2. Enumeración Interna: Con Credenciales
2.1. Listado de Recursos con awscli
- Configuración:
aws configure --profile pentester
kali@kali:~$ aws configure --profile attacker
AWS Access Key ID []: AKIAQO...
AWS Secret Access Key []: cOGzm...
Default region name []: us-east-1
Default output format []: json
kali@kali:~$ aws --profile attacker sts get-caller-identity
{
"UserId": "AIDAQOMAIGYU5VFQCHOI4",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/attacker"
}
Comandos Útiles
aws --profile attacker ec2 describe-images --owners amazon --executable-users all
: Lista imágenes de Amazon disponibles para todos los usuarios ejecutables.aws --profile attacker ec2 describe-images --executable-users all --filters "Name=description,Values=*<keyword>*"
: Filtra imágenes por palabras clave en la descripción.-
aws --profile attacker ec2 describe-images --executable-users all --filters "Name=name,Values=*<keyword>*"
: Filtra imágenes por palabras clave en el nombre.- Ingresa Access Key, Secret Key y región.
- Listar Buckets S3:
aws s3 ls --profile pentester
- Listar Instancias EC2:
aws ec2 describe-instances --profile pentester
- Valor: Mapea la infraestructura interna rápidamente.
Obtención de IDs de Cuentas desde Buckets S3 Públicos
Para realizar esta técnica, se necesita una cuenta de AWS para interactuar con la API de AWS. Se utilizará un perfil configurado en AWS CLI para simular este escenario. Además, la cuenta objetivo debe tener un bucket S3 público que permita acceso de lectura. Primero, se debe crear un usuario IAM que, por defecto, no tendrá permisos para ejecutar acciones. Luego, se añadirá una política que otorgue acceso de lectura al bucket, con la condición de que el permiso solo se aplique si el ID de la cuenta propietaria del bucket comienza con un dígito específico. Si no se puede leer el bucket, se probarán otros números hasta que se logre acceder, lo que permitirá identificar el primer dígito del ID de la cuenta propietaria. Este proceso se puede repetir para obtener todos los dígitos del ID de la cuenta. El primer paso es seleccionar un bucket o un objeto público dentro de la cuenta objetivo. Dado que el bucket u objeto es público, debería ser posible listar su contenido con cualquier usuario IAM de cualquier cuenta de AWS. A continuación, se crea un nuevo usuario IAM en la cuenta propia. Por defecto, los usuarios IAM no tienen permisos para ejecutar acciones, por lo que el nuevo usuario no podrá listar el contenido del recurso público incluso si es accesible públicamente. Después, se define una política que permita listar buckets y leer objetos. Sin embargo, se añade una condición para que el permiso de lectura solo se aplique si el ID de la cuenta propietaria del bucket comienza con un dígito específico. Finalmente, se prueba si el nuevo usuario puede listar el bucket utilizando sus credenciales. Se prueba con valores de dígitos del 0 al 9 hasta que se logre listar el bucket, lo que confirma el primer dígito del ID de la cuenta.
Creación de un Usuario IAM para Enumeración
kali@kali:~$ aws --profile attacker s3 ls offseclab-assets-public-kaykoour
Ahora, vamos a crear un nuevo usuario IAM con el comando iam create-user --user-name enum
. Recordemos que este usuario reside en la cuenta de AWS controlada por el atacante.
A continuación, también crearemos claves de acceso para el usuario IAM, de modo que podamos interactuar con la API de AWS a través de la herramienta AWS CLI. Ejecutaremos el comando iam create-access-key --user-name enum
y tomaremos nota de los valores de AccessKeyId
y SecretAccessKey
en la salida.
kali@kali:~$ aws --profile attacker iam create-user --user-name enum
{
"User": {
"Path": "/",
"UserName": "enum",
"UserId": "AIDAQOMAIGYU4HTPEJ32K",
"Arn": "arn:aws:iam::123456789012:user/enum",
}
}
kali@kali:~$ aws --profile attacker iam create-access-key --user-name enum
{
"AccessKey": {
"UserName": "enum",
"AccessKeyId": "AKIAQOMAIGYURE7QCUXU",
"Status": "Active",
"SecretAccessKey": "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",
}
}
2.2. Enumeración de Usuarios y Roles IAM
- Listar Usuarios:
aws iam list-users --profile pentester
- Listar Roles:
aws iam list-roles --profile pentester
- Valor: Identifica privilegios excesivos o roles asumibles.
Enumeración de Recursos IAM
- Contexto: Se inicia con credenciales comprometidas de un usuario IAM (
clouddesk-plove
), miembro del gruposupport
con la políticaSupportUser
, que otorga acceso de solo lectura a varios servicios. - Comandos clave:
aws iam list-users
: Lista todos los usuarios IAM.aws iam list-groups
: Lista los grupos.aws iam list-roles
: Lista los roles.aws iam get-account-summary
: Proporciona un resumen de recursos IAM (ej., 18 usuarios, 20 roles, 8 grupos) y revela configuraciones débiles como la ausencia de MFA ("MFADevices": 0
).
- Datos obtenidos: Nombre, ARN y ruta de usuarios, grupos y roles, guardados en archivos JSON (ej.,
users.json
,roles.json
) para análisis posterior. - Ejemplo práctico:
aws --profile target iam list-users | tee users.json
Muestra usuarios como
admin-alice
con rutas como/admin/
, sugiriendo privilegios elevados. - Advertencia: Políticas personalizadas como
SupportUser
pueden ser riesgosas si son demasiado permisivas.
Procesamiento de Datos de Respuesta de la API con JMESPath
- Qué es JMESPath: Un lenguaje de consulta para JSON que filtra y transforma salidas de AWS CLI.
- Uso: Reduce solicitudes a la API al procesar datos localmente.
- Ejemplos:
- Listar nombres de usuarios:
aws --profile target iam get-account-authorization-details --filter User --query "UserDetailList[].UserName"
Salida:
["admin-alice", "admin-cbarton", ...]
- Filtrar usuarios con “admin” en el nombre:
aws --profile target iam get-account-authorization-details --filter User --query "UserDetailList[?contains(UserName, 'admin')].{Name: UserName}"
Salida:
[{"Name": "admin-alice"}, {"Name": "admin-cbarton"}, ...]
- Combinar datos de usuarios y grupos:
aws --profile target iam get-account-authorization-details --filter User Group --query "{Users: UserDetailList[?Path=='/admin/'].UserName, Groups: GroupDetailList[?Path=='/admin/'].{Name: GroupName}}"
- Listar nombres de usuarios:
- Consejo: Guardar salidas en archivos y usar herramientas como
jp
para consultas offline, minimizando el ruido en logs.
Ejecución de Enumeración Automatizada con Pacu
- Pacu: Herramienta de enumeración y explotación para AWS, instalada en Kali con:
sudo apt install pacu
- Configuración:
- Iniciar sesión:
pacu
→ Crear sesión (ej.,enumlab
). - Importar claves:
import_keys target
.
- Iniciar sesión:
- Módulo clave:
iam__enum_users_roles_policies_groups
recopila datos de usuarios, roles, políticas y grupos.- Ejecución:
run iam__enum_users_roles_policies_groups
Resultado: Enumera 18 usuarios, 20 roles, 8 políticas y 8 grupos, almacenados en la base de datos de Pacu.
- Ver datos:
services # Lista servicios con datos (ej., IAM) data IAM # Muestra detalles
- Ejecución:
- Ventaja: Automatiza tareas repetitivas, pero requiere permisos adecuados en las credenciales comprometidas.
- Monitoreo: Revisar logs de CloudTrail para evaluar el impacto y ruido generado.
Extracción de Insights de los Datos de Enumeración
- Objetivo: Analizar datos para identificar caminos de escalada de privilegios (ej., obtener acceso de administrador).
- Ejemplo de análisis:
- Usuario
admin-alice
:aws --profile target iam get-account-authorization-details --filter User Group --query "UserDetailList[?UserName=='admin-alice']"
- Pertenece a los grupos
admin
(conAdministratorAccess
) yamethyst_admin
. - Sin MFA, vulnerable a ataques como ingeniería social.
- Pertenece a los grupos
- Grupo
admin
:- Política
AdministratorAccess
permite todo ("Action": "*", "Resource": "*"
).
- Política
- Política
amethyst_admin
:- Permite acciones IAM en recursos etiquetados con
"Project": "amethyst"
, incluyendoiam:CreateAccessKey
para usuarios comoadmin-alice
.
- Permite acciones IAM en recursos etiquetados con
- Usuario
- Caminos de escalada:
- Obtener credenciales de
admin-alice
(ej., sin MFA facilita ataques). - Usar un usuario de
amethyst_admin
(comoadmin-cbarton
) para crear claves de acceso deadmin-alice
.
- Obtener credenciales de
- Herramientas visuales: Awspx o Cloudmapper ayudan a mapear relaciones y visualizar caminos de ataque.
- Conclusión: La falta de MFA y políticas permisivas (uso de
*
) son puntos débiles explotables.
2.3. Detección de Configuraciones Erróneas
- Buckets S3 Públicos:
aws s3api get-bucket-policy --bucket example-lab-assets-public --profile pentester
- Valor: Encuentra puntos de entrada para escalar privilegios.
3. Ejemplo Práctico
- Escenario: Dominio
example.com
. - Paso 1: Enumerar subdominios:
dnsenum example.com
- Encuentra
dev.example.com
.
- Encuentra
- Paso 2: Resolver IP:
host dev.example.com
- Salida:
52.70.117.69
(EC2).
- Salida:
- Paso 3: Probar buckets:
curl http://example-lab-dev.s3.amazonaws.com/
- XML devuelto = bucket público.
4. Herramientas Recomendadas
awscli
: Interacción directa con la API de AWS.cloud_enum
: Automatiza búsqueda de recursos públicos.dnsenum
: Enumeración DNS eficiente.- pacu: Herramienta de enumeración y explotación de AWS.
Obtención de IDs de Cuentas desde Buckets S3
Descripción
Esta técnica aprovecha las características de la API de AWS para determinar el ID de una cuenta a partir de un bucket S3 público o un objeto accesible, incluso si no hay recursos compartidos públicamente de manera evidente.
Pasos Clave
- Crear un Usuario IAM en la Cuenta del Atacante:
- Genera un usuario IAM sin permisos iniciales en tu propia cuenta AWS.
- Usa el comando:
aws iam create-user --user-name enum
- Crea claves de acceso para este usuario:
aws iam create-access-key --user-name enum
- Configurar las Claves en AWS CLI:
- Configura un perfil en AWS CLI con las claves generadas:
aws configure --profile enum
- Configura un perfil en AWS CLI con las claves generadas:
- Definir una Política con Condición:
- Crea una política que permita leer el bucket solo si el ID de la cuenta que posee el bucket comienza con un dígito específico (por ejemplo, “1”). Ejemplo de política en
policy-s3-read.json
:{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowResourceAccount", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetObject" ], "Resource": "*", "Condition": { "StringLike": {"s3:ResourceAccount": ["1*"]} } } ] }
- Asocia la política al usuario:
aws iam put-user-policy --user-name enum --policy-name s3-read --policy-document file://policy-s3-read.json
- Crea una política que permita leer el bucket solo si el ID de la cuenta que posee el bucket comienza con un dígito específico (por ejemplo, “1”). Ejemplo de política en
- Probar el Acceso:
- Intenta listar el contenido del bucket con el perfil del usuario:
aws --profile enum s3 ls s3://<nombre-del-bucket>
- Si falla con “AccessDenied”, ajusta el dígito en la condición (de 0 a 9) y repite hasta que tengas éxito, revelando el primer dígito del ID.
- Intenta listar el contenido del bucket con el perfil del usuario:
- Iterar para Dígitos Siguientes:
- Modifica la condición para incluir más dígitos (por ejemplo,
"12*"
), y continúa hasta obtener el ID completo.
- Modifica la condición para incluir más dígitos (por ejemplo,
Ejemplo Práctico
- Si el bucket es
s3://ejemplo-bucket-publico
, prueba con diferentes condiciones:"0*"
→ AccessDenied"1*"
→ Éxito (el ID comienza con 1)"12*"
→ Éxito (siguiente dígito es 2)
- Automatiza el proceso con un script que itere sobre los dígitos.
Enumeración de Usuarios IAM en Otras Cuentas
Descripción
Esta técnica abusa de la validación de políticas IAM para identificar usuarios existentes en una cuenta objetivo, utilizando el ID de cuenta previamente obtenido.
Pasos Clave
- Crear un Bucket S3 en la Cuenta del Atacante:
- Genera un bucket único:
aws s3 mb s3://mi-bucket-$RANDOM-$RANDOM-$RANDOM
- Genera un bucket único:
- Definir una Política de Acceso:
- Crea una política que otorgue acceso a un usuario específico en la cuenta objetivo. Ejemplo en
grant-s3-bucket-read.json
:{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowUserToListBucket", "Effect": "Allow", "Resource": "arn:aws:s3:::mi-bucket-12345-67890-54321", "Principal": { "AWS": ["arn:aws:iam::123456789012:user/cloudadmin"] }, "Action": "s3:ListBucket" } ] }
- Aplica la política al bucket:
aws s3api put-bucket-policy --bucket mi-bucket-12345-67890-54321 --policy file://grant-s3-bucket-read.json
- Crea una política que otorgue acceso a un usuario específico en la cuenta objetivo. Ejemplo en
- Verificar Existencia:
- Si la política se aplica sin errores, el usuario existe.
- Si retorna “Invalid principal in policy”, el usuario no existe.
Ejemplo Práctico
- Prueba con
arn:aws:iam::123456789012:user/admin
:- Éxito → El usuario “admin” existe.
- Error → Prueba otro nombre como “nonexistent”.
- Automatiza con una lista de nombres de usuarios potenciales.
Herramientas Útiles
Pacu
- Descripción: Herramienta para automatizar la enumeración en AWS, incluyendo roles IAM.
- Instalación en Kali:
sudo apt update sudo apt install pacu
- Uso Básico:
- Inicia Pacu:
pacu
- Importa claves:
import_keys <perfil>
- Ejecuta la enumeración de roles:
run iam__enum_roles --word-list /ruta/a/lista.txt --account-id <ID_de_cuenta>
- Inicia Pacu:
AWSBucketDump
- Descripción: AWSBucketDump es una herramienta diseñada para enumerar y descargar datos de buckets S3 públicos en AWS.
- https://github.com/jordanpotti/AWSBucketDump.git
- Uso Básico:
- Ejecuta el script para buscar buckets públicos:
python AWSBucketDump.py -l lista_de_buckets.txt
- Descarga los datos de los buckets encontrados:
python AWSBucketDump.py -d -l lista_de_buckets.txt
- Ejecuta el script para buscar buckets públicos:
- Valor: Automatiza la identificación y extracción de datos sensibles de buckets S3 públicos, facilitando la enumeración en entornos AWS.
Ejemplo con Lista de Roles
- Crea una lista en
/tmp/role-names.txt
:lab_admin security_auditor content_creator
- Ejecuta:
run iam__enum_roles --word-list /tmp/role-names.txt --account-id 123456789012