한 줄 요약
rewrite 한 줄에 이름 없는 PCRE 캡처($1, $2)와 대체 문자열의 물음표(?)가 함께 들어가면, 비인증 공격자가 HTTP 요청 한 번으로 워커의 힙을 부순다. CVSS v4.0 9.2 Critical, 18년 전(2008년 NGINX 0.6.27)부터 조용히 있었던 결함이다.
F5와 depthfirst가 2026-05-13에 공동 공개했고, 별명은 NGINX Rift. 사흘 뒤인 5월 16일부터 VulnCheck canary가 실 익스플로이트 시도를 잡기 시작했다. 운영자는 즉시 패치 또는 임시 완화 둘 중 하나는 골라야 한다.
18년 묵은 결함이라는 의미
src/http/ngx_http_script.c에서 사는 결함이다. 2008년 NGINX 0.6.27에 처음 들어간 후 지금까지 모든 빌드가 영향권이다. 단일 함수 한 줄짜리 회귀가 아니라, 스크립트 엔진의 설계 단계에서 두 단계 호출 사이의 상태 누출이 그대로 굳어 버린 형태다.
지금까지 익숙했던 NGINX 취약점은 보통 모듈 단위였고 영향 버전 범위도 1~2년 정도였다. Rift는 0.6.27 ~ 1.30.0, NGINX Plus는 R32 ~ R36까지 한 줄로 묶인다. 같은 코드 경로를 그대로 가져다 쓴 fork와 다운스트림도 똑같이 영향을 받는다.
영향 받는 버전과 해결 버전
| 제품 | 영향 받는 버전 | 해결 버전 |
|---|---|---|
| NGINX Plus | R36 P4 미만 | R36 P4 이상 |
| NGINX Plus | R35 / R34 / R33 | 지원 라인업으로 마이그레이션 |
| NGINX Plus | R32 P6 미만 | R32 P6 이상 |
| NGINX Open Source | 1.30.1 미만 (≥ 0.6.27) | 1.30.1 (stable) / 1.31.0 (mainline) |
| NGINX Open Source | 0.9.7 이하 | 지원 라인업으로 마이그레이션 |
R35, R34, R33은 별도 패치 빌드가 없다 — 지원 중인 라인(R36 P4 또는 R32 P6)으로 마이그레이션이 답이다. F5 advisory는 K000161019, CVE 메타데이터는 NVD 페이지에 있다.
발현 조건
세 가지가 한 자리에서 만나야 한다.
rewrite지시문이 있다.- 그 뒤에
rewrite,if,set중 하나가 따라온다. - 대체 문자열에 이름 없는 PCRE 캡처(
$1,$2…)와 물음표(?)가 같이 들어간다.
예를 들어 다음 같은 흔한 패턴이 그대로 함정이다.
location /old/ {
# 취약: 이름 없는 $1 + 물음표 ?
rewrite ^/old/(.*)$ /new/$1?source=legacy break;
if ($http_user_agent ~ "bot") {
return 403;
}
}
이 자리에서 비인증 공격자가 특정 형태의 HTTP 요청을 한 번 보내면 워커의 힙에 경계 너머 쓰기가 일어난다. ASLR이 꺼져 있으면 임의 코드 실행이 가능해진다 — 워커 권한이므로 권한 상승은 그다음 단계지만, 컨테이너·구형 임베디드 환경에서는 그것만으로도 충분히 치명적이다.
버그 메커니즘 — 두 단계 스크립트 엔진의 상태 누출
NGINX의 스크립트 엔진은 같은 rewrite를 두 번 돈다. 길이 계산 패스(length pass)에서 출력 버퍼 크기를 정하고, 복사 패스(copy pass)에서 실제 값을 쓴다.
문제는 두 패스 사이에서 is_args 상태 플래그가 그대로 남는다는 점이다. 길이 계산 단계에서 물음표를 만나 is_args = 1로 켜진 플래그가 복사 단계의 다음 캡처 처리에 누출된다. 복사 단계의 ngx_escape_uri()는 켜진 플래그를 보고 인자(query string)용 이스케이프 규칙으로 더 많은 바이트를 써넣는다 — 길이 계산 단계에서는 다른 규칙으로 짧게 잡아 둔 그 버퍼에 말이다.
결과는 결정론적이다. heap chunk 경계 너머에 의도된 길이만큼 정확히 흘러넘친다.
flowchart TD
REQ["악성 HTTP 요청"]
REW["rewrite 지시문
(?, $1 포함)"]
LEN["1단계: 길이 계산
is_args 플래그 ON"]
LEAK["플래그 누출
(reset 누락)"]
COPY["2단계: 복사 패스
다음 캡처 처리"]
ESC["ngx_escape_uri
인자 규칙 적용"]
BUF["힙 버퍼 경계 초과 쓰기"]
DOS["워커 죽음 / 재시작"]
RCE["ASLR 꺼지면 RCE"]
REQ --> REW
REW --> LEN
LEN --> LEAK
LEAK --> COPY
COPY --> ESC
ESC --> BUF
BUF --> DOS
BUF --> RCE
패치(1.30.1 / 1.31.0)는 두 패스 진입 시 is_args를 명시적으로 reset하는 한 줄이 핵심이다. 18년 동안 묻혀 있던 이유는 — if / set이 뒤따르는 rewrite 체인에서만 두 패스가 같은 캡처를 두 번 보고, 거기에 이름 없는 캡처와 물음표가 동시에 있어야 하기 때문이다. 운영 환경에서 충분히 흔한 패턴인데 fuzz 코퍼스가 거기에 닿지 않았다.
임시 완화 — named capture로 교체
패치를 당장 못 올리는 환경에서는 F5와 depthfirst 모두 같은 권고를 한다. 모든 rewrite에서 이름 없는 캡처를 이름 있는 캡처로 바꾼다.
# Before (취약)
rewrite ^/old/(.*)$ /new/$1?source=legacy break;
# After (안전)
rewrite ^/old/(?<path>.*)$ /new/$path?source=legacy break;
이름 있는 캡처는 NGINX 스크립트 엔진의 다른 코드 경로를 타고, 거기에는 같은 플래그 누출이 없다. 동일한 동작을 유지하면서 결함 경로만 회피한다.
운영 중인 모든 config 파일에서 이름 없는 캡처 패턴을 검색해 둘 자리만 골라낸다.
grep -rnE 'rewrite[^;]*\$[0-9]' /etc/nginx/
지금 해야 할 일
- 버전 확인.
nginx -v로 정확한 빌드를 본다. NGINX Plus는nginx-plus -V에서 R 라인업이 나온다. - 노출도 평가. 위의
grep한 줄로 이름 없는 캡처 + 물음표 패턴을 가진 rewrite가 있는지 본다. 없으면 시간을 벌 수 있다. - 패치 적용. Open Source는 1.30.1 / 1.31.0, NGINX Plus는 R36 P4 / R32 P6. R33~R35는 지원 라인으로 마이그레이션.
- 즉시 패치 불가 시 named capture로 우회. 임시 패치 검증은 두 단계 — 정상 트래픽 회귀 테스트 + PoC 변형 요청 차단 확인.
- ASLR 확인.
cat /proc/sys/kernel/randomize_va_space가2인지 본다.0이면 임의 코드 실행 위험이 같이 살아 있다. - WAF·CDN 룰 확인. 앞단에 Cloudflare나 F5 BIG-IP 등이 있으면 벤더의 임시 시그니처가 이미 배포돼 있다 — Cloudflare는 5월 13일 당일에 managed rule을 풀었다.
- 로그 회수.
error.log에서 워커 재시작 패턴(worker process ... exited on signal 11)을 5월 13일 이후 기간으로 잡고 본다. 평소보다 빈도가 높으면 정찰 시도 흔적일 수 있다.
실 익스플로이트 현황
PoC는 DepthFirstDisclosures/Nginx-Rift repo에 공개돼 있다. VulnCheck의 canary 시스템이 5월 16일부터 인터넷 노출 NGINX를 향한 실 익스플로이트 시도를 잡기 시작했다. 공개에서 실 공격까지 사흘이다. Ingress NGINX(K8s)로도 같은 결함이 그대로 전파된다 — HeroDevs의 분석이 클러스터 운영자 관점에서 가장 친절하다.
정리
| 항목 | 값 |
|---|---|
| CVE | CVE-2026-42945 (NGINX Rift) |
| 분류 | CWE-122 Heap-based Buffer Overflow |
| CVSS | v4.0 9.2 Critical / v3.1 8.1 High |
| 공개일 | 2026-05-13 |
| 발견자 | depthfirst (with F5) |
| 도입 시점 | 2008년 NGINX 0.6.27 |
| 패치 | NGINX 1.30.1 / 1.31.0 · NGINX Plus R36 P4 / R32 P6 |
| 임시 완화 | 이름 없는 PCRE 캡처를 이름 있는 캡처로 교체 |
| 실 익스플로이트 | 2026-05-16부터 관측 (VulnCheck) |
if · set이 따라붙는 rewrite 체인은 어디서나 자주 쓴다. 운영하는 NGINX가 한 대라도 외부에 노출돼 있고, rewrite config에 $1 같은 표현이 한 줄이라도 들어 있다면, 지금이 1.30.1 패치를 올릴 가장 좋은 순간이다.
참고
- depthfirst — NGINX Rift 공식 페이지
- F5 K000161019 — Security advisory
- NVD — CVE-2026-42945
- DepthFirstDisclosures/Nginx-Rift — PoC repo
- The Hacker News — 18-Year-Old NGINX Rewrite Module Flaw Enables Unauthenticated RCE
- Help Net Security — Attackers are exploiting critical NGINX vulnerability
- HeroDevs — Heap Buffer Overflow Hits Ingress NGINX
- AlmaLinux — NGINX Rift Patches Released