
Kestra의 인증되지 않은 RCE인 CVE-2026-53576의 엔드투엔드 재현 및 교차 계층 탐지 — 기본 PoC를 넘어 일반적인 Docker 소켓 오구성이 컨테이너 root를 호스트 전체 장악으로 어떻게 전환시키는지 보여줍니다.
Kestra는 오픈소스 워크플로 오케스트레이션 플랫폼으로, 요청에 자격 증명이 필요한지 여부를 URL이 /configs로 끝나는지 확인하여 결정하는 인증 필터를 배포했습니다. 이 검사는 무해한 공개 엔드포인트 하나를 노출하기 위한 것이었습니다.
이 검사가 문자열의 끝부분만 확인했기 때문에, URL이 그렇게 끝나는 모든 요청은 인증을 완전히 건너뛰었으며, 여기에는 임의의 코드를 생성하고 실행하는 엔드포인트도 포함되었습니다. 그 결과: 네트워크를 통해 취약한 Kestra 인스턴스에 접근할 수 있는 사람은 누구나 자격 증명 없이, 피싱 없이, 비밀번호 추측 없이, 권한 상승 단계 없이 root로 명령을 실행할 수 있습니다.
이 실습에서는 그 단일 결함을 자체 호스팅 랩 인스턴스에 대해 처음부터 끝까지 실행했습니다:
모든 단계는 방어 텔레메트리 (네트워크 IDS, 호스트 런타임 보안, Linux 감사, 시스템 로그)에 대해 캡처되었습니다.
패치하지 않을 경우의 비즈니스 영향: Kestra를 실행하는 호스트의 완전한 장악이며, 애플리케이션만이 아니라 그 호스트에서 접근 가능한 다른 모든 것까지 확장됩니다.
수정: Kestra 1.0.45 / 1.3.21 이상으로 업그레이드하십시오 (패치만으로 기본 취약점은 해결되지만, 상승 및 지속성 단계는 별도의 독립적인 수정이 필요합니다 - 애플리케이션 컨테이너에 Docker 소켓을 마운트하지 마십시오, 섹션 8 참조).
이 보고서는 Kestra ≤1.3.20의 CVSS 10.0 인증되지 않은 원격 코드 실행 취약점인 CVE-2026-53576을 문서화하며, 이는 경로 접미사 인증 우회 (AuthenticationFilter.java, endsWith("/configs"))로 인해 발생합니다.
워크플로의 네임스페이스와 ID를 configs로 지정하는 공격자는 자격 증명 없이 Kestra 컨테이너 내부에서 root로 임의의 셸 명령을 생성하고 실행할 수 있습니다. 1.0.45 및 1.3.21에서 수정되었습니다. 동일한 버그는 CVE-2026-49869로도 독립적으로 보고되었으며, 이는 실제 야생에서의 악용과 관련된 CISA KEV 등재 번호입니다. 공개 소스와 스캐너가 둘 중 하나를 참조할 수 있으므로 둘 다 함께 인용해야 합니다.
| 취약 | Kestra ≤ 1.3.20 (및 1.0.x 라인의 1.0.45 이전) |
| 수정 | 1.0.45 / 1.3.21+ |
| CVE | CVE-2026-53576 |
| 쌍둥이 권고 | CVE-2026-49869 - 동일한 버그, CISA KEV 등재 (야생에서) |
| 날짜 | 이벤트 |
|---|---|
| 2026-06-02 | Kestra 1.3.21 릴리스; 변경 로그에 "인증 필터의 잠재적 인증 우회" 언급 |
| 2026-06-03 | Kestra 1.0.45가 1.0.x 라인에 릴리스 |
| 2026-09-02 | CVE-2026-49869 (쌍둥이 권고)가 CISA KEV 카탈로그에 추가됨 |
| 2026-09-22 ~ 09-24 | 이 랩 재현, 탐지 구축, 교차 계층 검증 |
자체 호스팅 홈랩:
- Debian 호스트 (호스트명 docker, 커널 6.12.107+deb13-amd64),
- Docker Engine 29.8.1.
- Kestra는 공식 kestra/kestra:v1.3.20 이미지로 배포되었으며, kestra.int.atlasvec.com의 Caddy 리버스 프록시를 통해 접근 가능.
- 테스트 중인 텔레메트리 스택: Falco (런타임/eBPF, 호스트 수준),
- Suricata 8.0.3 IDS (수동 SPAN 미러), Splunk로 전달.
무엇이든 건드리기 전에 대상이 실제로 취약한지, 텔레메트리 스택이 살아 있는지 확인했습니다. 또한 작업이 끝난 후 되돌릴 수 있도록 공격 전 상태의 스냅샷을 찍었습니다.
취약한 버전을 실행 중인 Kestra:

컨테이너 자체, 실행 중이며 접근 가능:

호스트에 로드된 Falco의 유닛:

Falco가 활발히 이벤트를 내보내는 중 (최신 eBPF 모드):

Suricata 서비스 활성:

그리고 eve.json이 실시간 이벤트를 기록 중:

이것은 하나가 아니라 두 가지 실수가 겹친 것입니다.
첫째, 인증 필터는 요청 경로의 끝을 매칭하여 요청이 인증을 건너뛸 수 있는지 결정합니다:```java // AuthenticationFilter.java — the vulnerable check, confirmed against the self-hosted v1.3.20 source if (path.endsWith("/configs")) { // treated as a public, unauthenticated path }
이 검사는 단일하고 무해한 엔드포인트인 공개 인스턴스 설정을 노출하기 위해 존재합니다. `endsWith`는 문자열의 끝부분만 읽기 때문에, 하나의 안전한 경로를 같은 방식으로 끝나는 다른 경로와 구별할 수 없습니다.
둘째, Kestra의 라우터는 여전히 그렇게 닮은 경로들을 실제의 민감한 핸들러로 디스패치합니다. `/api/v1/main/flows/configs`는 flow-create 핸들러에 도달합니다. `/api/v1/main/executions/configs/configs`는 execution 핸들러에 도달합니다. 필터는 둘 다 공개로 통과시키고, 라우터는 어쨌든 그것들을 실행합니다. flow의 namespace와 ID를 `configs`로 지정하면, 코드를 실행하는 엔드포인트가 이제 `/configs`로 끝나므로, 공개 경로의 무료 통과권을 상속받습니다.
캡처된 요청 쌍은 이를 명확히 보여줍니다. 자격 증명 없이 `GET /api/v1/main/flows/search`는 `401`을 반환합니다. 동일한 빈 auth 헤더로 `POST /api/v1/main/flows/configs`는 `200`을 반환하고 flow를 저장합니다(§5.1 참조).
## 5. 공격 시뮬레이션
> 아래의 모든 단계는 각각의 스크린샷과 함께 캡처됩니다. 모든 것은 리버스 프록시 뒤의 자체 호스팅 Kestra 인스턴스에 대해 제 격리된 홈랩 내부에서 실행됩니다.
### 5.1 1단계 - 인증 우회 -> Kestra 컨테이너 내부의 root
**대조 :** 자격 증명 없이 `GET /api/v1/main/flows/search` → `401 Unauthorized`.
정상 경로에서 인증이 강제됨을 확인합니다.

_____
**심기 :** auth 헤더 없이 `POST /api/v1/main/flows/configs`를 전송합니다. 본문은 `namespace`와 `flow id`가 모두 `configs`인 flow YAML이며, Process task runner를 사용하는 Commands task를 포함합니다. 서버는 `200 OK`를 반환하고 flow를 저장합니다. 그 외에는 보호되는 경로에 붙은 `/configs` 접미사가 우회를 유발하는 것입니다 **(섹션 4 참조).**

**청취 및 대기** : 테스트 목적으로 nc를 사용하여 간단한 리스너를 시작하여 리버스 셸을 잡습니다.

**트리거 / 실행** `POST /api/v1/main/executions/configs/configs`, auth 헤더 없음 → `200 OK`, 새 execution 생성됨.

**BaaaaM :** 셸을 획득했습니다. 하지만 기억하세요 - 우리는 "격리된" 상태이고, `root`이지만 Kestra docker 컨테이너 **내부**에 있으므로 여기서 탈출할 "수 없어야" 합니다. "**음, 그게 내가 생각한 거였는데**"

task의 명령은 Kestra JVM 프로세스의 직접 자식으로 실행되며, 호스트 측 프로세스 트리를 통해 확인되고, Kestra 자체의 실행 로그에 따라 성공적으로 완료됩니다.
**Kestra의 로그 대시보드**

**Kestra의 프로세스 트리**

**결과:** Kestra 컨테이너 내부에서 root로서의 인증되지 않은 원격 코드 실행. 이것이 **CVE-2026-53576**의 완전하고 자체 포함된 증명입니다.
### 5.2 2단계 - 노출된 Docker 소켓을 통한 권한 상승 (홈랩 특정, CVE 자체의 일부가 아님)
1단계 셸에서 `/var/run/docker.sock`이 컨테이너에 마운트된 것이 발견되었습니다 - Docker-outside-of-Docker (DooD) 패턴으로, Kestra 자체의 `Docker` task runner가 구성될 때 흔한데, 통신할 데몬이 필요하기 때문입니다.
그 소켓에 도달하는 것 자체가 호스트 **root**와 동일합니다: Docker API는 클라이언트가 자신이 생성하는 컨테이너에 대해 임의의 호스트 바인드 마운트와 호스트 PID/네트워크 네임스페이스를 구성할 수 있게 하며, 소켓 뒤의 데몬은 이미 호스트에서 root로 실행됩니다.
이것은 커널이나 컨테이너 탈출 익스플로잇이 아닙니다 - Docker API가 설계된 대로 작동하는 것이며, 도달할 수 없어야 할 곳에서 도달한 것입니다.
소켓을 사용하여, 호스트 파일시스템을 바인드하고 호스트 PID 및 네트워크 네임스페이스를 가진 형제 컨테이너를 생성한 다음 시작했습니다.
**참고:** 테스트 중에 더 조용한 두 번째 변형도 나타났지만, 별도로 스크린샷을 찍지는 않았습니다. 항상 새로운 형제 컨테이너를 생성하는 대신, 동일한 소켓 접근으로 이미 실행 중인 컨테이너에 대해 `POST /containers/{id}/exec`를 실행할 수 있으므로, 컨테이너 생성 이벤트가 전혀 없습니다. 이 Docker 호스트에는 Kestra와 Portainer가 모두 있어, 동일한 탈출에 어느 쪽이든 사용할 수 있습니다. 이는 탐지에 중요합니다: 새로 생성된 권한 있는 컨테이너에 초점을 맞춘 모든 규칙은 이 변형을 놓칩니다.
root를 확인하고 소켓이 아무 제한 없이 마운트 해제된 채 거기 있는 것을 발견:

Docker 데몬이 실제로 소켓을 통해 도달 가능한지 확인:

이미 로컬에 있는 이미지 목록을 확인하여 아무것도 pull할 필요가 없도록 함:

첫 번째 시도: 호스트 파일시스템을 바인드한 권한 있는 컨테이너:

두 번째 시도, 이번에는 호스트 PID 및 네트워크 네임스페이스 추가:

세 번째 시도, 마운트된 호스트 파일시스템으로 직접 chroot:

리스너를 띄우고 탈출 셸이 콜백할 포트에서 대기:

컨테이너 시작:

**Root, 하지만 이번에는 컨테이너가 아닌 호스트:**

컨테이너의 격리된 뷰가 아닌 실제 호스트와 일치하는 커널 버전:

나머지 세션을 위해 적절한 대화형 셸로 업그레이드:

### 5.3 3단계 - 지속성, 발동 확인됨
호스트 root 셸에서 두 가지 독립적인 지속성 메커니즘을 설정했습니다,
**첫째**, SSH 키. 누가 이미 접근 권한을 가지고 있는지 확인:

그런 다음 새 키를 차단할 만한 것이 있는지 sshd 자체 설정을 확인:

공격자 박스에서 키 쌍 생성:

sshd가 실제로 리스닝 중인지 확인:

공개 키를 root의 `authorized_keys`에 삽입:

그리고 일치하는 개인 키로 로그인:

**추신:** 이것은 원래 RCE 체인과 독립적인 root 접근입니다. Kestra가 패치되더라도 이 키는 여전히 작동합니다.
**둘째**, cron 비컨. 일정 간격으로 실행되도록 설정된 root 수준 콜백을 삽입한 다음, 새 리스너로 테스트하여 예정대로 실제로 발동하는지 확인:

**발동했습니다. RCE와 SSH 키 모두와 독립적인 호스트의 두 번째 발판.**
### 5.4 검증된 킬체인 타임라인.
아래 타임라인은 다릅니다: 독립적인 방어자 측 텔레메트리(네트워크 IDS + 호스트 런타임 보안)로부터 전적으로 재구성되었으며, 실제 Splunk 데이터에 대해 실시간으로 가져와 검증되었습니다.
**주요 RCE - 네트워크가 전달을 탐지, 호스트가 실행을 확인, 103초 차이:**
| 시간 (EDT) | 계층 | 이벤트 |
| ------------ | ------------------ | -------------------------------------------------------------------------------------------- |
| 02:46:09.778 | 네트워크 (Suricata) | 이 정확한 CVE에 대한 공개 ET 시그니처 발동 |
| 02:47:52.277 | 호스트 (Falco) | Kestra 컨테이너 내부에서 리버스 셸 확인, 정확한 명령과 컨테이너 ID 캡처 |
**권한 상승 - 네트워크와 호스트가 동일한 이벤트의 서로 다른 부분을 각각 독립적으로 입증:**
| 시간 (EDT) | 계층 | 이벤트 |
| ------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| 03:48:55.503 | 호스트 (Falco) | 권한 상승 컨테이너로부터의 리버스 셸 |
| 03:51:57.360 | 네트워크 (Suricata) | TCP 흐름 **및** 콘텐츠 기반 경보 - `id`가 실행될 때 리터럴 문자열 `uid=0(root)`가 호스트를 떠나는 것이 평문으로 관찰됨 |
## 6. 탐지 엔지니어링
실제 캡처된 텔레메트리에 대해 탐지를 구축한 다음, 각각을 리플레이에 대해 테스트했습니다. 매트릭스는 제가 시작하기 전에 커버리지가 존재했던 곳과 그렇지 않았던 곳을 보여줍니다.
### 6.0 탐지 커버리지 매트릭스
| 단계 | 네트워크 (Suricata) | 호스트 (Falco) | 호스트 (auditd/journald) | 상태 |
| --- | --- | --- | --- | --- |
| 초기 익스플로잇 요청 | 공개 ET 시그니처 발동 | 앱 계층 가시성 없음 | - | 커버됨 (기존) |
| RCE 실행 | - | 네이티브 규칙, T1059 태그 | - | 커버됨 (기존) |
| Docker 소켓 권한 상승 (기법) | - | 갭: 결과 셸만 잡고, 소켓 악용 API 호출은 잡지 못함 | EXECVE 레코드가 정확한 `curl --unix-socket` 호출을 캡처 | 갭 발견, auditd + 사용자 정의 Falco 규칙으로 해결 |
| 권한 상승 영향 확인 | 유출된 `id` 출력에 대한 콘텐츠 경보 | 동일한 일반 셸 규칙 | - | 커버됨 (기존, 교차 계층) |
| SSH 지속성 | - | - | journald: 전체 PAM 라이프사이클 및 키 지문 | 커버됨 (호스트 전용) |
| Cron 지속성 | - | - | journald 및 linux_audit, 두 소스, 정확한 5분 주기 | 커버됨 (호스트 전용) |
갭은 docker 소켓 권한 상승입니다. Falco의 기본 규칙은 침해된 컨테이너가 생성하는 셸을 잡지만, 안정적인 기본 세트에서 프로세스가 `/var/run/docker.sock`에 도달하여 Docker API를 직접 구동하는 것을 표시하는 것은 없습니다. 권한 있는 컨테이너 실행을 다룰 규칙인 `Launch Privileged Container`와 `Launch Sensitive Mount Container`는 `incubating` 및 `sandbox` 성숙도로 제공되므로, 기본 규칙 세트도 이를 로드하지 않습니다. auditd 상관 검색(탐지 03)과 사용자 정의 Falco 규칙(§6.3)으로 갭을 해결했습니다.
### 6.1 Splunk - 다섯 개의 상관 검색, 배포 및 예약됨
다섯 개 모두 Splunk에서 실시간으로 실행됩니다(`*/5 * * * *`, 경보 추적 활성화, 필드별 스로틀링). 단지 작성하고 텍스트로 남겨둔 것이 아닙니다. 전체 SPL, 정확한 FP 노트, 심각도, MITRE 태그, 각각에 대한 대응 런북은 `detections/splunk/*.spl`에 있습니다. 아래 상태 표는 각각에 대한 실시간 테스트 결과이며, 제가 발견하고 수정한 실제 버그를 포함합니다.
| # | 탐지 | MITRE | 상태 |
| --- | ---------------------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| 01 | 네트워크 익스플로잇 시그니처 (Suricata ET 경보 소비) | T1190 | **발동** - 과거 리플레이 확인됨, 이후 새 이벤트 없음 (현재 lookback 범위 밖) |
| 02 | 호스트 RCE 실행 (Falco redirect-to-network 규칙) | T1059 | **발동** - 과거 리플레이 확인됨 |
| 03 | Docker 소켓 악용 (auditd, 갭 해결자) | T1610, T1611 | **실시간 스케줄러 자체에서 발동** - 실제 `*/5 * * * *` 실행에서 `triggered_alert_count: 1` 확인됨, 수동 테스트만이 아님 |
| 04 | SSH root 로그인 지속성 | T1098.004, T1021.004 | **발동** - 과거 리플레이 확인됨 |
| 05 | Cron 비컨 지속성 | T1053.003 | **제가 발견하고 실시간으로 수정한 버그와 함께 배포됨.** `-10m` 디스패치 윈도우가 `distinct_intervals >= 3` 임계값에 필요한 세 개의 5분 버킷 중 두 개만 보유하여, 비컨이 실제 데이터에서 여전히 실행 중임에도 절대 발동할 수 없었습니다. `-30m`으로 넓히고 재배포했으며 - 그 이후 스케줄러가 53번 발동했으므로 수정이 유지됩니다. |
탐지 03의 역할 분담은 의도적입니다: Suricata 자체의 시그니처 로직을 SPL로 재구현하거나, Falco가 구축되지 않은 소켓 수준 기법을 잡도록 시도하는 대신, 여기 SIEM 계층은 정확한 `curl --unix-socket` 호출에 대한 auditd의 EXECVE 레코드를 소비합니다 - 이 특정 기법에 대해 가장 신뢰할 수 있는 것으로 입증된 텔레메트리 소스입니다.
1. **탐지 01** - ET 시그니처 발동 (`suricata:eve` 경보):```spl
index=main sourcetype=suricata:eve event_type=alert
alert.signature="ET WEB_SPECIFIC_APPS Kestra Unauthenticated Remote Code Execution (CVE-2026-53576)"
| stats count min(_time) as first_seen max(_time) as last_seen
values(src_ip) as source_ips
by dest_ip dest_port
| eval first_seen=strftime(first_seen,"%Y-%m-%d %H:%M:%S")
| eval last_seen=strftime(last_seen,"%Y-%m-%d %H:%M:%S")

Detection 02 - 컨테이너별로 분리된 Falco의 redirect-to-network 규칙. Source IP가 Kestra 컨테이너의 브리지 주소(172.17.0.3, 포트 4489에서의 최초 RCE)에서 호스트 자체(172.66.66.67, 포트 4491에서의 권한 상승)로 이동하는데, 이는 컨테이너에서 호스트로의 권한 상승이 가시화된 것이며, 목적지는 일정하게 유지된다. 즉 172.66.66.125에 있는 공격자의 리스너이다:

Detection 03 - curl --unix-socket docker.sock의 auditd EXECVE 레코드:

Detection 04 - journald root SSH 로그인, 키 지문 캡처됨:

Detection 05 - 정확히 5분 주기로 root 권한으로 실행되는 숨겨진 dotfile cron 비콘(/usr/local/bin/.sysmon): 약 6.5시간(04:30-11:00 EDT) 동안 79개의 서로 다른 간격. distinct_intervals >= 3 임계값이 주기적 비콘과 일회성 cron 작업을 구분하는 기준이다:

다섯 개 모두 예약된 저장 검색(*/5 * * * *)으로 배포됨:

cron 스케줄러가 이것들을 단지 존재하는 것이 아니라 실제로 실행한다는 증거: 다섯 개 모두 54회 실행되었다. Detection 03은 한 번 발생했고(docker-socket 악용, 06:35 EDT), Detection 05는 53회 발생했다(여전히 활성 상태인 cron 비콘). Detection 01/02/04는 0회 발생으로 표시되는데, 이는 일회성 과거 이벤트(익스플로잇 요청, RCE, SSH 로그인)로서 -10m lookback 범위를 벗어났기 때문이며, 반면 라이브 또는 반복되는 인스턴스라면 여전히 경고할 것이다:

/dev/tcp/ 리버스 셸 패턴 - 최초 RCE와 권한 상승 콜백 모두에서 사용됨. SigmaHQ는 이에 대한 규칙을 제공한다: "Suspicious Reverse Shell Command Line"(id 738d9bcf-6999-4fdb-b4ac-3033037db8ab, Nextron Systems의 Florian Roth 작성)이며, 그 키워드 중 하나가 bash -i >& /dev/tcp/인데, 이는 우리 캡처에 나타난 것과 정확히 일치한다.
그래서 나는 그 규칙을 변경 없이 가져와(detections/sigma/lnx_shell_susp_rev_shells.yml) Detection 02가 이미 캡처한 동일한 Falco 이벤트에 대해 그 키워드를 확인했다. Sigma는 스스로 "발생"하지 않는다 - 실행 중인 엔진이 아니라 이식 가능한 시그니처이다 - 하지만 교과서적 예시 대신 이번 실행의 실제 텔레메트리에 그 키워드가 적용되는 것을 보여줄 수 있다.
공개 SigmaHQ 규칙 "Suspicious Reverse Shell Command Line" - Detection 02와 동일한 실제 이벤트에 대한 bash -i >& /dev/tcp/ 키워드:

detections/falco/docker_socket_abuse.yaml - 라이브 Falco 인스턴스에 배포되었고 실제 리플레이에서 발생 확인됨, 2026-09-24T10:27:29Z.
Falco의 기본 규칙 세트는 이것을 다루지 않는다. 프로세스가 /var/run/docker.sock에 접근하는 것을 탐지하는 것은 새로운 아이디어가 아니다 - Sysdig 자체의 Falco 예제에서는 소켓 경로에 대한 open_write를 감시하여 이를 수행한다 - 하지만 배포/기본 세트에는 그러한 규칙이 없으며(프로젝트에 이에 대한 열린 요청이 있다, falcosecurity/falco #2940), 인접한 기본 규칙 하나는 docker/kubectl CLI만 잡을 뿐 원시 curl --unix-socket은 잡지 못한다.
문제는: 그 표준적인 소켓에 대한 open_write 접근 방식이 이 설정에서는 발생하지 않았다는 것이다 - modern_bpf와 패시브 미러에서는 소켓이 open()이 아니라 connect()를 통해 접근된다. 그래서 나는 대신 프로세스 생성 시점의 명령줄을 매칭한다(spawned_process + proc.cmdline contains "docker.sock"), 이는 Falco가 여기서 이미 안정적으로 처리하는 동일한 이벤트 클래스이다. 호출당 두 번 발생한다 - 셸 래퍼와 curl 리프 - 전체 컨텍스트와 함께:```
priority=Critical, container_id=d417e027d444, image=kestra/kestra:v1.3.20, user=root, cmdline="curl -s --unix-socket /var/run/docker.sock http://localhost/version", tags=[T1610, T1611]
커스텀 Falco 규칙 발화 - "Unexpected Process Accessing Docker Socket" (T1610/T1611):

발화한 기본 Falco 규칙 - 기본 규칙 세트에는 docker-socket 규칙이 없으며, 이것이 바로 그 간극이다:

### 6.4 Suricata - 기존 공개 커버리지, 커스텀 규칙은 보류
주 익스플로잇의 네트워크 계층은 이미 공개된 Emerging Threats 시그니처인 `ET WEB_SPECIFIC_APPS Kestra Unauthenticated Remote Code Execution (CVE-2026-53576)`로 커버되며, 이는 Phase 2 동안 실제 트래픽에서 발화했다.
아래는 네트워크 계층에서 관찰된 동일한 우회이며, 나는 취약점 패턴을 바탕으로 쿼리를 작성했다. `flows` 또는 `executions` 엔드포인트에서 경로가 `/configs`로 끝나는 모든 요청은 `200`을 반환한 반면, 정상 경로(`/flows/search`)는 예상대로 `401`을 반환했다.
`Attacker IP (XFF)` 열은 실제 HTTP 오리진으로, `X-Forwarded-For` 헤더에서 읽은 값이다: `10.10.10.106`, 즉 Burp를 실행 중인 내 Mac이다. Suricata 자체의 `src_ip`는 리버스 프록시 홉(`172.66.66.1`)만 본다. 이는 나중에 리버스 셸을 받고 SSH 로그인을 수행한 `172.66.66.125` Kali 박스와는 다른 머신이므로, HTTP 익스플로잇과 콜백은 서로 다른 호스트에서 발생했다.

### 6.5 대시보드
`cve_2026_53576_kill_chain`은 Splunk에 배포되어 있으며 다음을 포함한다: 헤드라인 KPI(탐지 계층, ATT&CK 기법, 배포된 탐지, 지속성 메커니즘), 텔레메트리 계층별로 색상이 지정된 공격 타임라인 컬럼 차트, 단계별 실시간 증거 수가 표시된 MITRE ATT&CK 킬체인 맵, §5.4의 네트워크-호스트 상관 타임라인, 예약된 saved search별 탐지 커버리지, docker-socket 기법 분석, 그리고 로그에서 실시간으로 가져온 침해 지표 테이블.
- KPI, 공격 타임라인 차트, ATT&CK 맵의 시작 부분:

- ATT&CK 맵의 나머지 부분, 상관 킬체인, docker-socket 분석 옆의 탐지 커버리지, 그리고 IOC 테이블:

## 7. ATT&CK 매핑
| Tactic | Technique | Evidence |
| -------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Initial Access | T1190 - Exploit Public-Facing Application | Control/plant/execute 요청 (§5.1); Suricata ET 시그니처 발화, §5.4 |
| Execution | T1059.004 - Command and Scripting Interpreter: Unix Shell | Kestra `Commands` 태스크, 호스트 프로세스 트리 (`07-kestra-process-tree.png`); Falco 규칙, §6.1 탐지 02 |
| Command and Control | T1095 - Non-Application Layer Protocol | Raw `/dev/tcp/` TCP 리버스 셸 - 애플리케이션 계층 C2 프레이밍 미사용 |
| Discovery | T1613 - Container and Resource Discovery | 소켓을 통한 Docker 이미지 열거 (`10-docker-images-enum.png`) |
| Privilege Escalation | T1610 - Deploy Container | Docker API를 통한 형제 컨테이너 생성/시작 (`11`–`15`); auditd EXECVE 레코드, §6.1 탐지 03 |
| Privilege Escalation | T1611 - Escape to Host | 호스트 root 확인, hostname/kernel 일치 (`16`, `17`) |
| Persistence | T1098.004 - Account Manipulation: SSH Authorized Keys | `/root/.ssh/authorized_keys`에 키 이식 (`23`) |
| Lateral Movement | T1021.004 - Remote Services: SSH | 키 기반 root 로그인 성공 (`24`); journald, §6.1 탐지 04 |
| Persistence | T1053.003 - Scheduled Task/Job: Cron | Cron 비콘, 예약대로 발화 확인 (`25`); §6.1 탐지 05 |
## 8. 교정 및 강화
**주요 수정.** Kestra 1.0.45(1.0.x 라인) 또는 1.3.21+(1.3.x 라인)로 업그레이드한다. 이것만으로 인증 우회 - 이번 실습의 Stage 1 - 이 차단되며, 적용 후 추가 보완 통제가 필요 없는 유일한 수정이다. [GHSA-2q47-568g-9h4f](https://github.com/kestra-io/kestra/security/advisories/GHSA-2q47-568g-9h4f)를 참조.
**즉시 패치가 불가능한 경우**, 영향도 순으로 나열한 보완 통제:
1. **리버스 프록시 강제** - 취약한 필터는 원시 경로 접미사에서만 실패하므로, Kestra 앞의 리버스 프록시(이 랩에서는 Caddy)가 `/api/v1/*/(flows|executions)/.*`와 일치하는 모든 경로에 대해 끝부분과 무관하게 독립적으로 인증을 강제할 수 있어, 애플리케이션 버그가 닿을 수 없는 계층에서 우회를 차단한다.
2. **Docker 소켓 마운트 제한** - 이는 Kestra 패치와 무관하게 Stage 2–3을 완전히 차단한다. `/var/run/docker.sock`을 Kestra 컨테이너에 바인드 마운트하지 말 것. `Docker` 태스크 러너가 정말로 필요하다면, 전체 데몬 접근 권한을 부여하는 대신 특정 API 호출만 허용 목록에 등록하는 범위 제한 소켓 프록시(예: `docker-socket-proxy`)를 사용하라 - 소켓에 대한 전체 접근은 §5.2에서 입증된 것처럼 호스트 root와 동등하다.
3. **SSH 강화** - 지속성 체인의 첫 번째 메커니즘은 애초에 키 기반 SSH로 root에 접근 가능하다는 점에 의존했다. `PermitRootLogin no`(또는 root에 대해 배스천/MFA 요구)는 초기 RCE와 무관하게 그 특정 지속성 경로를 차단했을 것이다 - 이 CVE와 별개로 해둘 가치가 있다.
4. **임시 탐지 커버리지** - 이번 실습에서 배포하고 검증한 Splunk 상관 검색과 커스텀 Falco 규칙은 패치가 예정된 동안 이 특정 체인의 단계들에 대한 임시 커버리지를 제공한다.
**사후 위생 조치**, 이 패턴이 이미 익스플로잇된 것으로 발견된 경우: 단순한 애플리케이션 침해가 아니라 전체 호스트 침해로 취급하라 - Kestra 인스턴스가 접근할 수 있었던 모든 자격 증명과 시크릿(KV 스토어 항목, 다운스트림 시스템 연결 자격 증명)을 회전시켜야 하며, Kestra 자체의 접근 권한만이 아니다.
**실제 공격 상태.** 동일한 버그에 대한 쌍둥이 권고인 `CVE-2026-49869`는 CISA의 KEV 카탈로그에 등재되어 있으며 관측된 크립토마이닝 및 클라우드 자격 증명 탈취 캠페인과 연결되어 있다. `CVE-2026-53576`(이 보고서)은 자체적인 KEV 등재가 없지만, 동일한 취약점이다. 두 CVE 번호 중 하나만 추적하는 취약점 관리 도구는 노출을 과소 보고할 수 있다.
## 9. 참고 자료
- Kestra 보안 권고 - [GHSA-2q47-568g-9h4f](https://github.com/kestra-io/kestra/security/advisories/GHSA-2q47-568g-9h4f) (CVE-2026-53576, 이 보고서의 주요 출처)
- 쌍둥이 권고 - [GHSA-5vc5-wxxq-3fjx](https://github.com/kestra-io/kestra/security/advisories/GHSA-5vc5-wxxq-3fjx) (CVE-2026-49869, 동일한 버그, CISA KEV 등재)
- CVE.org - [CVE-2026-53576](https://www.cve.org/CVERecord?id=CVE-2026-53576), [CVE-2026-49869](https://www.cve.org/CVERecord?id=CVE-2026-49869)
- CISA Known Exploited Vulnerabilities Catalog - https://www.cisa.gov/known-exploited-vulnerabilities-catalog (CVE-2026-49869 항목, 2026-09-02 추가)
- 수정 릴리스, 둘 다 존재하고 태그된 것으로 확인됨 - [v1.3.21](https://github.com/kestra-io/kestra/releases/tag/v1.3.21) (2026-06-02, 체인지로그에 "potential authentication bypass in the authentication filter"를 명시적으로 언급), [v1.0.45](https://github.com/kestra-io/kestra/releases/tag/v1.0.45) (2026-06-03)
- Docker 소켓 권한 상승 기법 (§5.2) - [HackTricks: Docker Breakout / Privilege Escalation](https://hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html), [Trail of Bits: Understanding Docker Container Escapes](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/), [MindPatch: Docker Escape](https://www.mindpatch.net/posts/docker-escape/)
- Sigma 규칙 (§6.2) - 직접 작성하는 대신 사용한 공개 규칙: [SigmaHQ "Suspicious Reverse Shell Command Line"](https://github.com/SigmaHQ/sigma/blob/master/rules/linux/builtin/lnx_shell_susp_rev_shells.yml) (id `738d9bcf-6999-4fdb-b4ac-3033037db8ab`, Florian Roth / Nextron Systems), [Detection Rule License 1.1](https://github.com/SigmaHQ/sigma/blob/master/LICENSE.Detection.Rules.md)에 따라 사용
- Falco 규칙 (§6.3) - docker-socket 간극은 업스트림에 열린 요청 사항이다 ([falcosecurity/falco #2940](https://github.com/falcosecurity/falco/issues/2940)); 커스텀 규칙은 [Sysdig의 Docker + Falco 예제](https://www.sysdig.com/blog/docker-falco-security)의 패턴을 따른다