Experience the Danger of the Mysterious Metadata Service v1

Today we learn how IAM roles work with instances, and how an older (and widely used) essential mechanism can be easily exploited.

Prerequisites

  • Ideally have completed our other labs, but this one largely stands alone.

The Lesson

Ever want to understand the mechanism of the big Capitol One breach? Not the entire break (read that linked post for those details) but how an attacker could steal the IAM role credentials from an exposed instance? Then today’s your lucky day!

Our last lab explored static access keys inside an instance’s configuration files. But you may recall that in a number of labs we have been using IAM roles instead, and I told you that IAM roles are temporary credentials which AWS manages. This makes life harder for attackers, because the credentials only last as long as the session. Now it’s time to learn just how the heck that happens.

Roles came a long time after those pesky static access keys. AWS realized it needed a more secure way to handle credentials, since the very concept of access keys — originally created just for API calls using the root account — doesn’t scale securely. But all the APIs rely on access key cryptography, and AWS didn’t really want to completely break how things worked (they leave that to Microsoft) so instead of replacing them, they enhanced them.

When you assume a role for a session (or your instance does it for you automatically), AWS provides an access key, a secret key, and… a security token. All the API calls need all three elements, which are issued by something called the Security Token Service (STS). Wait, didn’t we see that in our IAM policies when we first created roles? That little sts:AssumeRole permission? Yes, we sure did!

When you make an API call to assume a role — meaning you are creating a session and asking to use the permissions assigned that role — sts returns an access key, secret access key, and session token good for the life of the session (they usually default to 1 hour, but can last longer or shorter). You then use those to make API calls instead of just an access and secret key alone. It’s more secure, since once the session expires the sts-issued access key/secret key/token no longer work. Want to see what these look like? In your Identity Center sign-in portal you can click Access Keys instead of the console link, and it will look like this:

How Instances Use Roles: Profiles and the Metadata Service

The example above show how you, an IAM Identity Center user, can access temporary role credentials. Did you notice the access key started with an ASIA instead of that evil AKIA? That’s the sign of the Security Token Service at work.

When we create a role in the IAM part of the console, we have the option to choose whether it will be used by instances. If we select that it creates the role, allows the EC2 service to assume the role, and creates something called an Instance Profile. The profile serves as a container for the IAM role, and acts as a bridge between the role and the EC2 instance. When you launch an EC2 instance you can specify an instance profile to associate with it (such as SSMClient). This profile contains the IAM role for the instance to assume.

There’s one more piece we need to make this work, the Instance Metadata Service (IMDS). his is a special little connection via the hypervisor which an instance can query for information about itself. At a basic level this is how an instance figures out its IP address, Instance ID, or other important information. And since I’m bad at plot development, you already figured out that the IMDS is the thingy that talks to the IAM instance profile — which calls STS and holds the access/secret keys and token for the instance.

Your app or command line asks the metadata service for credentials. If there is an instance profile it assumes the role, and gets the access/secret keys and token from the security token service. They are then available from the metadata service. Last time I checked the default session length for this was 6 hours, and then credentials were rotated. The process looks like this:

IMDS Version 1 vs. Version 2

That’s all cool, but how could this lead to the Capital One breach?

At the time of the breach the metadata service had a weakness that was relatively well known by attackers. All they needed to do to extract information was to hit the url http://169.254.169.254/latest/meta-data/iam/security-credentials/SSMClient.

(If you didn’t know the role name you could also get that with a single URL). So what’s the problem? Well there is a kind of attack known as Server Side Request Forgery (SSRF), to which a lot of software is vulnerable. In an SSRF attack the attacker enters something like that URL into an input field, and tricks a web server into accessing the URL and returning all its data. Don’t worry — we’ll check it out in a future lab, but the TL;DR is that you can just paste some URLs into inputs to get all their juicy metadata without any real effort.

The access/secret keys and token? They work from anywhere. Like, including your laptop.

IMDSv2 fixes this flaw by adding some complexity to the process so blindly requesting a single URL won’t return the data. You’ll get to see both in this lab. Keep in mind that if an attacker can actually log into the instance and work natively with the command line they can still get the data. IMDSv2 is about stopping SSRF — not all possible attacks.

Key Lesson Points

  • When you assign a role to be usable by EC2 it creates something called an instance profile, which is how the instance can connect to and use the role. The profile handles assuming the role.

  • Instances can get information on themselves using something called the Instance Metadata Service.

  • Version 1 of the IMDS is easy to exploit if the instance has a Server Side Request Forgery (SSRF) vulnerability. An attacker can trick the instance into showing its IAM credentials.

The Lab

For this lab we’ll launch a CloudFormation template which creates an instance locked to the IMDSv2, which is currently the default behavior (finally). Then we will launch an instance using version 1 and log in with Session Manager to see the differences between the two. Especially how easy it is to steal credentials with IMDSv1.

Video Walkthrough

Step by Step

We’ll use our usual starting sequence these days. Log into your sign-in portal, then TestAccount1 > AdministratorAccess > CloudFormation. Launch a stack with this template and name it IMDS:

As usual, give that a few minutes to fully launch, then head over to EC2 > Launch instance:

Name it IMDSv1 and choose the default Amazon Linux:

Choose Proceed without a key pair, then in Network settings Select existing security group and go with default:

We have more Advanced details this time. First pick the SSMClient IAM instance profile. Cool, now you know what that is!!!

Keep scrolling down so to select IMDSv1. Then click the dropdown for Metadata version > V1 and V2 (token optional). Notice the warning?

Now click Launch instance and wait about 3 minutes for it to fully run and pass the static checks.

We’ll start with IMDSv1. Go ahead and Connect > Session manager > Connect (less screenshots — you know this):

Okay. Command line time!

If you don’t know, curl is a command in Linux to access a URL. when you curl a website, you get all the raw text from that location. We will curl the metadata service and see what we get. First we need to figure out the name of our instance profile (role). We can do that with this command by using curl on the fixed address of the metadata service, which is 169.254.169.245, and then a path to get the instance profile name. Go ahead and copy and paste it in:

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

You’ll see SSMClient returned:

In an SSRF attack the adversary just needs to find a vulnerable form field and send whatever text is needed to trick the instance into grabbing that same data from the metadata service. Next we’ll ask the metadata service for the current SSMClient credentials:

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/SSMClient

Well, that was easy. These credentials now work from anywhere, including your own laptop!

This is the risk of IMDSv1. Two simple command lines: one to get the name, the other to get the credentials. And you don’t need to be logged into the console to pull this off if the instance has an SSRF vulnerability.

Version 2 is much more secure. Let’s see how.

Terminate your connection to IMDSv1 and then Connect to IMDSv2. Once logged in we’ll us three different command lines to see the differences between IMDS versions. Go ahead and copy and paste these commands all in a row. We will:

  • Request a token from IMDSv2. This token is a required first step; the metadata service will issue it to the instance, and also bind it to the instance so it can’t be used anywhere else. Our command line sets this as a variable named TOKEN.

  • Get the role name (instance profile) by setting the token as a header in the curl command, then and only then connecting to the same URL. That’s how this works: every request in IMDSv2 requires the token — which is unique to the instance — to be sent as a header. This also isn’t something you can do with most SSRF vulnerabilities.

  • Obtain the access/secret keys and token using the same technique.

TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ROLE_NAME=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" "http://169.254.169.254/latest/meta-data/iam/security-credentials/")
curl -H "X-aws-ec2-metadata-token: $TOKEN" "http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME"

In my example I first try the old way and it doesn’t work. Then I use those three command lines.

This may not seem like much, but that extra little speed bump is enough to break SSRF, a very common attack. Requiring the token and then setting it in the header means the instance can still get its credentials, but in a way that defends against SSRF.

This was exactly how part of the Capital One breach happened. Had IMDSv2 been available to customers (it wasn’t at the time) and Capital One used it, the attacker would have been stopped in her tracks.

Lab Key Points

  • IMDSv1 is vulnerable to SSRF attacks, but v2 is not.

  • You can use curl to talk to both versions of the metadata service, but version 2 requires you to first get a token and then set it as a header.

  • That token will not work with any other instance.

-Rich

Reply

or to participate.