A tag to rule them all: Using AWS tags to enumerate cloud resources
Infrastructure Enumeration is the process of gathering information about a target, after gaining initial access. Enumeration depends on the level of privileges an attacker gets on the initial access
Intro
Infrastructure Enumeration is the process of gathering information about a target, after gaining initial access. Enumeration depends on the level of privileges an attacker gets on the initial compromise. For AWS, privileges are split by API call, so if an identity can has a policy that only allows access to iam:ListUsers
, they are not allowed to execute any other API call (except for sts:GetCallerIdentity
, but that is allowed by default to all identities).
To enumerate resources, an identity will need to know what access they have on the account and then know how what resources can be accessed. Due to how AWS manages privileges and API calls, this will result in many failed attempts and logs generated, which might tip off a defender.
This leads to the attacker needing to find creative workarounds to be able to retrieve the information they need. Bruteforce has been a technique used a lot in Cloud Pentesting, where an attacker will attempt to execute an API call and either get the information, or an access denied. Information gathering using bruteforce is a known technique. Unauthenticated identity finding, subdomain enumeration, password spraying, are all techniques used to gather another information that can be utilized for further access. Abusing indirect information gathering, like getting information through error messages, tool output or tool interaction with security products are also known and used techniques. In this blog, we will see just that. We will go through how an attacker can utilize Resource Tags
to enumerate AWS hosted environments and how to utilize bruteforce and very minimal permissions to enumerate the resources inside such environments.
This research will culminate in the release of TagNabIt
, a tool which encapsulates the techniques discussed throughout this blog. TagNabIt
automates the bruteforce and enumeration of AWS resources using their tags, showcasing how the concepts explored here can be applied in practice to retrieve information, we otherwise would not have been able to, and ultimately strengthen the security posture of cloud environments.
Cloud Enumeration
On-Premise Active Directory infrastructure utilizes LDAP, which works as a database containing all the domain objects. On an Active Directory domain, each user by default, will get enough permissions to list all objects, their ACL, GPOs, etc. That also includes domains and forests, their relationships with each other and if allowed, resources on those other domains and forests. Using it, an attacker can create a map of the entire infrastructure. Tools like BloodHound
even make it easier to graph the relationship between the resources.
Cloud environments on the other hand, are harder to enumerate. AWS for example, follow the principle of Least-Privilege
, by utilizing whitelisting. That means, an identity, by default, will only be allowed to execute sts:GetCallerIdentity
, which is the equivalent of whoami
for AWS and nothing else. Every other permission has to be assigned to the identity so it can be executed by them. In AWS, for an attacker to know what permissions they currently have, they will first need access to other permissions. Permissions like iam:ListUserPolices
, iam:ListAttachedUserPolicy
, iam:ListGroups
, iam:ListGroupsForUser
, iam:ListGroupPolicies
, iam:ListAttachedGroupPolicies
), provide the identity with the necessary knowledge to know what permissions they have on the AWS account. Following the principle of Least-Privilege
, not every identity will have access to them. That is why, attacker are opting for bruteforcing API calls. That is achieved by executing each API call they might need and hope they have access to any of them. Tools like enumerate-iam
and Pacu’s iam__bruteforce_permissions
module are primary examples of this. This leads to three issues.
First of, too many failed attempts will result in suspicious activity. An identity will not usually have so many failed attempts, especially if these tools are used as-is, without trying to modify their User-Agent. This can lead to immediate detection by the detection team.
There might be some requests that require previous information from the user. If the attacker does not have that information, they either hope another API call will provide it to them or, attempt to use dummy strings to fill the required information.
Pacu
is known for usingDummydata
strings to fill required information, which becomes an easy detection.Lastly, if a request attempts to write a resource (create, update, delete), if the attacker needs to know if they have access or not, they will need to execute it. That means, the attacker will try to write the resource. This means, a resource will either get created, updated or deleted, which might potentially cause cost or denial of service issues. There are some EC2 and S3 API calls with a
DryRun Capability
(the onesPacu’s iam__bruteforce_permissions
is utilizing), but aside from those two services, the rest do not have aDryRun Capability
, resulting in changes to resources in case the attacker tries to execute the call and is successful.
This means, an attacker needs to find alternative ways to enumerate an account and the resources inside it.
Resource Tagging
Tagging resources is a best-practice recommendation for Cloud based infrastructures, as it will allow better grouping and management of resources. There are some services which by default will be adding tags to the resources they are using, as to group them based on the functionality.
AWS Tagging
AWS tags have a key and value format, both which can be provided by the identity which creates the tag. That means, any string can be put as key and any string as value. A resource can have more than one tag. Below is an example of tags belongs to a RDS Instance
, one for the instance name and another for its administrative user.
"Tags": [
{
"Key": "Name",
"Value": "RDS-Instance"
},
{
"Key": "Username",
"Value": "admin"
}
]
AWS by default, will try to name some resources on creation, with the option that some of them can have their name modified later on. This allows the account owners and users to identify which resources they will need to use. They will do so, by utilizing Resource Tags
. The name of the resources in AWS will be a tag with the key “Name”
, or an equivalent and the value, will be the identifier.
Aside from the tags AWS provides, an administrator can also put tags on resources themselves. This allows for an administrator/DevOps engineer to distinct and separate resources based on usage or project, as well as manage permissions towards resources based on tags on them. In the AWS IAM policy below, the identity will be allowed to describe all instances which contain the tag Owner
and the tag Owner
value is the identity with the policy attached.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringEquals": {"aws:ResourceTag/Owner": "${aws:username}"}
}
},
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*"
}
]
}
**Policy Code taken from https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html*
Azure Tags
Azure allows tagging for Subscriptions and the resources inside them, but not EntraID resources. For each resource type, on their section on the Azure Portal, there is a tab called Tags
, where the tags and resources are listed, created, or deleted.

Similar to AWS, Azure resources can be managed using tags and privileges can be assigned to and for them, allowing or denying access to such resources based on the tags they have:
"policyRule": {
"if": {
"anyOf": [
{
"field": "tags['Env']",
"notEquals": "[resourcegroup().tags['Env']]"
},
{
"field": "tags['Env']",
"exists": false
}
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['Env']",
"value": "[resourcegroup().tags['Env']]"
}
]
}
}
}
**Below policy copied from https://learn.microsoft.com/en-us/azure/governance/policy/tutorials/govern-tags*
GCP Tags
GCP offers tags as a feature, but extend upon their functionality. GCP has 3 types of tagging for resources, Labels
, Resource Tags
and Network Tags
. There are other naming conventions like project name, identity names, etc, but they are not considered tags.
Resource Tags
have a key-value format, and are attached to resources, but can be managed centrally by theResource Manager
. The connection between a resource and a tag is called abinding
.gcloud resource-manager tags bindings create \\ --tag-value=tagValues/678901234567 \\ --parent=//compute.googleapis.com/projects/my-project/zones/us-central1-a/instances/my-instance
Labels
, which have a key-value format and are placed on resources specifically, meaning there is no centralized method of managing them (creating, deleting, modifying, listing)labels: - key: environment value: production - key: team value: backend
Network Tags
, are placed in order to assist inNetwork Rules
. They have a value-only format, with the value, being the value of the tag of the rule created.tags: - web-server - allow-ssh
Which then can be used to create firewall rules with target tags. Then, if those tags are assigned to resources, the firewall rule is applied:
gcloud compute firewall-rules create allow-ssh-from-anywhere \\ --direction=INGRESS \\ --priority=1000 \\ --network=default \\ --action=ALLOW \\ --rules=tcp:22 \\ --target-tags=allow-ssh \\ --source-ranges=0.0.0.0/0 gcloud compute instances create my-vm \\ --zone=us-central1-a \\ --machine-type=e2-medium \\ --image-family=debian-11 \\ --image-project=debian-cloud \\ --tags=allow-ssh \\ --metadata=ssh-keys="your-username:ssh-rsa AAAAB3Nza... your-username"
AWS Resource Tag Mapping
This blog will only go through AWS Tags and their enumeration. As previously mentioned, AWS follows a Key-Value approach for their tags. The tags are attached to the resource. AWS does have a pseudo centralized management API, in the form of ResourceGroupsTaggingAPI
, but due to each tag being attached to the resources, in order to tag a resource on a service, calling the identity needs to have both tag:TagResources
and the tagging permission for the specific resource, for example ec2:CreateTags
for EC2 specific resources.
From the AWS Docs for TagResources In addition to the
tag:TagResources
permission required by this operation, you must also have the tagging permission defined by the service that created the resource. For example, to tag an Amazon EC2 instance using theTagResources
operation, you must have both of the following permissions:In addition to the
tag:TagResources
permission required by this operation, you must also have the tagging permission defined by the service that created the resource. For example, to tag an Amazon EC2 instance using theTagResources
operation, you must have both of the following permissions:
tag:TagResources
ec2:CreateTags
Tag Editor and Resource Explorer
AWS Tagging Editor
is the old, on-deprecation method of listing resources and managing their tags through the AWS Management Console
. It will execute many API calls, list resources, get resource information and list their tags, if they have any. The user has the option to filter by region, resource type and tags for each service.
This of course, will result in a lot of events being generated, as all resources from all services and regions will be listed.

Resource Explorer is the new dashboard to manage the resources and their tags, pushing for more filters like, List Resources with or without Tags. Same as AWS Tagging Editor, the usage of Resource Explorer will generate a lot of activity.

Listing AWS Resources using API
Using ResourceGroupsTagging API
There are 3 API calls that allow listing of resources and their tags. Those are tags:GetResources
, tag:GetTagKeys
and tag:GetTagValues
. tag:GetResources
will list many of the resources in the account, along with their tags.

There is a lack of consistency on what is listed and what is not listed using tag:GetResources
though. For example, IAM Policies
and EC2 Instance Profiles
are listed, but not IAM Users
, Groups
or Roles
. That is because AWS does not support all resources. According to AWS Docs, tag:GetResources
will not list untagged resources.
From AWS Docs (https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html)
GetResources
does not return untagged resources. To find untagged resources in your account, useAWS Resource Explorer
with a query that usestag:none
. For more information, see Search query syntax reference for Resource Explorer.
That is not true, as non-tagged resources will indeed get listed, but what will not get listed are a group of resources, like IAM Users
, Roles
, Inline Policies
, EC2 Instances
, etc.

In case tag:GetResources
privilege is not allowed to be executed, there are two additional API calls which an attacker can utilize:
tag:GetTagKeys
tag:GetTagValues
tag:GetTagKeys
will return a list of unique keys assigned on resources and tag:GetTagValues
will take a tag key as an input and output the value assigned to it. Neither of them will list the resources that contain the tags. But, through the tags, we can retrieve other information about the environment, resources, owners, resources associated with them, etc. The next section goes through the information that can be retrieved using tags. For now, if we can get a list of keys from tag:GetTagKeys
and pass them to tag:GetTagValues
, and potentially retrieve information about the target.

Resources listed using Tags
Every resource returned will have its Tags
field, either filled or not. The tags can be set by the identity that created the resource, or can be assigned by AWS itself, when the resource is first created.
We took a look at several AWS services and resources. Some of the resources we have noticed, where a tag is assigned by default are:
Resources where the name assigned at creation is actually a tag, usually under the tag key
Name
:EC2 Instances
Security Group
Subnets
S3 Buckets
used byCodestar
(not all S3 Buckets)SMS-Voice Registration
Route Tables
VPCs
andVPC Endpoints
Resources as part of a deployment, which provide information about other resources
Codestar Projects
have many resources that they use and all the resources will have some a tag which points to the project ARN under the keyawscodestar:projectArn
API Gateway
Cloudformation Stack
CodeCommit Repository
Code Deploy Application
CodePipeline Pipelines
Security Groups
S3 Buckets
Lambda Functions
Resources which give information about the root account or the creator
CloudFormation Stacks
, will contain a tag listing theCloud9 Owner
and if created by the root user, will show the root userGlue Endpoints
, will show the owner, which by default will be the creator
SSM Access on EC2 Instances
SSM Sessions
are created whenssm:StartSession
is executed and by default stay for some time, or untilssm:TerminateSession
is executed. Those sessions will contain a tag with the ID of the target EC2 Instance ("Key": "aws:ssmmessages:target-id"; "Value": "i-123456789abc12345"
) and the ARN will contain the name of the session consisting of the user and a long stringarn:aws:ssm:us-east-1:123456789012:session/admin-someLongString1234566
. This session ID can later be passed tossm:ResumeSession
to regain a session access, or just gather information on whichEC2 instances
allowSSM access
and the identities with this access allowed.
Bruteforce Resources using Tags
For the most part, almost each service will have an API call like <service>:ListTags
<service>:GetTags
, <service>:ListTagsForResource
, <service>:ListTagsForResources
, <service>:Get<Resource>Tags
or <service>:List<Resource>Tags
. There are some exceptions shown on the other sections below, but for the most part, most calls with either have ResourceName
, ResourceARN
or ResourceId
as the input parameter. If access to execute the API is denied, an AccessDenied
error will be returned. If a resource exists, and we have access to execute the service’s tag related API call, the tags will be returned. If the resource does not exist and we have access to execute the call, a ResourceNotFoundFault
error will be returned. Utilizing all of it, we can create a script which will get a list of resource ID, names or ARNs, based on the input and try to execute the corresponding service tag related API call.
Image here
There are currently 255 services that allow tag based enumeration:
[*] acm-pca
[*] acm
[*] apigateway
[*] apigatewayv2
[*] backup
[*] ce
[*] cloudhsmv2
[*] cloudtrail
[*] connect
[*] dax
[*] directconnect
[*] dynamodb
[*] ecr-public
[*] efs
[*] elb
[*] elbv2
[*] es
[*] firehose
[*] glacier
[*] glue
[*] kinesisvideo
[*] kms
[*] lakeformation
[*] lambda
[*] logs
[*] machinelearning
[*] memorydb
[*] mq
[*] opensearch
[*] opsworks
[*] resource-groups
[*] route53
[*] sagemaker
[*] sqs
[*] workspaces
[*] accessanalyzer
[*] amp
[*] amplify
[*] appconfig
[*] appfabric
[*] appflow
[*] appintegrations
[*] application-autoscaling
[*] application-insights
[*] appmesh
[*] apprunner
[*] appstream
[*] appsync
[*] athena
[*] auditmanager
[*] b2bi
[*] backup-gateway
[*] batch
[*] bcm-data-exports
[*] bedrock-agent
[*] bedrock
[*] billingconductor
[*] braket
[*] chime-sdk-identity
[*] chime-sdk-media-pipelines
[*] chime-sdk-meetings
[*] chime-sdk-messaging
[*] chime-sdk-voice
[*] cleanrooms
[*] cleanroomsml
[*] cloud9
[*] clouddirectory
[*] cloudfront
[*] cloudhsm
[*] cloudwatch
[*] codeartifact
[*] codecommit
[*] codedeploy
[*] codeguru-reviewer
[*] codeguru-security
[*] codeguruprofiler
[*] codepipeline
[*] codestar-connections
[*] codestar-notifications
[*] cognito-identity
[*] cognito-idp
[*] comprehend
[*] config
[*] connectcampaigns
[*] connectcases
[*] controltower
[*] cur
[*] customer-profiles
[*] databrew
[*] dataexchange
[*] datasync
[*] datazone
[*] detective
[*] devicefarm
[*] dlm
[*] dms
[*] docdb-elastic
[*] docdb
[*] drs
[*] ds
[*] ecr
[*] ecs
[*] eks
[*] elasticache
[*] elasticbeanstalk
[*] emr-containers
[*] emr-serverless
[*] entityresolution
[*] events
[*] evidently
[*] finspace
[*] fis
[*] fms
[*] forecast
[*] frauddetector
[*] fsx
[*] gamelift
[*] globalaccelerator
[*] grafana
[*] greengrass
[*] greengrassv2
[*] groundstation
[*] guardduty
[*] healthlake
[*] imagebuilder
[*] inspector
[*] inspector2
[*] internetmonitor
[*] iot
[*] iotanalytics
[*] iotdeviceadvisor
[*] iotevents
[*] iotfleethub
[*] iotfleetwise
[*] iotsecuretunneling
[*] iotsitewise
[*] iotthingsgraph
[*] iottwinmaker
[*] iotwireless
[*] ivs-realtime
[*] ivs
[*] ivschat
[*] kafka
[*] kendra-ranking
[*] kendra
[*] keyspaces
[*] kinesisanalytics
[*] kinesisanalyticsv2
[*] lex-models
[*] lexv2-models
[*] license-manager
[*] location
[*] lookoutequipment
[*] lookoutmetrics
[*] lookoutvision
[*] m2
[*] macie2
[*] managedblockchain
[*] marketplace-catalog
[*] marketplace-deployment
[*] mediaconnect
[*] mediaconvert
[*] medialive
[*] mediapackage-vod
[*] mediapackage
[*] mediapackagev2
[*] mediastore
[*] mediatailor
[*] medical-imaging
[*] mgn
[*] migration-hub-refactor-spaces
[*] migrationhuborchestrator
[*] mwaa
[*] neptune-graph
[*] neptune
[*] network-firewall
[*] networkmanager
[*] networkmonitor
[*] oam
[*] omics
[*] opensearchserverless
[*] opsworkscm
[*] organizations
[*] osis
[*] outposts
[*] panorama
[*] payment-cryptography
[*] pca-connector-ad
[*] personalize
[*] pi
[*] pinpoint-email
[*] pinpoint-sms-voice-v2
[*] pinpoint
[*] pipes
[*] proton
[*] qbusiness
[*] qconnect
[*] qldb
[*] quicksight
[*] rbin
[*] rds
[*] redshift-serverless
[*] rekognition
[*] repostspace
[*] resiliencehub
[*] resource-explorer-2
[*] robomaker
[*] rolesanywhere
[*] route53-recovery-control-config
[*] route53-recovery-readiness
[*] route53resolver
[*] rum
[*] s3control
[*] sagemaker-geospatial
[*] savingsplans
[*] scheduler
[*] schemas
[*] securityhub
[*] securitylake
[*] service-quotas
[*] servicecatalog-appregistry
[*] servicediscovery
[*] sesv2
[*] shield
[*] signer
[*] simspaceweaver
[*] snow-device-management
[*] sns
[*] ssm-contacts
[*] ssm-incidents
[*] ssm-sap
[*] ssm
[*] sso-admin
[*] stepfunctions
[*] storagegateway
[*] swf
[*] synthetics
[*] textract
[*] timestream-query
[*] timestream-write
[*] tnb
[*] transcribe
[*] transfer
[*] translate
[*] voice-id
[*] vpc-lattice
[*] waf-regional
[*] waf
[*] wafv2
[*] wellarchitected
[*] wisdom
[*] workmail
[*] workspaces-thin-client
[*] workspaces-web
[*] xray
Other AWS Tagging Enumeration
As stated before, there are some other services do not have a ListTagsForResource
, or other equivalent API calls, but still allow bruteforce or enumeration of resources using tags. IAM
is the best example, where we can still bruteforce its resources, but the API calls and input parameters are different. On the other hand, some other services like ECR
, Cost Explorer
, EC2
, Lakeformation
, Autoscaling
, Discovery
, Redshift
, allow listing of resources and their tags using API calls, without the need of bruteforce.
IAM Enumeration
IAM
has 8 API calls
that allow enumeration of IAM Users
, Roles
, Policies
, MFA Devices
, SAML Provider
, Certificate Servers
, Instance Providers
, Open ID Connect Providers
. Each asking an input of resource ARN or resource name. The output is still the same, where an AccessDenied
is returned when requesting identity has no access to it, ResourceNotFound
, when resource does not exist, or Tags
when it does.
{
"list_instance_profile_tags": [
"InstanceProfileName"
],
"list_mfa_device_tags": [
"SerialNumber"
],
"list_open_id_connect_provider_tags": [
"OpenIDConnectProviderArn"
],
"list_policy_tags": [
"PolicyArn"
],
"list_role_tags": [
"RoleName"
],
"list_saml_provider_tags": [
"SAMLProviderArn"
],
"list_server_certificate_tags": [
"ServerCertificateName"
],
"list_user_tags": [
"UserName"
]
}
Other Services
Other Services and calls that allow enumeration include services ECR
, Cost Explorer
, EC2
, Lakeformation
, Autoscaling
, Discovery
, Redshift
. Neither of them requires an input, except for ce:GetTags
, which requires a Time Period
Input, which can be anything and will return a list of Resources
and their Tags
. This will work the same as tag:GetResources
, where an API call will list resources.
ecr:DescribeImageTags
ce:GetTags
, requiringTimePeriod
as an input, but can be any time framece:ListCostAllocationTags
ec2:DescribeTags
lakeformation:ListLFTags
autoscaling:DescribeTags
discovery:DescribeTags
redshift:DescribeTags
Introducing TagNabIt
The research culminated in the development of a comprehensive four-part tool, TagNabIt
. This tool is designed to enhance cloud environment enumeration through the following capabilities:
Resource Enumeration: Leverages API calls that avoid the need for brute force techniques.
IAM Resource Brute Forcing: Identifies IAM resources through tag-related API calls.
Resource-Specific Tag Brute Forcing: Discovers other resource types using their respective tag-related API endpoints.
CloudTrail Log Analysis: Searches CloudTrail logs to detect occurrences of tag-based enumeration activity.
For all functionalities, TagNabIt
requires a locally stored IAM profile (within the .aws
directory), the target region, and a list of resources to enumerate.

Enumerate Resources using Tags
TagNabIt
leverages API calls that do not require predefined input parameters to enumerate resources efficiently. These include:
tag:GetResources
ecr:DescribeImageTags
ce:GetTags
(requiresTimePeriod
as an input)ce:ListCostAllocationTags
ec2:DescribeTags
lakeformation:ListLFTags
autoscaling:DescribeTags
discovery:DescribeTags
redshift:DescribeTags
By utilizing these API endpoints, TagNabIt
can enumerate a wide range of AWS resources without relying on prior knowledge of their identifiers.
$ python3 TagNabIt.py ENUMERATERESOURCES
--------------------------------------------------------------------------------------------------------------------
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░████ Key: Name █████░░ ░░████ Key: Type ███░░ ░░████ Key: PolicyName ███░░
░░████ Value: EC2 Instance█████░░ ░░████ Value: S3 Bucket ███░░ ░░████ Value: AdminPolicy ███░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
░░░░░░░░░░░ ░ ░░░░ ░░░ ░░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░ ░░░░░░░░░░░░░░░░░░░░
▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒▒▒▒▒ ▒▒ ▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▓▓▓▓▓▓▓▓▓▓▓ ▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓ ▓▓ ▓ ▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
██████████ ██████ █████ ██ ████ ██ ██ ██ ██ ████ █████ ████████ ███████████████████████
███████████ █ ███████ █████ ████ ███ ███ ███ ██ ████ ██ ███ █████ ███████████████████████
████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
--------------------------------------------------------------------------------------------------------------------
by gl4ssesbo1
--------------------------------------------------------------------------------------------------------------------
[*] Testing Account 012345678912...
[*] Enumerating AWS Resources using tag:GetResources...
[*] ------------------------------------------------------------!
[*] Enumerate using tag:GetResources!
[*] ------------------------------------------------------------!
[*] -----------------------------------------------------------------------------------!
[*] arn:aws:secretsmanager:us-east-1:012345678912:secret/somesecretvalue!
[*] -----------------------------------------------------------------------------------!
[*] Tags...
[*] Environment:prod
[*] Identity:AdministrativeUser
[*] ------------------------------------------------------------!
[*] Enumerate using ec2:DescribeTags!
[*] ------------------------------------------------------------!
[*] ---------------------!
[*] igw-012345678912abcdef012345!
[*] ---------------------!
[*] Tags...
[*] Environment:prod
[*] ------------------------------------------------------------!
[*] Enumerate using ce:GetTags!
[*] ------------------------------------------------------------!
[*] No tags found using lakeformation:ListLFTags!
[*] ------------------------------------------------------------!
[*] Enumerate using lakeformation:ListLFTags!
[*] ------------------------------------------------------------!
[*] No tags found using lakeformation:ListLFTags!
[*] ------------------------------------------------------------!
[*] Enumerate using autoscaling:DescribeTags!
[*] ------------------------------------------------------------!
[*] No tags found using autoscaling:DescribeTags!
[*] ------------------------------------------------------------!
[*] Enumerate using discovery:DescribeTags!
[*] ------------------------------------------------------------!
[*] No tags found using discovery:DescribeTags!
[*] ------------------------------------------------------------!
[*] Enumerate using redshift:DescribeTags!
[*] ------------------------------------------------------------!
[*] No tags found using redshift:DescribeTags
Bruteforcing IAM
Since IAM uses specific API calls and input to list resources and tags, it would be good to have a separate tool section to bruteforce IAM resources. They will be using the IAM specific API calls
, which will list all 8 Resource types allowed in IAM.
{
"list_instance_profile_tags": [
"InstanceProfileName"
],
"list_mfa_device_tags": [
"SerialNumber"
],
"list_open_id_connect_provider_tags": [
"OpenIDConnectProviderArn"
],
"list_policy_tags": [
"PolicyArn"
],
"list_role_tags": [
"RoleName"
],
"list_saml_provider_tags": [
"SAMLProviderArn"
],
"list_server_certificate_tags": [
"ServerCertificateName"
],
"list_user_tags": [
"UserName"
]
}
python3 TagNabIt.py BRUTEFORCEIAM -rf ../iamresources.txt -rt user -r us-east-1
--------------------------------------------------------------------------------------------------------------------
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░████ Key: Name █████░░ ░░████ Key: Type ███░░ ░░████ Key: PolicyName ███░░
░░████ Value: EC2 Instance█████░░ ░░████ Value: S3 Bucket ███░░ ░░████ Value: AdminPolicy ███░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
░░░░░░░░░░░ ░ ░░░░ ░░░ ░░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░ ░░░░░░░░░░░░░░░░░░░░
▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒▒▒▒▒ ▒▒ ▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▓▓▓▓▓▓▓▓▓▓▓ ▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓ ▓▓ ▓ ▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
██████████ ██████ █████ ██ ████ ██ ██ ██ ██ ████ █████ ████████ ███████████████████████
███████████ █ ███████ █████ ████ ███ ███ ███ ██ ████ ██ ███ █████ ███████████████████████
████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
--------------------------------------------------------------------------------------------------------------------
by gl4ssesbo1
--------------------------------------------------------------------------------------------------------------------
[*] Testing Account 012345678912...
[*] Bruteforcing IAM users...
[*] Resource Found: 'someUser'!
{
"Tags": [
{
"Key": "Environment",
"Value": "Prod"
}
],
"IsTruncated": false
}
Bruteforcing Resources
TagNabIt
performs brute-force enumeration across 255 AWS services by systematically invoking tag-related API calls. If an incorrect resource ID format is supplied or the corresponding API call for a specific service does not exist, the tool gracefully handles the failure and returns an appropriate error message.
$ python3 TagNabIt.py BRUTEFORCERESOURCES -rf ../cloudtrailresources.txt -s cloudtrail -r us-east-1 -v
--------------------------------------------------------------------------------------------------------------------
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░████ Key: Name █████░░ ░░████ Key: Type ███░░ ░░████ Key: PolicyName ███░░
░░████ Value: EC2 Instance█████░░ ░░████ Value: S3 Bucket ███░░ ░░████ Value: AdminPolicy ███░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
░░░░░░░░░░░ ░ ░░░░ ░░░ ░░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░ ░░░░░░░░░░░░░░░░░░░░
▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒▒▒▒▒ ▒▒ ▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▓▓▓▓▓▓▓▓▓▓▓ ▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓ ▓▓ ▓ ▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
██████████ ██████ █████ ██ ████ ██ ██ ██ ██ ████ █████ ████████ ███████████████████████
███████████ █ ███████ █████ ████ ███ ███ ███ ██ ████ ██ ███ █████ ███████████████████████
████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
--------------------------------------------------------------------------------------------------------------------
by gl4ssesbo1
--------------------------------------------------------------------------------------------------------------------
[*] Testing Account 012345678912...
[*] Bruteforcing AWS Resources for service cloudtrail...
[*] Retrieving ARNs from file ../cloudtrailresources.txt!
[*] 2 ARNs retrieved from file ../cloudtrailresources.txt!
[*] Error Bruteforcing resource arn:aws:cloudtrail:us-east-1:012345678912:trail/trial1 in service cloudtrail An error occurred (CloudTrailARNInvalidException) when calling the ListTags operation: You must specify an ARN that the caller account can access.!
[*] Resource arn:aws:cloudtrail:us-east-1:012345678912:trail/testtrialbleon exists!
{
"ResourceTagList": [
{
"ResourceId": "arn:aws:cloudtrail:us-east-1:012345678912:trail/testtrialbleon",
"TagsList": [
{
"Key": "somekey",
"Value": "somevalue"
}
]
}
]
}
Find occurrences of Tag Enumeration or Bruteforce in Logs
The final feature of TagNabIt
focuses on log analysis. It utilizes the cloudtrail:LookupEvents
API to retrieve CloudTrail logs
and identify patterns indicative of tag-based enumeration or brute-force activity. These findings can then be reviewed and investigated further by the security team to assess potential threats or suspicious behavior.
$ python3 TagNabIt.py CHECKUSAGE
--------------------------------------------------------------------------------------------------------------------
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░████ Key: Name █████░░ ░░████ Key: Type ███░░ ░░████ Key: PolicyName ███░░
░░████ Value: EC2 Instance█████░░ ░░████ Value: S3 Bucket ███░░ ░░████ Value: AdminPolicy ███░░
░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░ ░░█████░░░░░░░░░░░░░░░░░░░░░░░░░████░░
░░██████████████████████████████████░░ ░░██████████████████████████████████░░ ░░██████████████████████████████████░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
░░░░░░░░░░░ ░ ░░░░ ░░░ ░░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░ ░░░░░░░░░░░░░░░░░░░░
▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒▒▒▒▒ ▒▒ ▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▓▓▓▓▓▓▓▓▓▓▓ ▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓ ▓▓ ▓ ▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
██████████ ██████ █████ ██ ████ ██ ██ ██ ██ ████ █████ ████████ ███████████████████████
███████████ █ ███████ █████ ████ ███ ███ ███ ██ ████ ██ ███ █████ ███████████████████████
████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
--------------------------------------------------------------------------------------------------------------------
by gl4ssesbo1
--------------------------------------------------------------------------------------------------------------------
[*] Testing Account 0123456789012...
[*] Finding Occurrences of Tag Based Enumeration in Cloud...
[*] Finding usage of tag bruteforce on logs...
[*] Finding usage of resourcegroupstaggingapi:GetResources in logs...
[*] Found 6 occurrences of resourcegroupstaggingapi:GetResources in logs!
[*] Finding usage of acm-pca:ListTags in logs...
[*] Found 0 occurrences of acm-pca:ListTags in logs!
[*] Finding usage of acm:ListTagsForCertificate in logs...
[*] Found 270 occurrences of acm:ListTagsForCertificate in logs!
[*] Finding usage of apigateway:GetTags in logs...
[*] Found 0 occurrences of apigateway:GetTags in logs!
[*] Finding usage of apigatewayv2:GetTags in logs...
[*] Found 0 occurrences of apigatewayv2:GetTags in logs!
[*] Finding usage of autoscaling:DescribeTags in logs...
--snip--
[*]
Detecting the Attack
The most effective detection method for this type of attack is monitoring for patterns of repeated brute-force attempts against resource identifiers. During such activity, an attacker must supply numerous resource IDs—many of which are likely to be invalid. This behavior generates a high volume of API calls that result in the InvalidResourceId
error code.
By correlating and identifying bulk occurrences of tag-based API calls returning InvalidResourceId
, security teams can reliably detect potential tag-based brute-force activity. Currently, there are 11 unique CloudTrail events associated with 255 AWS services that support this form of tag-based brute-forcing.
ListTagsForResource
DescribeTags
GetResourceLFTags
GetTags
ListResourceTags
ListTags
ListTagsForCertificate
ListTagsForDeliveryStream
ListTagsForResources
ListTagsOfResource
ListTagsForVault
Conclusion
Enumeration on cloud-hosted environments is notoriously challenging due to the abstraction layers, managed services, and limited visibility that cloud providers inherently impose. Unlike traditional on-premises infrastructures where an attacker or security researcher might have direct access to network topology, internal services, and host configurations, cloud environments rely heavily on APIs, permissions, and identity-based access controls. This complexity does not mean enumeration is impossible—it simply requires a different mindset and approach.
By shifting perspective and focusing on what information can be gathered from any accessible source, even seemingly insignificant data points can become valuable. For example, metadata services, publicly exposed endpoints, or cloud provider-specific APIs can reveal hints about the environment’s structure. Similarly, something as simple as a tag assigned to a resource—perhaps indicating an environment name, owner, or purpose—can unintentionally disclose information about internal architecture or workflows. These small details, when aggregated, can paint a much clearer picture of the cloud environment.
Once initial information is gathered, it can be correlated to identify relationships between resources, privilege boundaries, and potential misconfigurations. This incremental discovery process can expose weak points, such as overly permissive IAM roles, forgotten storage buckets, exposed management interfaces, or neglected services. In many cases, these weaknesses originate from the complexity of cloud deployments and the tendency for security configurations to drift over time.
Ultimately, effective cloud enumeration is about leveraging every available angle—API calls, error messages, naming conventions, logs, and even resource tags—to build situational awareness. When approached methodically, this process can uncover hidden attack surfaces and provide critical insights into securing or, in the case of red teaming, exploiting cloud infrastructure.
Last updated
Was this helpful?