AWS Secrets Manager Enumeration – Cybr Lab Walkthrough

Secrets Manager enumeration lab walkthrough

In this lab walkthrough, we’re going to take a look at how to enumerate the AWS Secrets Manager service in order to better understand how the service works, and also to figure out how to access secrets stored in an AWS account.

This walkthrough uses a completely free lab that only requires a free account registration.

Also, I have a video walkthrough if you prefer that format:

Why Secrets Manager enumeration is important

I created this lab because extracting secrets from Secrets Manager is an important part of our IAM PrivEsc course where you learn how to escalate your IAM privileges in AWS in order to either exfiltrate sensitive S3 data, or extract secrets stored in the account.

That way, if you’re not already familiar with the process of enumeration in AWS, or you’re not familiar with Secrets Manager, this gives you an easy-to-follow walkthrough.

Secrets Manager is a service that organizations can use to store their secrets, which makes it a juicy target for attackers. As security professionals, it’s our job to find potential weaknesses in our organization’s environments so that we can fix them before threat actors find them.

Configuring our AWS CLI

Once your lab has launched, we’re given an access key ID and secret access key.

If you don’t already have the AWS CLI installed, you will need that to complete this lab, so pause here and go to this page that will walk you through how to quickly and easily install it.

Then, in your terminal, type:

aws configure

AWS Access Key ID [None]: AKIAT6...
AWS Secret Access Key [None]: sa3CB4...
Default region name [None]: us-east-1
Default output format [None]:

Code language: CSS (css)

(Make sure you use us-east-1 as our labs always use this region unless otherwise specified)

(For default output format, you can just press enter to leave the default value of None. I tend to prefer JSON though so I usually go with that)

Once you have your AWS access keys set up, it’s time to enumerate!

IAM Enumeration

Because IAM controls a lot in AWS when it comes to access control, for us to know whether we can even enumerate Secrets Manager or not, we need to understand what policies we have either for our current user or current role (depending on what you have access to — in the case of this lab, a user).

We’re also going to have a separate lab walkthrough explaining IAM enumeration, so check out our channel for that.

Let’s start with a very common command used by AWS professionals and attackers:

aws sts get-caller-identity
Code language: JavaScript (javascript)

Our result should look something like this:

{
    "UserId": "AIDAT6ZKEI3E3J2XL4E5B",
    "Account": "921234892411",
    "Arn": "arn:aws:iam::921234892411:user/sm-enumeration-Julie"
}

Code language: JSON / JSON with Comments (json)

We can tell from this that we’re authenticated as a user. Let’s start trying to enumerate this user’s permissions.

We’ll start by listing out user policies (by copy/pasting the username, not the full ARN):

aws iam list-user-policies --user-name sm-enumeration-Julie
{
    "PolicyNames": [
        "AllowReadSecretsManager"
    ]
}

Code language: PHP (php)

We can see that the Julie user as a policy named AllowReadSecretsManager.

Let’s retrieve this policy:

aws iam get-user-policy --user-name sm-enumeration-Julie --policy-name AllowReadSecretsManager 

{
    "UserName": "sm-enumeration-Julie",
    "PolicyName": "AllowReadSecretsManager",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "iam:ListPolicies",
                    "iam:ListPolicyVersions",
                    "iam:GetPolicy",
                    "iam:GetUser",
                    "iam:GetUserPolicy",
                    "iam:ListUserPolicies"
                ],
                "Resource": "*",
                "Effect": "Allow",
                "Sid": "AllowIAMActions"
            },
            {
                "Action": [
                    "secretsmanager:GetSecretValue",
                    "secretsmanager:ListSecretVersionIds",
                    "secretsmanager:GetResourcePolicy",
                    "secretsmanager:DescribeSecret"
                ],
                "Resource": [
                    "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password*",
                    "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-api-key*"
                ],
                "Effect": "Allow",
                "Sid": "AllowSecretsManagerActions"
            },
            {
                "Action": [
                    "secretsmanager:ListSecrets"
                ],
                "Resource": "*",
                "Effect": "Allow",
                "Sid": "AllowListSecrets"
            }
        ]
    }
}

Code language: JavaScript (javascript)

We can see exactly what this policy permits, which is several actions, but let’s focus on the Secrets Manager actions:

  • secretsmanager:GetSecretValue
  • secretsmanager:ListSecretVersionIds
  • secretsmanager:GetResourcePolicy
  • secretsmanager:DescribeSecret
  • secretsmanager:ListSecrets

The first 4 actions are only allowed against two resources:

  • arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password*
  • arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-api-key*

This, by the way, gives us an indication that there are at least 2 secrets stored in this account, and that you likely have access to them.

To keep this lab focused, I’m not going to try and enumerate more policies like managed policies or group policies because there aren’t any. This is it, so we can move forward without further IAM enumeration.

Secrets Manager Enumeration

Now that we know our user Julie has access to read data from Secrets Manager, we need to familiarize ourselves with the Secrets Manager CLI. Luckily, this is a narrowly focused service, and so there are very few available commands which makes it easy to learn compared to some of the larger services (like IAM).

Since all we’re doing is enumerating, we can slim down the commands even further because we can ignore all non GET or LIST commands, which means we’re left with:

  • describe-secret
  • get-resource-policy
  • get-secret-value
  • list-secret-version-ids
  • list-secrets

Get-random-password is not relevant for this since it’s an operational command, so I left that out as well.

By the way, the next lesson in this course has these commands already listed out for you which you can use as a free reference guide if you want.

Ok, so first things first, we need to:

  1. Verify that — even though we have a policy allowing us — we do indeed have access to Secrets Manager in this account (there could be a boundary permission blocking access, or even a resource policy blocking access, more on that below)
  2. See if this account even has any secrets stored or not

To clarify on point #1: what we enumerated above is an identity-based policy, which grants our identity (user Julie) access. However, Secrets Manager also can use resource-based policies which specify who can access the secret and the actions they can perform on that secret. You can read more on that here but the gist is that just because your user has access via an identity-based policy, it doesn’t mean the resource-based policy will grant access.

So let’s use the list-secrets command to list out all secrets in this account stored in Secrets Manager:

aws secretsmanager list-secrets
Code language: PHP (php)

Because this command returns a lot of data, your terminal will likely enter “scroll mode” which is when you see a : in the bottom left. You can use your up/down arrow keys on your keyboard to scroll until you reach the end, or you can press q to exit that mode.

{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-api-key-rxnVJD",
            "Name": "sm-enumerate-api-key",
            "Description": "Secret containing an api secret key",
            "LastChangedDate": "2024-01-31T13:50:36.351000-07:00",
            "Tags": [
                {
                    "Key": "aws:cloudformation:stack-name",
                    "Value": "sm-enumerate"
                },
                {
                    "Key": "aws:cloudformation:logical-id",
                    "Value": "APISecretEncoded"
                },
                {
                    "Key": "aws:cloudformation:stack-id",
                    "Value": "arn:aws:cloudformation:us-east-1:921234892411:stack/sm-enumerate/60249f60-c07a-11ee-89d7-0e2c4e8725db"
                }
            ],
            "SecretVersionsToStages": {
                "4db98b6b-a7e9-86f8-0d42-1f684d01bc67": [
                    "AWSCURRENT"
                ]
            },
            "CreatedDate": "2024-01-31T13:50:36.306000-07:00"
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password-RR3paj",
            "Name": "sm-enumerate-password",
            "Description": "Secret containing a password",
            "LastChangedDate": "2024-01-31T13:50:36.422000-07:00",
            "Tags": [
                {
                    "Key": "aws:cloudformation:stack-name",
                    "Value": "sm-enumerate"
                },
                {
                    "Key": "aws:cloudformation:logical-id",
                    "Value": "PasswordSecret"
                },
                {
                    "Key": "aws:cloudformation:stack-id",
                    "Value": "arn:aws:cloudformation:us-east-1:921234892411:stack/sm-enumerate/60249f60-c07a-11ee-89d7-0e2c4e8725db"
                }
            ],
            "SecretVersionsToStages": {
                "652c5a16-bc3a-7ec3-48fb-a46b232742d5": [
                    "AWSCURRENT"
                ]
            },
            "CreatedDate": "2024-01-31T13:50:36.378000-07:00"
        }
    ]
}

Code language: JSON / JSON with Comments (json)

To issue this command, you must have secretsmanager:ListSecrets access (which we do)

From this command, we can see that we have a couple of results.

These results include:

  • Arn
  • Name
  • Description
  • and more…

As a next step and using the secret ID, which is the Name, we could run the list-secret-version-ids just to see if there are multiple versions of this secret:

aws secretsmanager list-secret-version-ids --secret-id sm-enumerate-password
Code language: PHP (php)
{
    "Versions": [
        {
            "VersionId": "652c5a16-bc3a-7ec3-48fb-a46b232742d5",
            "VersionStages": [
                "AWSCURRENT"
            ],
            "CreatedDate": "2024-01-31T13:50:36.417000-07:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        }
    ],
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password-RR3paj",
    "Name": "sm-enumerate-password"
}

Code language: JSON / JSON with Comments (json)

Repeating the command for the second secret:

aws secretsmanager list-secret-version-ids --secret-id <value>
Code language: HTML, XML (xml)
{
    "Versions": [
        {
            "VersionId": "4db98b6b-a7e9-86f8-0d42-1f684d01bc67",
            "VersionStages": [
                "AWSCURRENT"
            ],
            "CreatedDate": "2024-01-31T13:50:36.347000-07:00",
            "KmsKeyIds": [
                "DefaultEncryptionKey"
            ]
        }
    ],
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-api-key-rxnVJD",
    "Name": "sm-enumerate-api-key"
}

Code language: JSON / JSON with Comments (json)

Here we can see that there is only one version of both secrets.

We also get back information about KmsKeyIds, by the way, which we won’t go into detail for this lab…but KMS is Amazon’s Key Manager Service which is what gets used to encrypt secrets in Secrets Manager.

Next, let’s check to see what resource policy is associated with the secrets:

aws secretsmanager get-resource-policy --secret-id sm-enumerate-password
Code language: JavaScript (javascript)
{
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password-RR3paj",
    "Name": "sm-enumerate-password"
}

Code language: JSON / JSON with Comments (json)

Repeating for the other secret:

aws secretsmanager get-resource-policy --secret-id sm-enumerate-api-key
Code language: JavaScript (javascript)
{
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-api-key-rxnVJD",
    "Name": "sm-enumerate-api-key"
}

Code language: JSON / JSON with Comments (json)

We don’t see a policy here which means that whoever created these keys did not set up permissions policies. They are optional, but they’re usually recommended as an extra layer of security.

We now have a fairly complete picture of a) what our permissions are in relations to secrets stored in Secrets Manager, and b) who or what is allowed to access these secrets based on the permissions policy (which don’t exist in this case).

There doesn’t appear to be anything blocking us from retrieving these secrets, so let’s do that!

We could use describe-secret:

aws secretsmanager describe-secret --secret-id sm-enumerate-password

{
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password-RR3paj",
    "Name": "sm-enumerate-password",
    "Description": "Secret containing a password",
    "LastChangedDate": "2024-01-31T13:50:36.422000-07:00",
    "Tags": [
        {
            "Key": "aws:cloudformation:stack-name",
            "Value": "sm-enumerate"
        },
        {
            "Key": "aws:cloudformation:logical-id",
            "Value": "FlagSecret"
        },
        {
            "Key": "aws:cloudformation:stack-id",
            "Value": "arn:aws:cloudformation:us-east-1:921234892411:stack/sm-enumerate/60249f60-c07a-11ee-89d7-0e2c4e8725db"
        }
    ],
    "VersionIdsToStages": {
        "652c5a16-bc3a-7ec3-48fb-a46b232742d5": [
            "AWSCURRENT"
        ]
    },
    "CreatedDate": "2024-01-31T13:50:36.378000-07:00"
}

Code language: JavaScript (javascript)

But this command only retrieves the details of a secret, not the encrypted secret value. This can still give us valuable information, but we want the actual secret value.

To get that, let’s use get-secret-value:

Couple of things to note:

  • To run this command successfully, you must have secretsmanager:GetSecretValue permissions (which we do)
  • This retrieves the contents of the encrypted fields either as a SecretString or SecretBinary depending on how it’s stored

As you can see from issuing this command, we get this result back:

aws secretsmanager get-secret-value --secret-id sm-enumerate-password
{
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password-RR3paj",
    "Name": "sm-enumerate-password",
    "VersionId": "652c5a16-bc3a-7ec3-48fb-a46b232742d5",
    **"SecretString": "{\\"password\\": \\"redacted...complete the lab to find out what the password is ;)\\"}",**
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2024-01-31T13:50:36.417000-07:00"
}

Code language: JavaScript (javascript)

That contains the secret string, which in this case is a password!

Let’s re-run for the other secret:

aws secretsmanager get-secret-value --secret-id sm-enumerate-api-key 

{
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-api-key-rxnVJD",
    "Name": "sm-enumerate-api-key",
    "VersionId": "4db98b6b-a7e9-86f8-0d42-1f684d01bc67",
    "SecretString": "{\\"secret-api-key\\": \\"redacted...complete the lab to find out what the password is ;)\\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2024-01-31T13:50:36.347000-07:00"
}

Code language: JavaScript (javascript)

This time, it looks like we have an API key, but the key is a jumble of text, which indicates some sort of encoding.

Encoding/Decoding is a topic we’ll reserve for another day but there are plenty of online free tools you can use to help, including this website: https://www.base64decode.org/.

Simply paste in the string, click on Decode, and there you go! It won’t always be this simple, but again, topic for another day.

I’ll let you discover the API secret on your own instead of decoding it here just for fun…

Conclusion & More Resources

But Et voila! We have successfully enumerated information and extracted secrets stored in this account’s Secrets Manager service.

Feel free to keep playing around with this lab environment if you’d like, and check out our channel on YouTube for more content like this, and also our AWS security courses. See you in our next walkthrough!

Related Articles

Responses

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.