This free lab provides you with an environment to practice enumerating Amazon’s Secrets Manager service if you’d like to get familiar with the process and warm up before diving into the CTF labs.
If you’re already fairly familiar with Amazon Secrets Manager, feel free to poke around on your own or even skip this lab entirely. If you’re not, then below is a sequence of commands that we recommend you go through to learn and familiarize yourself with what they do and how to effectively gather information, and ultimately, try to find vulnerabilities that enable you to retrieve secrets stored.
In the next lesson is a compiled list of Secrets Manager CLI enumeration commands that will be very useful throughout this course, so keep a handy copy 🙂
About Secrets manager
Secrets Manager is an AWS service that lets you encrypt and store secrets that you can then use for all kinds of purposes, including for your applications, APIs, Lambda functions, etc…You can use it to store login credentials, API keys, or really any secret value you need to use but don’t want to hardcode since you’re trying to follow security best practices.
It encrypts data as you store it using KMS, then decrypts it when you retrieve it. It also supports automatically and periodically rotating your secrets without breaking your apps, and it enables you to control exactly who or what can access your secrets.
Getting started
First things first, launch the lab (if you haven’t already). This lab should only take about 1 minute or to launch since we’re spinning up new resources just for you. Once it’s launched, you’ll get back an access key ID and a secret access key.
AWS Access Keys
To use these access keys, open up your terminal and type in:
aws configure [--profile <NAME>]
Code language: HTML, XML (xml)
The brackets around [--profile <NAME>]
(and any other command in this course or AWS documentation) means that it’s optional.
…and then input the AWS credentials:
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
Wait, but I thought this was about Secrets Manager and not IAM?!
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).
Think of this as really good practice for the rest of this course because you’ll be issuing these commands a lot…and actually on that note, if you’re the adventurous type and you love automation, try to think of ways to automate some of this ;))
Let’s start with a very common command used by AWS professionals and attackers:
aws sts get-caller-identity
Code language: JavaScript (javascript)
(Remember to issue the --profile name
if you used a profile, like this:)
aws sts get-caller-identity --profile enumerate
Code language: JavaScript (javascript)
(Otherwise it won’t work, or worse, it will use different credentials and return wrong results!)
I will leave off the profile option going forward for these examples.
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)
(Your username and policy names, etc… will be longer than the examples I provide in this walkthrough. I’ve shortened them to reduce noise, but this is totally normal.)
Ok, so we know 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 (only use 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 ones:
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, we don’t have any other policies (like managed policies) or groups. 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.
Ok, so first things first, we need to:
- 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)
- 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)
Couple of things:
- To issue this command, you must have
secretsmanager:ListSecrets
access (which we do) - This command is eventually consistent, which means it might not show changes from the last five minutes. Not really important for enumeration but could impact your day-to-day operations, so just an FYI
From this command, we can see that we have a couple of results:
{
"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",
...REDACTED...
},
{
"ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:sm-enumerate-password-RR3paj",
"Name": "sm-enumerate-password",
"Description": "Secret containing a password",
...REDACTED...
}
]
}
Code language: JavaScript (javascript)
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
orSecretBinary
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\\": \\"cybr-labs-are-super-fun-2211\\"}",**
"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\\": \\"Y3lici1sYWJzLWZha2UtYXBpLWtleS0xMTIy\\"}",
"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.
We now have our decoded API key (which I’ll let you discover on your own instead of pasting it here ;))
Conclusion
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 once you’re ready, go ahead and complete this lesson, and check out the next lesson which gives you the above commands in a reference-able format.
Responses