
CVE-2026-9256에 대한 개념 증명 익스플로잇으로, NGINX ngx_http_rewrite_module의 힙 버퍼 오버플로우입니다. 특수 문자가 포함된 조작된 URI를 통해 원격 워커 크래시를 검증하며, 신뢰할 수 있는 탐지를 위한 다단계 keep-alive 프로브를 제공합니다.
적용 범위: 로컬 실습 환경, 승인된 재현 환경, 취약점 검증 및 보호 규칙 분석에만 사용합니다. 승인되지 않은 대상에는 사용하지 마십시오. 본 문서의 PoC 아이디어는 원격에서 관찰 가능한 NGINX worker crash 동작만 검증하며, RCE, ASLR 우회 또는 안정적인 익스플로잇 체인을 포함하지 않습니다.
CVE-2026-9256은 NGINX ngx_http_rewrite_module의 힙 버퍼 오버플로우 취약점입니다. 취약점 트리거는 단순히 특정 고정 URI에 접근하는 것이 아니라, 특정 rewrite 설정 패턴에 의존합니다: rewrite 정규식에 서로 겹치는 PCRE 캡처 그룹이 존재하고, replacement 부분에서 $1, $2와 같은 여러 캡처 변수를 참조합니다.
공격자가 특수 URI를 구성하여 rewrite 로직이 관련 경로에 진입하면, NGINX가 캡처 내용을 처리하고 rewrite 결과를 연결하거나 URI/파라미터 이스케이프를 수행할 때 길이 계산과 실제 쓰기가 불일치하여 결국 worker 프로세스 힙 메모리가 손상될 수 있습니다.
따라서 이 취약점의 핵심은 /api라는 경로 자체가 아니라, 대상 NGINX 설정에 요청으로 적중 가능한 취약한 rewrite 규칙이 존재하는지 여부입니다. PoC에서 기본적으로 사용하는 /api는 현재 재현 환경의 예시 경로일 뿐이며, 실제 테스트 시에는 NGINX 설정에 존재하는, 겹치는 캡처 그룹을 포함하고 여러 캡처 변수를 참조하는 rewrite 규칙에 맞게 요청 경로를 조정해야 합니다.
현재 PoC의 목표는 worker crash / 서비스 거부(denial of service) 동작을 검증하는 것입니다. 정확한 힙 레이아웃을 구성하거나, 반환 주소나 함수 포인터를 덮어쓰거나, 원격 코드 실행을 증명하려고 시도하지 않습니다. 원격 측에서 관찰할 수 있는 안정적인 증거는 주로: 트리거 요청 연결이 비정상적으로 종료되고, 이후 NGINX 서비스가 응답을 재개하며, keep-alive 연결이 트리거 후 worker crash로 인해 중단되는 현상입니다.
이 취약점이 트리거된 후 반드시 고정된 HTTP 500, 502 또는 400으로 나타나는 것은 아닙니다. 그 이유는 NGINX의 master-worker 모델에서 worker 프로세스가 충돌하면 master가 새로운 worker를 다시 띄우기 때문입니다. 공격자가 원격 측에서 보는 현상은 일반적으로 전체 서비스가 완전히 사용 불가능해지는 것이 아니라, 특정 연결이 갑자기 끊기거나, 읽기 타임아웃이 발생하거나, 연결이 리셋되고, 이후 다시 /에 접근하면 정상 응답을 받을 수 있는 상태입니다.
따라서 PoC는 단일 요청의 HTTP 상태 코드만으로 취약점 존재 여부를 판단할 수 없습니다. 긴 URI를 한 번 보내고 연결이 끊어지는 것을 보고 바로 "취약점 존재"라고 판단하면 오탐 위험이 높습니다. 연결 끊김은 네트워크 지터, 프록시 타임아웃, 요청이 중간 장비에 차단되거나, 백엔드 속도 제한 또는 서버 측에서 능동적으로 연결을 닫는 경우에도 발생할 수 있습니다.
따라서 PoC는 다단계 검증 방식으로 설계되어야 합니다:
"트리거 연결 비정상 + 이후 서비스 복구 + keep-alive 다중 연결 끊김"이 동시에 나타날 때만 CVE-2026-9256 스타일의 worker crash 동작이 존재한다고 더 안정적으로 판단할 수 있습니다.
현재 PoC의 핵심 트리거 경로는 다음과 같습니다:
GET /api/++++++++++++++++++++++++++++++++... HTTP/1.1
Host: 127.0.0.1:19321
여기서 /api/는 현재 실습 환경에서 rewrite 규칙을 적중시키기 위한 예시 라우트이며, 뒤에 많은 수의 + 문자가 이어집니다. 기본 개수는 4096개입니다.
+를 선택한 이유는 주로 세 가지입니다.
첫째, +는 유효한 URI 문자이며, 일반 HTTP 클라이언트를 사용하여 전송할 때 공백, # 등의 문자처럼 잘리거나 강제로 변환되지 않는 경우가 많습니다. 따라서 현재 PoC는 일부 request-target 우회 취약점처럼 반드시 raw socket을 사용하여 비정상적인 요청 라인을 구성할 필요가 없습니다.
둘째, 많은 반복 문자는 rewrite 캡처 그룹이 충분히 긴 입력을 받도록 하여, 이후 replacement 연결 또는 이스케이프 처리의 출력 규모를 확대함으로써 길이 계산과 실제 쓰기 간의 불일치를 더 쉽게 트리거할 수 있습니다.
셋째, 반복되는 +로 구성된 페이로드는 구조가 간단하여 패킷 캡처, 로그, IDS 규칙에서 관찰하기 쉽고, 길이를 조정하여 임계값 테스트를 수행하기에도 편리합니다.
다만 +가 유일한 이론적 트리거 문자는 아닙니다. 실제 트리거 조건은 여전히 "취약한 rewrite 설정에 적중 + 입력이 관련 캡처 그룹에 진입 + rewrite 출력 처리로 힙 오버플로우 발생"입니다. 환경에 따라 트리거 라우트, 문자 유형, 길이 임계값을 조정해야 할 수 있습니다.
현재 PoC는 기본적으로 많은 수의 +를 트리거 문자로 선택하지만, 이것이 +만이 문제를 트리거할 수 있다는 의미는 아닙니다. +는 일반 PoC에 작성하기에 가장 적합한 문자일 뿐입니다. URI에서 상대적으로 안정적이며, 일반 HTTP 클라이언트로 전송하기 쉽고, 패킷 캡처 특징도 명확합니다.
취약점 원리상, NGINX rewrite 처리 과정에서 문자가 NGX_ESCAPE_ARGS 이스케이프 로직에 진입하고, 원래 1바이트에서 %XX 형태의 3바이트로 확장된다면, "길이 계산 값이 실제 쓰기 값보다 작은" 차이가 발생할 수 있습니다. 즉, 트리거 포인트는 본질적으로 + 자체가 아니라 "args 모드에서 이스케이프 가능한 문자가密集(밀집)하여 나타나는 것"입니다.
+ 외에도 이론적으로 고려해야 할 주요 문자는 다음과 같습니다:
공백: 0x20
#: 0x23
%: 0x25
&: 0x26
?: 0x3F
제어 문자: 0x00-0x1F
상위 바이트: 0x7F-0xFF
이 문자들이 관련 캡처에 진입하여 rewrite replacement에서 args 내용으로 이스케이프 처리되면 유사한 확장 효과가 발생합니다. 예:
+ -> %2B
& -> %26
% -> %25
# -> %23
? -> %3F
공백 -> %20
이러한 문자가 하나 나타날 때마다 이론적으로 1바이트에서 3바이트로 확장되어 실제 쓰기 길이가 2바이트 증가합니다. 입력에 이러한 문자가 많이 존재하면 실제 쓰기 길이가 이전에 잘못 계산된 버퍼 길이를 크게 초과하여 힙 버퍼 오버플로우를 더 쉽게 트리거할 수 있습니다.
그러나 PoC에서 각 문자의 사용 가능성은 완전히 동일하지 않습니다.
+가 가장 안정적입니다. 일반적으로 HTTP request-target에 직접 나타날 수 있으며, 브라우저나 명령줄 도구에 의해 잘리기 어렵고 URI의 path/query 구조를 자연스럽게 변경하지 않습니다. 따라서 현재 PoC는 4096개의 +를 기본 페이로드로 사용합니다.
&도 후보 문자가 될 수 있습니다. args 모드에서 %26으로 이스케이프되기 때문입니다. 그러나 셸에서 &는 백그라운드 실행 의미를 가지며, URL에서도 query 파라미터 구분자로 사용되는 경우가 많으므로 테스트 시 따옴표 처리와 위치에 주의해야 합니다. 그렇지 않으면 요청이 의도대로 전송되지 않을 수 있습니다.
%도 후보 문자가 될 수 있습니다. %25로 이스케이프되기 때문입니다. 그러나 % 자체는 URL 인코딩 접두사이므로 일부 클라이언트, 프록시 또는 프레임워크에서 %XX 시퀀스를 해석하려고 시도할 수 있습니다. 잘못 구성되면 대상이 원래 % 문자 대신 클라이언트가 전처리한 내용을 받을 수 있습니다.
?도 이론적으로 이스케이프 가능한 문자에 속하지만, HTTP request-target에서 path와 query를 구분합니다. 경로에 직접 배치하면 이후 내용이 query string으로 해석되어 rewrite 캡처 범위가 변경될 수 있습니다. 따라서 보충 테스트 문자로는 적합하지만 기본 PoC 주 문자로는 적합하지 않습니다.
#는 이론적으로 이스케이프를 트리거할 수 있지만, 브라우저는 #과 그 이후의 fragment를 서버로 전송하지 않습니다. 많은 고급 HTTP 클라이언트도 이를 인코딩하거나 자릅니다. 따라서 리터럴 #을 테스트하려면 일반적으로 raw socket, Burp Repeater 또는 원래 request-target을 유지할 수 있는 도구가 필요하며, 브라우저 주소 표시줄에 직접 의존할 수 없습니다.
공백 0x20도 이스케이프 문자에 속하지만, 일반 HTTP/1.1 요청 라인에서 공백 자체는 구분자이므로 request-target에 직접 넣으면 요청 라인 구조가 손상됩니다. 실제 테스트 시 %20으로 작성하면 서버 측 처리 단계에서 인코딩된 형태인지 디코딩된 공백인지는 구체적인 파싱 프로세스와 rewrite 위치에 따라 다릅니다. 따라서 공백은 원리 설명 및 보조 테스트에 더 적합하며 기본 페이로드로는 적합하지 않습니다.
0x00-0x1F 제어 문자와 0x7F-0xFF 상위 바이트도 이스케이프 범위에 포함되지만, 실제 HTTP 링크에서는 클라이언트, 프록시, WAF 또는 NGINX HTTP 파서에 의해 차단, 정규화 또는 거부될 가능성이 더 높습니다. 이들은 소스 코드 수준의 이스케이프 대상 설명에는 적합하지만 일반 PoC의 기본 트리거 문자로는 권장되지 않습니다.
따라서 현재 PoC가 +를 사용하는 이유는 취약점이 +로만 트리거될 수 있기 때문이 아니라, +가 세 가지 조건을 동시에 충족하기 때문입니다: args 이스케이프 확장을 트리거할 수 있고, 안정적으로 전송하기 쉬우며, URI 구조를 크게 변경하지 않습니다. 보호 규칙이나 트래픽 분석 시 연속된 +만 매칭해서는 안 되며, 긴 URI에 +, &, %, ?, # 등 이스케이프 가능한 문자가 많이 등장하는 고밀도 조합도 고려해야 합니다.
탐지 관점에서 더 합리적인 일반화는 다음과 같습니다:
/api/ 뒤에 많은 +가 나타남
보다는:
긴 URI에서 NGX_ESCAPE_ARGS 모드에서 %XX로 확장되는 특수 문자가 많이 나타남
++++만 탐지하면 현재 PoC의 기본 작성 방식만 커버할 수 있습니다. 공격자가 페이로드를 &&&&, %%%%, ????로 바꾸거나 +%&?#를 혼합하여 사용하면 단일 + 특징으로는 누락될 수 있습니다. 더 안정적인 탐지 방법은 URI 길이, 특수 문자 밀도, 연속 반복 횟수, rewrite 위험 경로 및 NGINX 서비스 노출 면을 종합적으로 판단하는 것입니다.
PoC의 normalize_target 함수는 명령줄 입력을 처리하며, 세 가지 형식을 지원합니다:
python3 CVE-2026-9256-poc.py 127.0.0.1:19321
python3 CVE-2026-9256-poc.py 127.0.0.1 19321
python3 CVE-2026-9256-poc.py http://127.0.0.1:19321
사용자가 scheme 없이 host:port만 입력하면 스크립트가 자동으로 http://host:port로 보완합니다. 그런 다음 urllib.parse.urlparse를 사용하여 hostname과 port를 추출하고 base를 생성합니다. 예:
host = 127.0.0.1
port = 19321
base = http://127.0.0.1:19321
현재 구현은 주로 HTTP 평문 실습 환경을 대상으로 합니다. normalize_target이 https:// 형식을 허용하지만, 이후 keep-alive 탐지는 일반 TCP 소켓을 사용하며 TLS 계층을 포함하지 않으므로 HTTPS 시나리오에서는 crash probe가 정확하지 않습니다. HTTPS를 지원하려면 소켓에 ssl.wrap_socket 또는 ssl.create_default_context().wrap_socket()을 추가해야 합니다.
PoC는 먼저 check_alive(base)를 호출하여 루트 경로 /에 접근합니다:
GET /
대상이 임의의 HTTP 상태 코드를 반환하면 서비스가 기본적으로 살아있는 것으로 간주하고 계속 테스트합니다. 연결에 실패하면 바로 종료하여, 연결 불가능한 대상을 취약점 트리거 실패로 오판하지 않도록 합니다.
그런 다음 check_rewrite(base)를 호출하여 다음에 접근합니다:
GET /api/test
이 요청은 /api/*가 현재 실습 환경의 rewrite 로직에 적중할 가능성이 있는지 관찰하는 데 사용됩니다. 301, 302, 303, 307, 308 등 리다이렉트 상태 코드가 반환되면 rewrite 리다이렉트 동작이 뚜렷한 것이므로 PoC는 Location 헤더를 보조 증거로 출력합니다.
그러나 이 단계는 필수 성공 조건이 아닙니다. 일부 재현 구성에서는 /api/* 자체가 문제가 있는 rewrite 경로에 진입할 수 있으며, 일반 탐지 요청도 타임아웃되거나 예외적으로 처리될 수 있습니다. 따라서 스크립트는 정상적인 rewrite 응답을 받지 못하더라도 트리거 단계를 계속 진행합니다.
트리거 함수는 send_trigger(base, plus_count=4096)이며, 핵심 로직은 다음과 같은 연결입니다:
payload = "/api/" + ("+" * plus_count)
기본 최종 요청 경로는 다음과 유사합니다:
/api/++++++++++++++++++++++++++++++++... 총 4096개의 +
그런 다음 requests.get(base + payload, timeout=10, allow_redirects=False)를 통해 요청을 전송합니다.
여기서 자동 리다이렉트를 비활성화하는 데는 두 가지 이유가 있습니다.
첫째, rewrite 자체가 리다이렉트를 반환할 수 있습니다. HTTP 클라이언트가 자동으로 리다이렉트를 따라가면 원래 트리거 요청과 이후 리다이렉트 요청이 혼합되어 첫 번째 요청에서 정확히 무슨 일이 일어났는지 판단하기 어려워집니다.
둘째, PoC는 트리거 단계의 연결 상태에 관심이 있을 뿐, 리다이렉트 후의 비즈니스 페이지에는 관심이 없습니다. 원래 응답을 유지하는 것이 분석에 더 유리합니다.
트리거 결과는 여러 범주로 나뉩니다:
ConnectionError가 포착되면 트리거 요청 중 연결이 비정상적으로 종료되었음을 의미하며, 이는 worker crash의 원격 징후일 수 있습니다.
ReadTimeout이 포착되면 요청 전송 후 오랫동안 정상 응답이 없음을 의미하며, worker가 멈추거나 충돌 전에 정상적으로 반환되지 않았거나, 네트워크 환경으로 인한 타임아웃일 수 있습니다.
정상적으로 HTTP 응답을 받으면 상태 코드와 응답 본문 길이를 출력하지만, 정상 응답만으로 취약점 부재를 단정할 수는 없습니다. 일부 환경에서는 트리거 조건이 완전히 충족되지 않았거나 페이로드 길이가 부족할 수 있기 때문입니다.
트리거 요청 후, PoC는 1초간 대기한 후 follow_up(base)를 호출하여 다시 루트 경로 /에 접근합니다.
이 단계의 목적은 오버플로우 자체를 증명하는 것이 아니라, NGINX가 "worker crash 후 master에 의해 재시작되는" 특징을 보이는지 판단하는 것입니다.
트리거 요청 연결이 비정상적으로 종료되었으나, 이후 /에 접근하면 200 또는 다른 정상 HTTP 상태 코드가 반환된다면, 서비스 전체가 다운된 것이 아니라 단일 worker 프로세스가 충돌했다가 복구된 것에 가깝습니다.
트리거 후 서비스가 장기간 도달 불가능한 경우는 전체 서비스 중단, 컨테이너 충돌 또는 네트워크 이상일 수 있으며, 이러한 결과는 CVE-2026-9256 성공 트리거와 직접적으로 동일시할 수 없습니다.
따라서 현재 PoC의 판단 기준은 원격에서 관찰 가능한 worker crash이며, 단순한 "서비스 불가"가 아닙니다.
PoC에서 가장 중요한 안정성 검증은 keepalive_probe(host, port, rounds=5, plus_count=4096)입니다.
requests를 사용하지 않고, 직접 socket.create_connection을 사용하여 TCP 연결을 설정하고, 동일한 keep-alive 연결에서 연속으로 세 개의 요청을 보냅니다.
첫 번째 요청은 일반 요청입니다:
GET / HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
이 요청은 현재 연결이 사용 가능한지 확인하고, 가능한 한 이후 트리거 요청이 동일한 연결에 도달하도록 합니다.
두 번째 요청은 트리거 요청입니다:
GET /api/++++++++++++++++++++++++++++++++... HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
이 요청이 worker crash를 트리거하면, 해당 worker가 유지하는 keep-alive 연결이 직접 끊어질 가능성이 높습니다.
세 번째 요청은 다시 일반 요청입니다:
GET / HTTP/1.1
Host: 127.0.0.1
Connection: close
세 번째 요청에 여전히 응답이 오면 연결이 트리거 요청으로 인해 중단되지 않은 것이므로, 이번 라운드에서는 worker crash가 아닌 것으로 간주합니다.
세 번째 요청 전송 실패, 데이터를 읽을 수 없거나 연결이 이미 닫힌 경우 다음으로 기록합니다:
keepalive connection dropped
PoC는 기본적으로 5라운드를 반복합니다. 여러 라운드를 반복하는 의미는 우발적인 네트워크 오류로 인한 오탐을 줄이기 위함입니다. 5라운드 중 여러 번 keep-alive 연결이 끊어지고, 이후 서비스가 여전히 응답을 복구한다면 원격 측 증거가 더 충분해집니다.
PoC의 최종 판단은 세 단계로 나뉩니다.
첫 번째 단계: 취약점 확인.
조건:
crash_count > 0 and recovered == True
즉, keep-alive 탐지에서 최소 한 번 연결 끊김이 감지되고, 후속 일반 요청으로 서비스가 응답을 복구했음이 입증된 경우입니다. 스크립트 출력:
VULNERABILITY CONFIRMED - CVE-2026-9256 style crash behavior
Impact confirmed: worker crash / denial of service
RCE is not proven by this script
이는 현재 환경이 CVE-2026-9256 스타일의 worker crash 동작을 보이지만, 원격 코드 실행을 증명하지는 않음을 나타냅니다.
두 번째 단계: 의심됨.
조건:
kind == "connection_error" and recovered == True
즉, 주요 트리거 요청에서 연결 끊김이 발생하고 이후 서비스가 복구되었지만, keep-alive probe가 worker crash를 안정적으로 확인하지 못한 경우입니다. 스크립트는 VULNERABILITY SUSPECTED를 출력합니다.
이 경우 이상 현상이 있지만 증거가 충분히 안정적이지 않으므로, 서버 측 error.log, core dump, 컨테이너 로그 또는 디버거를 통해 추가 확인이 필요합니다.
세 번째 단계: 미확인.
안정적인 keep-alive 연결 끊김도, 트리거 연결 비정상 및 서비스 복구 조합도 없으면 스크립트는 다음을 출력합니다:
VULNERABILITY NOT CONFIRMED
이것이 반드시 대상에 절대 취약점이 없다는 것을 의미하지는 않습니다. 경로가 rewrite에 적중하지 않았거나, 페이로드 길이가 부족하거나, 문자 선택이 맞지 않거나, 대상 버전이 이미 패치되었거나, 전방 프록시가 URI를 변경했거나, 현재 스크립트가 HTTPS에 적응하지 못했을 수 있습니다.
스크립트 실행 흐름은 다음과 같이 요약할 수 있습니다:
/에 요청하여 대상 서비스 활성 여부를 확인합니다./api/test에 요청하여 예시 rewrite 경로가 활성화되어 있는지 확인합니다./api/에 4096개의 +를 추가한 긴 URI 트리거 요청을 전송합니다./에 요청하여 worker가 복구되었는지 확인합니다.로컬 실습 환경 예시:
python3 CVE-2026-9256-poc.py http://127.0.0.1:19321
또는:
python3 CVE-2026-9256-poc.py 127.0.0.1 19321
성공적으로 트리거되면 일반적인 출력은 다음과 같습니다:
[+] Connection dropped during trigger request
[+] Worker is responding after trigger (HTTP 200)
round 1: worker likely crashed (keepalive connection dropped)
round 2: worker likely crashed (keepalive connection dropped)
...
[+] VULNERABILITY CONFIRMED - CVE-2026-9256 style crash behavior
[+] Impact confirmed: worker crash / denial of service
[*] RCE is not proven by this script
이러한 출력은 원격 측에서 비교적 안정적인 worker crash 증거가 관찰되었음을 의미합니다.
이 PoC의 보안 경계는 비교적 명확합니다.
첫째, crash 검증만 수행하며 RCE 익스플로잇을 수행하지 않습니다.
둘째, 힙 스프레이, ROP, ASLR 우회, 셸코드 또는 명령 실행 로직을 구성하지 않습니다.
셋째, 성공 기준은 worker 연결 끊김 및 서비스 복구이며, 셸 획득이나 파일 읽기가 아닙니다.
넷째, 로컬 재현, 취약점 검증, IDS/IPS 규칙 구성 및 패치 전후 비교 테스트에 적합합니다.
보안성을 더 강화하려면 다음 제한을 추가할 수 있습니다:
127.0.0.1, localhost, 사설 주소 또는 명시적으로 승인된 실험 네트워크 세그먼트에만 접근 허용.--plus-count 매개변수를 추가하여 기본적으로 너무 큰 페이로드를 전송하지 않도록 함.--route 매개변수를 추가하여 사용자가 트리거 경로를 명시적으로 지정할 수 있도록 하고, /api/를 고정하지 않음.--rounds 매개변수를 추가하여 keep-alive 탐지 횟수를 제어.--print-request 디버그 매개변수를 추가하여 실제 전송된 HTTP 요청을 출력하고 패킷 캡처 결과와 비교 가능하도록 함.PoC 유도 관점에서 탐지 규칙은 /api/에만 집중해서는 안 됩니다. /api는 취약점 고정 경로가 아니라 현재 실습 환경의 예시일 뿐이기 때문입니다. 실제로 더 가치 있는 탐지 포인트는 다음과 같아야 합니다:
+, 또는 +, &, %, ?, # 등의 특수 문자가 혼합되어 나타남).규칙이 /api/++++로만 고정되면 현재 PoC와 현재 실습 환경만 커버됩니다. 더 일반적인 공격 트래픽을 커버하려면 "긴 URI + 다량의 특수 문자 고밀도 출현 + HTTP 요청 방향 + NGINX rewrite 위험 경로"를 중심으로 특징을 추출해야 합니다.
동시에, 합법적인 비즈니스에서도 긴 URL이나 많은 인코딩 문자가 존재할 수 있으므로, 규칙은 길이 임계값, 문자 밀도, 반복 횟수 및 경로 컨텍스트를 통해 오탐을 줄여야 합니다. 비교적 안정적인 탐지 방향은 다음과 같습니다:
긴 URI
+
NGX_ESCAPE_ARGS에서 이스케이프 확장될 수 있는 다량의 특수 문자
+
요청 방향 to_server
+
NGINX rewrite 관련 노출 면
단순 탐지:
/api/++++
Suricata / Snort 규칙의 경우, 현재 공개 PoC만 커버하려면 연속된 +를 강력한 특징 중 하나로 사용할 수 있습니다. 변종을 커버하려면 특수 문자 범위를 PCRE에 포함해야 합니다(예: +, %, #, &, ? 및 기타 이스케이프 확장 가능 문자). 그러나 이러한 규칙은 오탐 가능성도 더 높으므로 urilen, 문자 반복 임계값, 경로 제약 및 NGINX 자산 범위와 함께 사용해야 합니다.
CVE-2026-9256의 PoC 유도에서 중요한 것은 고정된 취약점 경로를 찾는 것이 아니라, 먼저 취약점 트리거 조건을 이해하는 것입니다: 취약한 rewrite 설정, 겹치는 캡처 그룹, 여러 캡처 변수 참조, 그리고 rewrite 처리 결과를 비정상적으로 확장시킬 수 있는 특수 URI 입력.
현재 스크립트가 /api/에 4096개의 +를 선택한 이유는 해당 경로가 현재 재현 환경의 rewrite 규칙을 적중시킬 수 있고, 많은 +가 안정적으로 긴 입력 부하를 생성하기 때문입니다. 스크립트는 RCE를 구현하지 않으며, 연결 끊김, 서비스 복구 및 keep-alive 다중 라운드 연결 끊김을 통해 worker crash를 증명합니다.
동시에 +는 가장 안정적이고 전송하기 쉬운 기본 문자일 뿐, 유일하게 트리거 가능한 문자는 아닙니다. NGX_ESCAPE_ARGS 모드에서 %XX로 확장되는 모든 문자는 원리 분석 및 보호 규칙 고려 대상에 포함되어야 합니다. 더 정확한 이해는 다음과 같아야 합니다: 긴 URI에서 이스케이프 확장 가능한 문자가 밀집하여 나타나고, 취약한 rewrite 캡처 및 replacement 처리를 거쳐 길이 계산과 실제 쓰기가 불일치하여 결국 worker crash 또는 더 심각한 메모리 손상을 초래합니다.