Skip to content

Commit b0d0266

Browse files
committed
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks-cloud
2 parents d56be2b + 92e9580 commit b0d0266

File tree

18 files changed

+875
-18
lines changed

18 files changed

+875
-18
lines changed

src/SUMMARY.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
- [Atlantis Security](pentesting-ci-cd/atlantis-security.md)
4242
- [Cloudflare Security](pentesting-ci-cd/cloudflare-security/README.md)
4343
- [Cloudflare Domains](pentesting-ci-cd/cloudflare-security/cloudflare-domains.md)
44+
- [Cloudflare Workers Pass Through Proxy Ip Rotation](pentesting-ci-cd/cloudflare-security/cloudflare-workers-pass-through-proxy-ip-rotation.md)
4445
- [Cloudflare Zero Trust Network](pentesting-ci-cd/cloudflare-security/cloudflare-zero-trust-network.md)
4546
- [Okta Security](pentesting-ci-cd/okta-security/README.md)
4647
- [Okta Hardening](pentesting-ci-cd/okta-security/okta-hardening.md)
@@ -303,6 +304,7 @@
303304
- [AWS - Apigateway Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apigateway-privesc/README.md)
304305
- [AWS - AppRunner Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apprunner-privesc/README.md)
305306
- [AWS - Chime Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-chime-privesc/README.md)
307+
- [AWS - CloudFront](pentesting-cloud/aws-security/aws-privilege-escalation/aws-cloudfront-privesc/README.md)
306308
- [AWS - Codebuild Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codebuild-privesc/README.md)
307309
- [AWS - Codepipeline Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codepipeline-privesc/README.md)
308310
- [AWS - Codestar Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codestar-privesc/README.md)
@@ -574,3 +576,6 @@
574576

575577
- [HackTricks Pentesting Network$$external:https://book.hacktricks.wiki/en/generic-methodologies-and-resources/pentesting-network/index.html$$]()
576578
- [HackTricks Pentesting Services$$external:https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-ssh.html$$]()
579+
580+
- [Feature Store Poisoning](pentesting-cloud/aws-security/aws-post-exploitation/aws-sagemaker-post-exploitation/feature-store-poisoning.md)
581+
- [Aws Sqs Dlq Redrive Exfiltration](pentesting-cloud/aws-security/aws-post-exploitation/aws-sqs-dlq-redrive-exfiltration.md)

src/pentesting-ci-cd/cloudflare-security/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ On each Cloudflare's worker check:
5454
> [!WARNING]
5555
> Note that by default a **Worker is given a URL** such as `<worker-name>.<account>.workers.dev`. The user can set it to a **subdomain** but you can always access it with that **original URL** if you know it.
5656
57+
For a practical abuse of Workers as pass-through proxies (IP rotation, FireProx-style), check:
58+
59+
{{#ref}}
60+
cloudflare-workers-pass-through-proxy-ip-rotation.md
61+
{{#endref}}
62+
5763
## R2
5864

5965
On each R2 bucket check:
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
# Abusing Cloudflare Workers as pass-through proxies (IP rotation, FireProx-style)
2+
3+
{{#include ../../banners/hacktricks-training.md}}
4+
5+
Cloudflare Workers can be deployed as transparent HTTP pass-through proxies where the upstream target URL is supplied by the client. Requests egress from Cloudflare's network so the target observes Cloudflare IPs instead of the client's. This mirrors the well-known FireProx technique on AWS API Gateway, but uses Cloudflare Workers.
6+
7+
### Key capabilities
8+
- Support for all HTTP methods (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
9+
- Target can be supplied via query parameter (?url=...), a header (X-Target-URL), or even encoded in the path (e.g., /https://target)
10+
- Headers and body are proxied through with hop-by-hop/header filtering as needed
11+
- Responses are relayed back, preserving status code and most headers
12+
- Optional spoofing of X-Forwarded-For (if the Worker sets it from a user-controlled header)
13+
- Extremely fast/easy rotation by deploying multiple Worker endpoints and fanning out requests
14+
15+
### How it works (flow)
16+
1) Client sends an HTTP request to a Worker URL (`<name>.<account>.workers.dev` or a custom domain route).
17+
2) Worker extracts the target from either a query parameter (?url=...), the X-Target-URL header, or a path segment if implemented.
18+
3) Worker forwards the incoming method, headers, and body to the specified upstream URL (filtering problematic headers).
19+
4) Upstream response is streamed back to the client through Cloudflare; the origin sees Cloudflare egress IPs.
20+
21+
### Worker implementation example
22+
- Reads target URL from query param, header, or path
23+
- Copies a safe subset of headers and forwards the original method/body
24+
- Optionally sets X-Forwarded-For using a user-controlled header (X-My-X-Forwarded-For) or a random IP
25+
- Adds permissive CORS and handles preflight
26+
27+
<details>
28+
<summary>Example Worker (JavaScript) for pass-through proxying</summary>
29+
30+
```javascript
31+
/**
32+
* Minimal Worker pass-through proxy
33+
* - Target URL from ?url=, X-Target-URL, or /https://...
34+
* - Proxies method/headers/body to upstream; relays response
35+
*/
36+
addEventListener('fetch', event => {
37+
event.respondWith(handleRequest(event.request))
38+
})
39+
40+
async function handleRequest(request) {
41+
try {
42+
const url = new URL(request.url)
43+
const targetUrl = getTargetUrl(url, request.headers)
44+
45+
if (!targetUrl) {
46+
return errorJSON('No target URL specified', 400, {
47+
usage: {
48+
query_param: '?url=https://example.com',
49+
header: 'X-Target-URL: https://example.com',
50+
path: '/https://example.com'
51+
}
52+
})
53+
}
54+
55+
let target
56+
try { target = new URL(targetUrl) } catch (e) {
57+
return errorJSON('Invalid target URL', 400, { provided: targetUrl })
58+
}
59+
60+
// Forward original query params except control ones
61+
const passthru = new URLSearchParams()
62+
for (const [k, v] of url.searchParams) {
63+
if (!['url', '_cb', '_t'].includes(k)) passthru.append(k, v)
64+
}
65+
if (passthru.toString()) target.search = passthru.toString()
66+
67+
// Build proxied request
68+
const proxyReq = buildProxyRequest(request, target)
69+
const upstream = await fetch(proxyReq)
70+
71+
return buildProxyResponse(upstream, request.method)
72+
} catch (error) {
73+
return errorJSON('Proxy request failed', 500, {
74+
message: error.message,
75+
timestamp: new Date().toISOString()
76+
})
77+
}
78+
}
79+
80+
function getTargetUrl(url, headers) {
81+
let t = url.searchParams.get('url') || headers.get('X-Target-URL')
82+
if (!t && url.pathname !== '/') {
83+
const p = url.pathname.slice(1)
84+
if (p.startsWith('http')) t = p
85+
}
86+
return t
87+
}
88+
89+
function buildProxyRequest(request, target) {
90+
const h = new Headers()
91+
const allow = [
92+
'accept','accept-language','accept-encoding','authorization',
93+
'cache-control','content-type','origin','referer','user-agent'
94+
]
95+
for (const [k, v] of request.headers) {
96+
if (allow.includes(k.toLowerCase())) h.set(k, v)
97+
}
98+
h.set('Host', target.hostname)
99+
100+
// Optional: spoof X-Forwarded-For if provided
101+
const spoof = request.headers.get('X-My-X-Forwarded-For')
102+
h.set('X-Forwarded-For', spoof || randomIP())
103+
104+
return new Request(target.toString(), {
105+
method: request.method,
106+
headers: h,
107+
body: ['GET','HEAD'].includes(request.method) ? null : request.body
108+
})
109+
}
110+
111+
function buildProxyResponse(resp, method) {
112+
const h = new Headers()
113+
for (const [k, v] of resp.headers) {
114+
if (!['content-encoding','content-length','transfer-encoding'].includes(k.toLowerCase())) {
115+
h.set(k, v)
116+
}
117+
}
118+
// Permissive CORS for tooling convenience
119+
h.set('Access-Control-Allow-Origin', '*')
120+
h.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD')
121+
h.set('Access-Control-Allow-Headers', '*')
122+
123+
if (method === 'OPTIONS') return new Response(null, { status: 204, headers: h })
124+
return new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers: h })
125+
}
126+
127+
function errorJSON(msg, status=400, extra={}) {
128+
return new Response(JSON.stringify({ error: msg, ...extra }), {
129+
status, headers: { 'Content-Type': 'application/json' }
130+
})
131+
}
132+
133+
function randomIP() { return [1,2,3,4].map(() => Math.floor(Math.random()*255)+1).join('.') }
134+
```
135+
136+
</details>
137+
138+
### Automating deployment and rotation with FlareProx
139+
140+
FlareProx is a Python tool that uses the Cloudflare API to deploy many Worker endpoints and rotate across them. This provides FireProx-like IP rotation from Cloudflare’s network.
141+
142+
Setup
143+
1) Create a Cloudflare API Token using the “Edit Cloudflare Workers” template and get your Account ID from the dashboard.
144+
2) Configure FlareProx:
145+
146+
```bash
147+
git clone https://github.com/MrTurvey/flareprox
148+
cd flareprox
149+
pip install -r requirements.txt
150+
```
151+
152+
**Create config file flareprox.json:**
153+
154+
```json
155+
{
156+
"cloudflare": {
157+
"api_token": "your_cloudflare_api_token",
158+
"account_id": "your_cloudflare_account_id"
159+
}
160+
}
161+
```
162+
163+
**CLI usage**
164+
165+
- Create N Worker proxies:
166+
```bash
167+
python3 flareprox.py create --count 2
168+
```
169+
- List endpoints:
170+
```bash
171+
python3 flareprox.py list
172+
```
173+
- Health-test endpoints:
174+
```bash
175+
python3 flareprox.py test
176+
```
177+
- Delete all endpoints:
178+
```bash
179+
python3 flareprox.py cleanup
180+
```
181+
182+
**Routing traffic through a Worker**
183+
- Query parameter form:
184+
```bash
185+
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/ip"
186+
```
187+
- Header form:
188+
```bash
189+
curl -H "X-Target-URL: https://httpbin.org/ip" https://your-worker.account.workers.dev
190+
```
191+
- Path form (if implemented):
192+
```bash
193+
curl https://your-worker.account.workers.dev/https://httpbin.org/ip
194+
```
195+
- Method examples:
196+
```bash
197+
# GET
198+
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/get"
199+
200+
# POST (form)
201+
curl -X POST -d "username=admin" \
202+
"https://your-worker.account.workers.dev?url=https://httpbin.org/post"
203+
204+
# PUT (JSON)
205+
curl -X PUT -d '{"username":"admin"}' -H "Content-Type: application/json" \
206+
"https://your-worker.account.workers.dev?url=https://httpbin.org/put"
207+
208+
# DELETE
209+
curl -X DELETE \
210+
"https://your-worker.account.workers.dev?url=https://httpbin.org/delete"
211+
```
212+
213+
**`X-Forwarded-For` control**
214+
215+
If the Worker honors `X-My-X-Forwarded-For`, you can influence the upstream `X-Forwarded-For` value:
216+
```bash
217+
curl -H "X-My-X-Forwarded-For: 203.0.113.10" \
218+
"https://your-worker.account.workers.dev?url=https://httpbin.org/headers"
219+
```
220+
221+
**Programmatic usage**
222+
223+
Use the FlareProx library to create/list/test endpoints and route requests from Python.
224+
225+
<details>
226+
<summary>Python example: Send a POST via a random Worker endpoint</summary>
227+
228+
```python
229+
#!/usr/bin/env python3
230+
from flareprox import FlareProx, FlareProxError
231+
import json
232+
233+
# Initialize
234+
flareprox = FlareProx(config_file="flareprox.json")
235+
if not flareprox.is_configured:
236+
print("FlareProx not configured. Run: python3 flareprox.py config")
237+
exit(1)
238+
239+
# Ensure endpoints exist
240+
endpoints = flareprox.sync_endpoints()
241+
if not endpoints:
242+
print("Creating proxy endpoints...")
243+
flareprox.create_proxies(count=2)
244+
245+
# Make a POST request through a random endpoint
246+
try:
247+
post_data = json.dumps({
248+
"username": "testuser",
249+
"message": "Hello from FlareProx!",
250+
"timestamp": "2025-01-01T12:00:00Z"
251+
})
252+
253+
headers = {
254+
"Content-Type": "application/json",
255+
"User-Agent": "FlareProx-Client/1.0"
256+
}
257+
258+
response = flareprox.redirect_request(
259+
target_url="https://httpbin.org/post",
260+
method="POST",
261+
headers=headers,
262+
data=post_data
263+
)
264+
265+
if response.status_code == 200:
266+
result = response.json()
267+
print("✓ POST successful via FlareProx")
268+
print(f"Origin IP: {result.get('origin', 'unknown')}")
269+
print(f"Posted data: {result.get('json', {})}")
270+
else:
271+
print(f"Request failed with status: {response.status_code}")
272+
273+
except FlareProxError as e:
274+
print(f"FlareProx error: {e}")
275+
except Exception as e:
276+
print(f"Request error: {e}")
277+
```
278+
279+
</details>
280+
281+
**Burp/Scanner integration**
282+
- Point tooling (for example, Burp Suite) at the Worker URL.
283+
- Supply the real upstream using ?url= or X-Target-URL.
284+
- HTTP semantics (methods/headers/body) are preserved while masking your source IP behind Cloudflare.
285+
286+
**Operational notes and limits**
287+
- Cloudflare Workers Free plan allows roughly 100,000 requests/day per account; use multiple endpoints to distribute traffic if needed.
288+
- Workers run on Cloudflare’s network; many targets will only see Cloudflare IPs/ASN, which can bypass naive IP allow/deny lists or geo heuristics.
289+
- Use responsibly and only with authorization. Respect ToS and robots.txt.
290+
291+
## References
292+
- [FlareProx (Cloudflare Workers pass-through/rotation)](https://github.com/MrTurvey/flareprox)
293+
- [Cloudflare Workers fetch() API](https://developers.cloudflare.com/workers/runtime-apis/fetch/)
294+
- [Cloudflare Workers pricing and free tier](https://developers.cloudflare.com/workers/platform/pricing/)
295+
- [FireProx (AWS API Gateway)](https://github.com/ustayready/fireprox)
296+
297+
{{#include ../../banners/hacktricks-training.md}}

src/pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,54 @@ This is stealthier than exposing a Function URL and doesn’t change the primary
8787
aws-lambda-alias-version-policy-backdoor.md
8888
{{#endref}}
8989

90+
### Freezing AWS Lambda Runtimes
91+
92+
An attacker who has lambda:InvokeFunction, logs:FilterLogEvents, lambda:PutRuntimeManagementConfig, and lambda:GetRuntimeManagementConfig permissions can modify a function’s runtime management configuration. This attack is especially effective when the goal is to keep a Lambda function on a vulnerable runtime version or to preserve compatibility with malicious layers that might be incompatible with newer runtimes.
93+
94+
The attacker modifies the runtime management configuration to pin the runtime version:
95+
96+
```bash
97+
# Invoke the function to generate runtime logs
98+
aws lambda invoke \
99+
--function-name $TARGET_FN \
100+
--payload '{}' \
101+
--region us-east-1 /tmp/ping.json
102+
103+
sleep 5
104+
105+
# Freeze automatic runtime updates on function update
106+
aws lambda put-runtime-management-config \
107+
--function-name $TARGET_FN \
108+
--update-runtime-on FunctionUpdate \
109+
--region us-east-1
110+
```
111+
112+
Verify the applied configuration:
113+
```bash
114+
aws lambda get-runtime-management-config \
115+
--function-name $TARGET_FN \
116+
--region us-east-1
117+
```
118+
119+
Optional: Pin to a specific runtime version
120+
```bash
121+
# Extract Runtime Version ARN from INIT_START logs
122+
RUNTIME_ARN=$(aws logs filter-log-events \
123+
--log-group-name /aws/lambda/$TARGET_FN \
124+
--filter-pattern "INIT_START" \
125+
--query 'events[0].message' \
126+
--output text | grep -o 'Runtime Version ARN: [^,]*' | cut -d' ' -f4)
127+
```
128+
129+
Pin to a specific runtime version:
130+
131+
```bash
132+
aws lambda put-runtime-management-config \
133+
--function-name $TARGET_FN \
134+
--update-runtime-on Manual \
135+
--runtime-version-arn $RUNTIME_ARN \
136+
--region us-east-1
137+
```
90138

91139
{{#include ../../../../banners/hacktricks-training.md}}
92140

0 commit comments

Comments
 (0)