Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
Kestra-cve-2026-53576 — Kestra의 인증되지 않은 RCE인 CVE-2026-53576의 엔드투엔드 재현 및 교차 계층 탐지 — 기본 PoC를 넘어 일반적인 Docker 소켓 오구성이 컨테이너 root를 호스트 전체 장악으로 어떻게 전환시키는지 보여줍니다. | Kitploit
도구/GitHubGitHub/atlasvector/kestra-cve-2026-53576
Privilege EscalationContainer SecurityPersistence MechanismsVulnerability AnalysisExploitationPost-ExploitationPenetration TestingPapers & ResearchRed Teaming

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
Incident Response
Labs & Practice
GitHubatlasvector/kestra-cve-2026-53576

Kestra-cve-2026-53576

Kestra의 인증되지 않은 RCE인 CVE-2026-53576의 엔드투엔드 재현 및 교차 계층 탐지 — 기본 PoC를 넘어 일반적인 Docker 소켓 오구성이 컨테이너 root를 호스트 전체 장악으로 어떻게 전환시키는지 보여줍니다.

저장소 보기
2일 전아직 검토되지 않음

Kestra의 트레일링 경로 인증 우회를 통한 인증되지 않은 RCE (CVE-2026-53576)

목차

  • 요약
  • 1. 개요
  • 2. 영향받는 버전 / 수정된 버전
  • 3. 테스트 환경 및 사전 점검
  • 4. 근본 원인
  • 5. 공격 시뮬레이션
  • 6. 탐지 엔지니어링
  • 7. ATT&CK 매핑
  • 8. 완화 및 강화
  • 9. 참고 자료

요약

Kestra는 오픈소스 워크플로 오케스트레이션 플랫폼으로, 요청에 자격 증명이 필요한지 여부를 URL이 /configs로 끝나는지 확인하여 결정하는 인증 필터를 배포했습니다. 이 검사는 무해한 공개 엔드포인트 하나를 노출하기 위한 것이었습니다.

이 검사가 문자열의 끝부분만 확인했기 때문에, URL이 그렇게 끝나는 모든 요청은 인증을 완전히 건너뛰었으며, 여기에는 임의의 코드를 생성하고 실행하는 엔드포인트도 포함되었습니다. 그 결과: 네트워크를 통해 취약한 Kestra 인스턴스에 접근할 수 있는 사람은 누구나 자격 증명 없이, 피싱 없이, 비밀번호 추측 없이, 권한 상승 단계 없이 root로 명령을 실행할 수 있습니다.

이 실습에서는 그 단일 결함을 자체 호스팅 랩 인스턴스에 대해 처음부터 끝까지 실행했습니다:

  • 인증되지 않은 코드 실행.
  • 노출된 Docker 소켓 발견.
  • 기반 호스트에 대한 완전한 root 접근으로의 상승.
  • 두 가지 독립적인 지속성 메커니즘 (SSH 백도어 키와 예약된 비콘).

모든 단계는 방어 텔레메트리 (네트워크 IDS, 호스트 런타임 보안, Linux 감사, 시스템 로그)에 대해 캡처되었습니다.

패치하지 않을 경우의 비즈니스 영향: Kestra를 실행하는 호스트의 완전한 장악이며, 애플리케이션만이 아니라 그 호스트에서 접근 가능한 다른 모든 것까지 확장됩니다.

수정: Kestra 1.0.45 / 1.3.21 이상으로 업그레이드하십시오 (패치만으로 기본 취약점은 해결되지만, 상승 및 지속성 단계는 별도의 독립적인 수정이 필요합니다 - 애플리케이션 컨테이너에 Docker 소켓을 마운트하지 마십시오, 섹션 8 참조).

1. 개요

이 보고서는 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 등재 번호입니다. 공개 소스와 스캐너가 둘 중 하나를 참조할 수 있으므로 둘 다 함께 인용해야 합니다.

2. 영향받는 버전 / 수정된 버전

취약Kestra ≤ 1.3.20 (및 1.0.x 라인의 1.0.45 이전)
수정1.0.45 / 1.3.21+
CVECVE-2026-53576
쌍둥이 권고CVE-2026-49869 - 동일한 버그, CISA KEV 등재 (야생에서)

타임라인

날짜이벤트
2026-06-02Kestra 1.3.21 릴리스; 변경 로그에 "인증 필터의 잠재적 인증 우회" 언급
2026-06-03Kestra 1.0.45가 1.0.x 라인에 릴리스
2026-09-02CVE-2026-49869 (쌍둥이 권고)가 CISA KEV 카탈로그에 추가됨
2026-09-22 ~ 09-24이 랩 재현, 탐지 구축, 교차 계층 검증

3. 테스트 환경 및 사전 점검

자체 호스팅 홈랩: - 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: 01-kestra-version-v1.3.20

컨테이너 자체, 실행 중이며 접근 가능: 06-docker-kestra-running

호스트에 로드된 Falco의 유닛: 02-falco-units-one-active

Falco가 활발히 이벤트를 내보내는 중 (최신 eBPF 모드): 03-falco-modern-bpf-active-emitting

Suricata 서비스 활성: 04-suricata-systemctl-active

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

4. 근본 원인

이것은 하나가 아니라 두 가지 실수가 겹친 것입니다.

첫째, 인증 필터는 요청 경로의 끝을 매칭하여 요청이 인증을 건너뛸 수 있는지 결정합니다:```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 }

root@kitploit:~
이 검사는 단일하고 무해한 엔드포인트인 공개 인스턴스 설정을 노출하기 위해 존재합니다. `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`. 
정상 경로에서 인증이 강제됨을 확인합니다.
![01-burp-control-401](https://assets.kitploit.com/production/public/readmes/56348/2a6d266e96b2b4e09bc32c0ccf3609159eaf5bacdc204989d5572211e616e6ff/8a8bab993fd7ba08656d03ad85822001996be4c391de87c535751cc9e14542a1-display-v1.webp)
_____

**심기 :** auth 헤더 없이 `POST /api/v1/main/flows/configs`를 전송합니다. 본문은 `namespace`와 `flow id`가 모두 `configs`인 flow YAML이며, Process task runner를 사용하는 Commands task를 포함합니다. 서버는 `200 OK`를 반환하고 flow를 저장합니다. 그 외에는 보호되는 경로에 붙은 `/configs` 접미사가 우회를 유발하는 것입니다 **(섹션 4 참조).**
![02-burp-plant-flow-200](https://assets.kitploit.com/production/public/readmes/56348/5d2a2db2d70e9d60e7136c765a7a85f4d8b684ea945da5b84e84d85a2b05a151/1ee6d8f7efd58d22ef41b536f32acbbdd417d68ac030ed28e2d06f9d6d4ccb93-display-v1.webp)
**청취 및 대기** : 테스트 목적으로 nc를 사용하여 간단한 리스너를 시작하여 리버스 셸을 잡습니다.

![03-kali-listener-4444](https://assets.kitploit.com/production/public/readmes/56348/88d7d3516aaeef900bbb9b372d9006323a3d7391078b693124ee24710da557ac/aa9806454d3742b7e958611a5c6ed2d3dfb3072eec3c14e4bb3f050a41220803-display-v1.webp)




**트리거 / 실행** `POST /api/v1/main/executions/configs/configs`, auth 헤더 없음 → `200 OK`, 새 execution 생성됨.
![04-burp-execute-200](https://assets.kitploit.com/production/public/readmes/56348/e70d1cd38f3825dca36c25e722bdfcf4a7614b1402fe1b6d0ccebdf992738bbe/9a394373a293d22ef55e3b6ee32eae6991feac73a5ccbc7909536bdf3435172d-display-v1.webp)

**BaaaaM :** 셸을 획득했습니다. 하지만 기억하세요 - 우리는 "격리된" 상태이고, `root`이지만 Kestra docker 컨테이너 **내부**에 있으므로 여기서 탈출할 "수 없어야" 합니다. "**음, 그게 내가 생각한 거였는데**"
![05-kali-revshell-container](https://assets.kitploit.com/production/public/readmes/56348/97257430abd2415f37f12c790a738d73e12f0c2509c193b1b7d24545453a1a70/9880399e445d4b8b602c1f381bbd8523a83c8c3c097b9a919e2b1871c7f1129e-display-v1.webp)


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

**Kestra의 로그 대시보드**
![06-kestra-ui-pwn-log](https://assets.kitploit.com/production/public/readmes/56348/b447d0d268daa119b1d64a9d7d95a588b80a7cb228613b81a6bfd69777aea7bb/467a61936f8779b533cc83a297d651957e17f9d00241ff97cc7640df917450fe-display-v1.webp)


**Kestra의 프로세스 트리**
![07-kestra-process-tree](https://assets.kitploit.com/production/public/readmes/56348/a7e20df484e1c5759fca4f5e403bc280ffc45b03b47dae22804321bb8398858c/0a0e30aa6c0537adf8ddd204453c8d51e808de2d5ff764fc5ad8f551cf059665-display-v1.webp)

**결과:** 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를 확인하고 소켓이 아무 제한 없이 마운트 해제된 채 거기 있는 것을 발견:
![08-docker-socket-present](https://assets.kitploit.com/production/public/readmes/56348/d2a34fd7db05bb2966a540410dbc8e76cfec416a545786349372984902b128f9/ca3ce180476010ee482b60c42687751f27a072aa2c0b78fbb6400b8406cee5e5-display-v1.webp)

Docker 데몬이 실제로 소켓을 통해 도달 가능한지 확인:
![09-docker-api-version](https://assets.kitploit.com/production/public/readmes/56348/7ce4365a9c48db827aa3c6e53c73622bef0ee7a99f530b5e37a065601b3892b0/d6debd41ca945cd5812add55df46cc5dd2f7bbaba1c88965f438ee7d5c9a4bcc-display-v1.webp)

이미 로컬에 있는 이미지 목록을 확인하여 아무것도 pull할 필요가 없도록 함:
![10-docker-images-enum](https://assets.kitploit.com/production/public/readmes/56348/aa1ff3ff76e92437899afc7b603925eeb53838f99f4d8586df69f8a96ff23622/34cd26942854c4c4bf59135beb54cac278aaad304faac4a3f5b64bec9e1a84de-display-v1.webp)

첫 번째 시도: 호스트 파일시스템을 바인드한 권한 있는 컨테이너:
![11-docker-create-privileged](https://assets.kitploit.com/production/public/readmes/56348/38f4f42a486e3f46f4d798e131b3eb3bd58a7e7507b7a9e88845ed52ee32bd29/673b8ab3de93e21c6fbe23b343c4cd7fc4ddac11554ad56c0d656e2ae46467dd-display-v1.webp)

두 번째 시도, 이번에는 호스트 PID 및 네트워크 네임스페이스 추가:
![12-docker-create-hostns](https://assets.kitploit.com/production/public/readmes/56348/f2a5c239adbabc9b3cef7f24d2ff60b49765bfec2ec231520d18edbcaec597cb/c387405779506f4d5e8f30715d359550b69d2c1a899525b293e8b69ce61c6e73-display-v1.webp)

세 번째 시도, 마운트된 호스트 파일시스템으로 직접 chroot:
![13-docker-create-chroot](https://assets.kitploit.com/production/public/readmes/56348/dc38f66a291764a224f2982d22b9ca3cb37bdb31d39c48344b8030448f452e41/23519a1a158885f8b9b5691ffab18ef6eb1b5c989af00bf7c4caf6fe58ee7176-display-v1.webp)

리스너를 띄우고 탈출 셸이 콜백할 포트에서 대기:
![14-host-listener-4491](https://assets.kitploit.com/production/public/readmes/56348/37b558192ffff02366b4d219e2393d1f9fe468e82555c90a236e2cf1bdd35aa7/116c772ff659ec661cad22e023a6179eb8ffd1ebf409624b4832a27a4e947626-display-v1.webp)

컨테이너 시작:
![15-docker-container-start](https://assets.kitploit.com/production/public/readmes/56348/277f7899c2fbb23d86a1918621f5efe79c635bd84af584811e98bdf37b7ab253/3f02d6a19613662df1b32fb8fa1bdbb03043f6b232844d2de3a23f552873103e-display-v1.webp)


**Root, 하지만 이번에는 컨테이너가 아닌 호스트:**
![16-host-root-id](https://assets.kitploit.com/production/public/readmes/56348/0a77d4e6c239354c2c79737c51f492005cf129af8c5a595614c1005c0a125405/02ed259073555446cd67e2ce2ab86c7408fb9c2e7864ce3daac8bc50fbd2db36-display-v1.webp)

컨테이너의 격리된 뷰가 아닌 실제 호스트와 일치하는 커널 버전:
![17-host-root-uname](https://assets.kitploit.com/production/public/readmes/56348/9f059686a831bfb8b5196412b9fd10492e8aeeb211dcb7d45fc98b3b6c0f999c/2c2dbd97e8c41b21085d9230d3b2ffb74f76c693947d9831007cff197fe3647d-display-v1.webp)


나머지 세션을 위해 적절한 대화형 셸로 업그레이드:
![18-host-pty-upgrade](https://assets.kitploit.com/production/public/readmes/56348/34894e77c38df22cbbd807a14fd14b8e49aadc6f894d990e4022bc5b85978b62/0f81e4ed6fa6dfef8867eed194e7e4cdf12dc025b00c5763b2884530199c15d7-display-v1.webp)

### 5.3 3단계 - 지속성, 발동 확인됨

호스트 root 셸에서 두 가지 독립적인 지속성 메커니즘을 설정했습니다,

**첫째**, SSH 키. 누가 이미 접근 권한을 가지고 있는지 확인:
![19-host-authkeys-enum](https://assets.kitploit.com/production/public/readmes/56348/553f3a2b399361ce652e836fab2525686519f44dee9d94d8b7c9d45b1b939d44/0a2c697dc0f216566dba1b4cb38f134ce23ff7b57bc40dc87032016a558e2668-display-v1.webp)

그런 다음 새 키를 차단할 만한 것이 있는지 sshd 자체 설정을 확인:
![20-host-sshd-config-enum](https://assets.kitploit.com/production/public/readmes/56348/a25dd7b5a8376e48cee6c75e64264fa973def1db09a9d7ea520b705e32021ef3/adbfee0a5f27442b43fa318a36ef281d5abc1d998c367f2e5978b11d8282677d-display-v1.webp)

공격자 박스에서 키 쌍 생성:
![21-attacker-keygen](https://assets.kitploit.com/production/public/readmes/56348/4b560189f5ab37c619d941dfedadd77a4fa8a49420aa720eafd6fccc44f7f734/f90cf5f5b1ebb76fe1505b063ef844e17c9c7b8e9f21a2f92213eb36f9428dec-display-v1.webp)

sshd가 실제로 리스닝 중인지 확인:
![22-host-sshd-active](https://assets.kitploit.com/production/public/readmes/56348/bd0ee4ae0a24f08b096c16eff66fd4ff87efccd92f1c1b509078d24f65af0e0f/78518194b025287cdf07b81a3335ea8b02239fcca6cbd2f32b507e28cc908cf9-display-v1.webp)

공개 키를 root의 `authorized_keys`에 삽입:
![23-host-authkeys-implant](https://assets.kitploit.com/production/public/readmes/56348/e2faba217e62433f6dcd9777fa85c8dcd24858ab1c6a2f5d1293515d744003bc/0c1ca3973a85e0ade63514eaa9ad4f3d0fd63f047dc7be19b112058f24632cfd-display-v1.webp)

그리고 일치하는 개인 키로 로그인:
![24-ssh-root-login-proof](https://assets.kitploit.com/production/public/readmes/56348/14b698fb9eae32aff09e6ec7d179ecf1c2ef665d7b87be8d6f9fac956e68db2b/a2ced84629d34de099a598e38f71ba54411a890eaadb50a2dc8dd8dc099a6459-display-v1.webp)

**추신:** 이것은 원래 RCE 체인과 독립적인 root 접근입니다. Kestra가 패치되더라도 이 키는 여전히 작동합니다.

**둘째**, cron 비컨. 일정 간격으로 실행되도록 설정된 root 수준 콜백을 삽입한 다음, 새 리스너로 테스트하여 예정대로 실제로 발동하는지 확인:
![25-host-cron-persist](https://assets.kitploit.com/production/public/readmes/56348/3dfa92072c55dd052127ef69943a6c43a855534420b286e0dbd62ce833dc441f/7a75828de1e323b44a4c792a2eed2713cf656433685deef7931026f815b2dd98-display-v1.webp)

**발동했습니다. 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")

det01-network-et-signature

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

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

  3. Detection 04 - journald root SSH 로그인, 키 지문 캡처됨: det04-ssh-root-login

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

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

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

6.2 Sigma - 이식 가능한 호스트 프로세스 생성 규칙

/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/ 키워드:

sigma-devtcp-match-event

6.3 Falco - docker-socket 격차를 메우는 사용자 정의 규칙

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]

root@kitploit:~
커스텀 Falco 규칙 발화 - "Unexpected Process Accessing Docker Socket" (T1610/T1611):
![det17-falco-custom-docker-sock](https://assets.kitploit.com/production/public/readmes/56348/6fa1b11a7c8c6a3c8619ac95a2950cf1f326df0ef1651324aa0b4f80db389a12/8ac8f1a2c5184a84ba2af0c9c85c3112506e19c62b0734105e5b74c90e4d8078-display-v1.webp)

발화한 기본 Falco 규칙 - 기본 규칙 세트에는 docker-socket 규칙이 없으며, 이것이 바로 그 간극이다:
![falco-rule-inventory](https://assets.kitploit.com/production/public/readmes/56348/5da667ac881b32f6bc633e58b4d00a08ea22cf3a5000b3ae8522cb3937b051a4/3fe1201158632dc6aef5257bf3620e83e087814f3da0108f7d2ef04fd5088ec9-display-v1.webp)

### 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 익스플로잇과 콜백은 서로 다른 호스트에서 발생했다.

![suricata-raw-post-http](https://assets.kitploit.com/production/public/readmes/56348/d713d35f0d858af8dd5d477a9929ed6d07e55bce5e9e43946dfe1fb1cca73699/975155c6fe8a39a0de715497a7e5a659b17641a7ed4ed2d7f4d7bfcd02842398-display-v1.webp)

### 6.5 대시보드

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

- KPI, 공격 타임라인 차트, ATT&CK 맵의 시작 부분:
![dashboard-kill-chain-1](https://assets.kitploit.com/production/public/readmes/56348/e0fe4ac39189ed9b3c4741ab5c8fb3276484a482dcb476b11e14381700647afd/5f586685c93346bd1df629ea4092a5a61146d0a32c2d258dfba620b3dd984161-display-v1.webp)

- ATT&CK 맵의 나머지 부분, 상관 킬체인, docker-socket 분석 옆의 탐지 커버리지, 그리고 IOC 테이블:
![dashboard-kill-chain-2](https://assets.kitploit.com/production/public/readmes/56348/f4479575da20da3a4028a0abaac1c3b565c5b034582b157730599a15601e195f/8b18bbbdd05d8955c38f457d71029f3b2be53b409959a7560c0f8f08f038cbaf-display-v1.webp)


## 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)의 패턴을 따른다
도구 다운로드