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 using Dummydata 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 ones Pacu’s iam__bruteforce_permissions is utilizing), but aside from those two services, the rest do not have a DryRun 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 the Resource Manager. The connection between a resource and a tag is called a binding.

    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 in Network 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 the TagResources 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 the TagResources 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, use AWS Resource Explorer with a query that uses tag: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 by Codestar (not all S3 Buckets)

    • SMS-Voice Registration

    • Route Tables

    • VPCs and VPC 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 key awscodestar: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 the Cloud9 Owner and if created by the root user, will show the root user

    • Glue Endpoints, will show the owner, which by default will be the creator

  • SSM Access on EC2 Instances

    • SSM Sessions are created when ssm:StartSession is executed and by default stay for some time, or until ssm: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 string arn:aws:ssm:us-east-1:123456789012:session/admin-someLongString1234566. This session ID can later be passed to ssm:ResumeSession to regain a session access, or just gather information on which EC2 instances allow SSM 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, requiring TimePeriod as an input, but can be any time frame

  • ce: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 (requires TimePeriod 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?