8 phút đọc
Insights /

IMDSv1

Từ SSRF đến Cloud Breach: Cơ chế khai thác IMDSv1 và Bảo mật chủ động

Nguyễn Trung Hưng
Đăng ngày 21/08/2026 Senior DevOps Engineer
Từ SSRF đến Cloud Breach: Cơ chế khai thác IMDSv1 và Bảo mật chủ động

Mỗi khi review hạ tầng, thấy ứng dụng không lưu bất kỳ Access Key tĩnh nào trong code hay file .env mà gắn thẳng IAM Role cho EC2/ECS, có thể anh em hay nghĩ: hệ thống thế này là chuẩn và an tâm rồi

Cơ bản thì không sai. Nhưng khi gặp issue tôi mới biết nó mới chỉ giải quyết được một nửa bài toán: không để lộ static credentials trong code và config. Nó không tự động bảo vệ cơ chế cấp phát temporary token từ Metadata Service bên dưới.

Tính ra nhiều lúc học thi chứng chỉ cũng rất hữu ích đặc biệt là dùng cloud nhà nào thì nghiên cứu chứng chỉ nhà đó 😀

Nếu ứng dụng có các tính năng xử lý URL bên ngoài như:

  • Nhập URL để tải ảnh đại diện / tệp tin
  • Tạo link preview (metadata scraper)
  • Gửi webhook test hoặc web proxy nội bộ

Thì một lỗ hổng SSRF (Server-Side Request Forgery) có thể ép chính server gọi vào endpoint metadata cục bộ của EC2. Không cần RCE, không cần SSH, không cần đọc file .env. Nếu role gắn trên instance có quyền rộng, một lỗi web nhỏ sẽ biến thành Cloud Credential Exposure.

Lỗ hổng fetch URL bị khai thác

Không show được code dự án nhưng tôi giả sử bản chất nhé, backend có đoạn xử lý:

@app.route("/api/v1/fetch-avatar", methods=["POST"])
def fetch_avatar():
    image_url = request.json.get("url")
    response = requests.get(image_url, timeout=5)
    return response.content

Bình thường người dùng gửi:

https://example.com/avatar.jpg

Attacker khai thác SSRF bằng cách gửi:

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

Nếu instance còn bật IMDSv1, server sẽ gọi endpoint metadata thay cho attacker và trả về tên role:

web-production-ec2-role

Attacker tiếp tục gửi payload thứ hai:

http://169.254.169.254/latest/meta-data/iam/security-credentials/web-production-ec2-role

Kết quả trả về chính là temporary credential của IAM Role:

{
  "Code": "Success",
  "AccessKeyId": "ASIA...",
  "SecretAccessKey": "...",
  "Token": "...",
  "Expiration": "2026-08-21T14:45:00Z"
}

Attacker chỉ cần nạp credential này vào AWS CLI máy cá nhân:

export AWS_ACCESS_KEY_ID="ASIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."

aws sts get-caller-identity

Blast radius lúc này phụ thuộc vào quyền của role. Nếu role có AdministratorAccess, quyền đọc S3 bucket nhạy cảm, Secrets Manager hoặc SSM Parameter Store, chính thức toàn bộ hạ tầng Cloud trước mắt kẻ tấn công đã rõ như lòng bàn tay :))

Vì sao IMDSv1 nguy hiểm?

169.254.169.254 là địa chỉ link-local. Chỉ workload chạy trực tiếp trên EC2 instance mới kết nối được. Attacker bên ngoài không thể gọi trực tiếp IMDS, nhưng với SSRF, request lại xuất phát từ chính hệ điều hành của server.

Với IMDSv1, việc lấy token chỉ cần một HTTP GET đơn giản:

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

Không cần header xác thực, không cần phiên làm việc. Ngoài IPv4, AWS Nitro instances trong subnet IPv6 còn hỗ trợ endpoint [fd00:ec2::254]. Khi phân tích rủi ro, cần tính cả hai dải IP này.

IMDSv2 giúp gì và không giúp gì?

Khi cấu hình HttpTokens=required, IMDSv2 bắt buộc quy trình lấy metadata phải qua 2 bước:

1. Xin Session Token (bắt buộc dùng PUT và header riêng):
   PUT /latest/api/token
   Header: X-aws-ec2-metadata-token-ttl-seconds: 21600

2. Đọc metadata kèm token:
   GET /latest/meta-data/...
   Header: X-aws-ec2-metadata-token: 
<token>

Phần lớn lỗi SSRF cơ bản chỉ cho phép attacker điều khiển URL mục tiêu với method GET. Attacker không thể ép backend gửi request PUT kèm custom header X-aws-ec2-metadata-token-ttl-seconds, do đó request lấy metadata trực tiếp sẽ bị chặn:

HTTP/1.1 401 Unauthorized

Lưu ý: IMDSv2 là cơ chế defense-in-depth, không thay thế việc vá SSRF ở tầng application. Nếu ứng dụng có tính năng forward HTTP request tùy biến hoàn toàn (cho phép custom header, method PUT, hoặc cho phép attacker điều khiển full HTTP client), rủi ro bypass vẫn tồn tại.

Cấu hình Hop Limit chính xác

HttpPutResponseHopLimit quy định số network hop tối đa mà response chứa token IMDSv2 được phép đi qua.

Kiểm tra cấu hình hiện tại, tôi ví dụ kiểu này:

aws ec2 describe-instances \
  --instance-ids i-0123456789abcdef0 \
  --query "Reservations[*].Instances[*].[InstanceId,MetadataOptions.HttpTokens,MetadataOptions.HttpPutResponseHopLimit]" \
  --output table

Cấu hình Hop Limit chuẩn theo từng mô hình hạ tầng:

Môi trường Cấu hình đề xuất Lý do kỹ thuật
EC2 chạy app trực tiếp (Monolith/Systemd) HttpTokens=required, Hop Limit = 1 Request đi trực tiếp từ OS host đến hypervisor (0 hop phụ), an toàn nhất.
EC2 host chạy Docker/Container cần IMDS HttpTokens=required, Hop Limit = 2 Packet từ Container qua bridge network (docker0) vào host mất 1 hop. Hop limit = 1 sẽ khiến container bị timeout/403 khi lấy token.
EKS Workload dùng IRSA / Pod Identity Hop Limit = 1 trên Node Group Ép pod không thể lấy IAM Role của EC2 Node bên dưới; pod bắt buộc phải dùng Service Account Role riêng.
ECS Workloads Hop Limit = 1 hoặc chặn IMDS qua iptables Ép task dùng ECS Task Role (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI), tránh việc container dùng role của EC2 instance profile.

Hardening ở tầng AWS

Tương tự tôi ví dụ để anh em có thể dễ hiểu chứ không có config nào như dưới copy-paste nhé. Thiết lập IMDSv2 mặc định cho toàn bộ instance mới tạo trong AWS Region:

aws ec2 modify-instance-metadata-defaults \
  --http-tokens required \
  --http-put-response-hop-limit 1

Cập nhật cho instance đang chạy:

# Cho EC2 standalone hoặc EKS node (dùng IRSA)
aws ec2 modify-instance-metadata-options \
  --instance-id i-0123456789abcdef0 \
  --http-tokens required \
  --http-endpoint enabled \
  --http-put-response-hop-limit 1

Khai báo chuẩn trong Terraform Launch Template:

resource "aws_launch_template" "app" {
  name_prefix   = "app-production-"
  image_id      = "ami-0123456789abcdef0"
  instance_type = "t3.medium"

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
    instance_metadata_tags      = "disabled"
  }
}

Ở cấp Organization, áp dụng Service Control Policy (SCP) để ngăn chặn việc tạo EC2 bỏ qua IMDSv2:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EnforceIMDSv2",
      "Effect": "Deny",
      "Action": "ec2:RunInstances",
      "Resource": "arn:aws:ec2:*:*:instance/*",
      "Condition": {
        "StringNotEquals": {
          "ec2:MetadataHttpTokens": "required"
        }
      }
    }
  ]
}

Xử lý SSRF triệt để ở tầng Application & Network

Bảo vệ IMDS không loại bỏ được việc attacker SSRF vào các tài nguyên nội bộ khác (Database, Redis, Internal API). Cần áp dụng quy chuẩn xử lý URL:

  • DNS Resolution & IP Validation: Trước khi gửi request, phân giải domain ra IP. Drop request nếu IP thuộc dải link-local (169.254.0.0/16), loopback (127.0.0.0/8), private (RFC1918: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) hoặc IPv6 Link-local (fe80::/10), Unique Local (fc00::/7).
  • Chống DNS Rebinding: Validate IP sau khi resolve và kết nối trực tiếp tới IP đã validate thay vì để thư viện HTTP tự resolve lại lần hai.
  • Tắt tính năng Follow Redirect: Nếu cần follow redirect, mỗi redirect URL đều phải chạy lại toàn bộ quy trình validate IP.
  • Kiểm soát Egress mạng: Sử dụng security group hoặc network firewall chặn outbound traffic tới metadata IP từ các subnet/container không có nhu cầu.

Kịch bản ứng phó sự cố (Incident Response)

Nếu phát hiện credential của instance bị leak:

  1. Thu hồi hiệu lực credential ngay: Temporary token của EC2 role có thời hạn mặc định lên đến 6 giờ. Attacker vẫn có thể sử dụng token đã lấy cho đến khi hết hạn dù bạn đã tắt IMDS.
  2. Truy vết CloudTrail: Tìm kiếm theo accessKeyId (chuỗi bắt đầu bằng ASIA...) để thống kê toàn bộ API đã bị gọi, nguồn IP bên ngoài và các tài nguyên đã bị truy cập.
  3. Kiểm tra AWS GuardDuty: Rà soát các finding thuộc nhóm UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS.
  4. Rotate Secrets: Đổi secret key/password trên Secrets Manager, RDS, SSM Parameter Store nếu role bị lộ có quyền truy cập các dịch vụ này.

Tổng kết

IAM Role vẫn là hướng đúng. Nhưng IAM Role không tự làm hệ thống an toàn nếu app có SSRF và metadata endpoint chưa được bảo vệ.

Theo tôi thì bảo mật hạ tầng cloud sẽ tuân thủ kiến trúc phòng thủ theo 4 lớp đồng bộ: Instance (bắt buộc IMDSv2), Container (Hop Limit và Task Roles), IAM (Least Privilege và Session Invalidation), Application (Strict URL validation).

Khi review kiến trúc, câu hỏi đúng không chỉ là Hệ thống đã dùng IAM Role chưa?, mà là: Nếu ứng dụng dính SSRF, temporary token có thể bị lấy hay không, và lớp nào sẽ ngăn chặn nó?

Nếu anh em muốn tìm hiểu sâu hơn tôi rất recommend kiến thức trong khóa khá nhiều thứ đáng học.

Chia sẻ bài viết

Theo dõi
Thông báo của
0 Góp ý
Được bỏ phiếu nhiều nhất
Mới nhất Cũ nhất
Đã sao chép liên kết vào bộ nhớ tạm!