A systematic analysis method after obtaining AWS policy files (IAM Policy, Resource Policy, Lambda code, etc.). Core objectives:Derive the attack surface from policies rather than blindly enumerating。
⛔ In-depth reference (required reading)
- S3 policy analysis + common vulnerability patterns → references/s3-attack-techniques.md
- Lambda/API Gateway/SNS resource policy vulnerability patterns → references/aws-resource-policy-exploits.md
Core principles
- Policy files first — When you obtain an IAM Policy / source code / CloudFormation template,analyze it first, do not blindly enumerate first
- Derive the attack surface from policies — Policies tell you "what is allowed"; the attack surface lies at "the boundary of what is allowed"
- Principal is the entry point —
"Principal": "*"means cross-account/anonymous access, and is the highest-priority check item - Conditions may be bypassed —
StringLikewildcards have different meanings in different protocols/contexts - Trust relationships > individual permissions — Focus on the trust chain between services (who can invoke whom, who can pass a role to whom)
Step 1: Rapid classification of policy files
After obtaining attachments/downloaded files, classify them first:
| File type | Identification method | Focus points |
|---|---|---|
| IAM Policy | "Version": "2012-10-17", "Statement" |
Action/Resource scope |
| Resource Policy | Same as above, but with the Principal field |
Who can access, condition restrictions |
| Lambda code | .py/.js files,handler(event, context) |
Input handling, path concatenation, injection points |
| CloudFormation | AWSTemplateFormatVersion, Resources |
Full architecture, role bindings |
| Trust Policy | "Action": "sts:AssumeRole" |
Who can assume the role |
Step 2: IAM Policy dangerous pattern identification
2.1 Check Principal
🔴 "Principal": "*" → 任何 AWS 身份(含匿名)可访问
🔴 "Principal": {"AWS": "*"} → 同上
🟡 "Principal": {"Service": "lambda.amazonaws.com"} → 特定服务可调用
🟢 "Principal": {"AWS": "arn:aws:iam::123456:root"} → 限定账户
2.2 Check Action scope
| Action pattern | Risk |
|---|---|
"Action": "*" |
🔴 Full control |
"Action": "s3:*" |
🔴 Full S3 control |
"Action": ["s3:GetObject", "s3:PutObject"] |
🟡 Readable and writable |
"Action": "s3:GetObject" on "Resource": "*" |
🟡 Can read all Buckets |
"Action": "sts:AssumeRole" |
🟡 Can switch roles (privilege escalation entry point) |
"Action": "iam:PassRole" |
🟡 Can pass roles (indirect privilege escalation) |
"Action": "lambda:InvokeFunction" with Principal:* |
🔴 Anyone can invoke Lambda |
2.3 Check Resource scope
🔴 "Resource": "*" → 所有资源
🟡 "Resource": "arn:aws:s3:::bucket/*" → bucket 内所有对象
🟢 "Resource": "arn:aws:s3:::bucket/public/*" → 仅 public 前缀
2.4 Check Condition bypass
// StringLike 通配符 — 不同上下文含义不同
"Condition": {"StringLike": {"sns:Endpoint": "*@company.com"}}
// email 协议: Endpoint = 邮箱 → 必须是 xxx@company.com
// https 协议: Endpoint = URL → URL 中包含 @company.com 即可绕过
// IpAddress 条件 — 可能有 VPN/代理绕过
"Condition": {"IpAddress": {"aws:SourceIp": "10.0.0.0/8"}}
// StringEquals vs StringLike — 前者精确匹配,后者支持通配符
Step 3: Derive the service trust relationship graph
Draw the "who trusts whom" invocation relationships from the policy files:
读取所有策略文件
↓
识别所有 Principal(谁是调用者)
↓
识别所有 Resource(谁被访问)
↓
连线: Principal → Action → Resource
↓
找到最弱一环(Principal:* 或过宽权限的边)
Common service relationships:
- API Gateway → Lambda (API GW triggers Lambda)
- Lambda → S3/DynamoDB/SNS (Lambda execution role permissions)
- SNS → Lambda/SQS/HTTP (message push targets)
- IAM User → AssumeRole → High-privilege role
Key: Analyze the permissions of the Lambda Execution Role — this determines what resources Lambda can access.
Step 4: Lambda / application code audit
After obtaining Lambda code (handler.py/index.js), focus on checking:
| Vulnerability type | Code pattern | Exploitation Methods |
|---|---|---|
| Path Traversal | os.path.join(prefix, user_input) |
Absolute Path Bypass:/flag |
| Command Injection | os.system(f"cmd {user_input}") |
; cat /flag |
| SSRF | requests.get(user_input) |
http://169.254.169.254/... |
| Environment Variable Leakage | os.environ['SECRET'] |
Error Messages/Stack Trace |
| SQL Injection | String Concatenation SQL | ' OR 1=1 -- |
| Deserialization | pickle.loads()/yaml.load() |
Constructing Malicious Objects |
Step 5: AWS Service Endpoint Discovery
# 从目标页面提取 AWS 相关 URL
curl -s TARGET_URL | grep -oE 'https?://[a-z0-9.-]+\.amazonaws\.com[^"]*'
curl -s TARGET_URL | grep -oE 'https?://[a-z0-9]+\.execute-api\.[a-z0-9-]+\.amazonaws\.com[^"]*'
# 从 JS/HTML 中提取 S3 Bucket、API GW URL
curl -s TARGET_URL | grep -oE 's3\.amazonaws\.com/[^"]*'
# Presigned URL 信息泄露
# X-Amz-Credential 包含 AccessKeyId 和 Region
Step 6: Common Auxiliary Tools
# webhook.site — 接收 AWS 服务回调(SNS、S3 Event 等)
# 当需要外部 Endpoint 接收 AWS 推送时使用
# AWS CLI 策略检查
aws iam get-policy-version --policy-arn ARN --version-id v1
aws s3api get-bucket-policy --bucket BUCKET
aws lambda get-policy --function-name FUNC
# ScoutSuite — AWS 安全配置审计
# Prowler — AWS 安全基线检查
⚠️ Mistakes to Avoid
- Do not enumerate blindly — After 3 consecutive AccessDenied/404 responses, you should stop and re-analyze the policy
- Do not ignore attachments — The policy files in the attachments contain all the information needed to solve the challenge
- Do not assume a fixed attack chain — Each scenario has different service combinations and vulnerability points; start from policy analysis rather than applying a template
- Do not ignore the Condition field — Many policies that appear secure can have their Condition bypassed