What are these 'reserved' set of security-credentials in AWS?
A quick blog post to investigate what instance-identity
security credentials are that can be generated using the metadata instance on every EC2 instance in AWS, even when no role is attached to the instance.
Introduction
When we attach a role to an EC2 instance, we can generate temporary AWS credentials by querying the instance meta-data endpoint at http://169.254.169.254/latest/meta-data/iam/security-credentials/role_name
. This is pretty well known and is used by numerous services and implementations throughout the AWS world. It is also one of the first endpoints that attackers query when a SSRF is discovered on an EC2 hosted web application.
However, in this post, let us try to dig up on the lesser known (and used) endpoint at http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
that is at best vaguely documented by AWS and does provide, what appears to be security credentials that can be used programmatically.
AWS Documentation about the endpoint
If you take a look at https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/instancedata-data-categories.html, which describes instance metadata categories on AWS, you will see that the data column mentions identity-credentials/ec2/security-credentials/ec2-instance
which according to the description is [Reserved for internal use only] The credentials that AWS uses to identify an instance to the rest of the Amazon EC2 infrastructure.
This description is as useful as it gets. So I set about trying to figure out what these ‘reserved’ set of credentials are and what access do they provide if extracted and used.
The Setup (if you want to look at this yourself)
All you need is shell access to an EC2 running on AWS. You can launch a free tier instance on AWS and SSH to it. I’m using an Ubuntu 18.04 machine for the rest of this post.
The following curl command will fetch you the credentials that this metadata endpoint generates (IMDSv1).
curl http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
Analysis of the credentials
From the output, they have the same set of name value pairs as standard role based temporary credentials. The values required to start working with these credentials are AccessKeyId
, SecretAccessKey
and Token
. Make a note of the Expiration
as well, as the credentials will no longer work after that.
Using the credentials with the AWS cli
One of the first things I do when I find random credentials during assessments or otherwise is to create an AWS cli profile and figure out who those credentials belong to. These can be done using the following steps
1.
On a system with aws cli installed, run aws configure --profile ec2id
2.
Manually edit the ~/.aws/credentials
file in your favorite editor and add the token obtained from the curl command, below the secret as shown below
You can also use environment variables to do this as described here - https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
Running the ‘whoami’ of AWS IAM
Using the Security Token Service of AWS, we can identify who these credentials belong to
aws sts get-caller-identity --profile ec2id
For my test setup, I get
{
"UserId": "8953XXXXXXXX:aws:ec2-instance:i-0ab11ba319180ecd4",
"Account": "8953XXXXXXXX",
"Arn": "arn:aws:sts::8953XXXXXXXX:assumed-role/aws:ec2-instance/i-0ab11ba319180ecd4"
}
which tells us that the role name is aws:ec2-instance
. This role name contains characters not allowed by AWS when we try to create a role independently of this exercise
Also, the UserId
is not in the standard naming convention for any of the AWS Principals as per https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable
One key observation is the presence of the instance-id
of the EC2 instance (which is unique across the AWS EC2 infrastructure) from where these credentials were taken. If we look back at the AWS documentation for this endpoint, the description does say
The credentials that AWS uses to identify an instance to the rest of the Amazon EC2 infrastructure
So perhaps that is all these credentials are used for.
Let’s see what some other tools (and API calls) tell us.
Evaluating access using enumerate-iam
Let’s take a look at what kind of access these credentials have. We can use the enumerate-iam
tool by Andres Riancho from Github - https://github.com/andresriancho/enumerate-iam. The tool allows us to enumerate the permissions that a given set of credentials have by bruteforcing get*
and list*
API calls allowed by the IAM policy.
To setup this tool on your system
git clone git@github.com:andresriancho/enumerate-iam.git
cd enumerate-iam/
pip install -r requirements.txt
To run the tool, pass the access-key
, secret-key
and session-token
parameters as shown below
./enumerate-iam.py --access-key ASIA5... --secret-key gXjV8... --session-token IQoJb3...
Running the tool gave no usefule results after running it overnight, except for (weirdly) the ability to query endpoints for DynamoDB - dynamodb.describe_endpoints()
. The awscli equivalent for this is
aws dynamodb describe-endpoints --profile ec2id
Evaluating access using ScoutSuite
Just to ensure coverage, I ran another of my go to tools for AWS security evaluation called ScoutSuite by NCC Group. You can get this from https://github.com/nccgroup/ScoutSuite
Working with this tool is straightforward using docker, instructions for which are available at https://github.com/nccgroup/ScoutSuite/wiki/Docker-Image
Running the docker on the created profile gave slightly different results as seen with the enumerate-iam
tool, but visibly with lots of UnauthorizedOperation
errors.
docker run --rm -t -v /home/user/.aws:/root/.aws:ro -v "$(pwd)/results:/opt/scoutsuite-report" scoutsuite:latest aws --profile ec2id
ScoutSuite’s HTML report showed that only CloudTrail and IAM was accessible using these credentials.
However, a awscli check using the following two equivalent commands showed that the results returned in ScoutSuite were false positives
aws cloudtrail describe-trails --profile ec2id
aws iam get-account-password-policy --profile ec2id
Final thoughts
Turns out the credentials provide no known or documented form of access to the AWS account or any resources. The only programmatic access the credentials seem to have provided are the ability to list DynamoDB endpoints and list token caller info using the Session Token Service (STS), which provides the Instance-id
of the instance from where the token was obtained. It is also worth noting that I only tried out get*
, list*
and describe*
operations using 2 tools. Maybe there is a write API that the token can use?
For now, I will go with AWS on this one and consider that these credentials are truly [Reserved for internal use only]
, unless I find (or anyone else) that the credentials can be used to do something else.
Do let me know if you do find any other API calls that the credentials can successfully use and I will update the post! Till I write again, Happy Hacking!
Bonus Content - Generating Tokens on IMDSv2
For instances with IMDSv2
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
References
- https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/instancedata-data-categories.html
- https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable