
Static config scanner that flags nginx configs vulnerable to the complex_value two-pass capture-clobbering bug (regex map + regex capture → heap overflow / info leak).
complex_value 2단계 캡처 클로버링(capture-clobbering) 버그 클래스(F5/nginx SIRT 권고, 2026년 7월)에 취약한 nginx 설정을 표시하는 읽기 전용 정적 스캐너입니다. 설정을 파싱하여 취약한 패턴을 이유 및 위치와 함께 보고합니다. 아무것도 익스플로잇하지 않으며 실행 중인 서버를 건드리지 않습니다.
단일 파일, 표준 라이브러리만 사용, Python 3.6+.
취약점 전체 해설: https://cyberstan.co.uk/nginx-rce/
nginx는 많은 지시문 값을 두 단계로 구성합니다. LEN 단계는 길이를 측정하고 버퍼를 할당하며, 그다음 VALUE 단계가 그 버퍼에 기록합니다. 정규식 캡처($1부터 $9, 또는 명명된 (?P<name>...))는 요청별 공유 상태에서 읽힙니다. 정규식을 매치 키로 사용하는 map은 해당 변수가 평가되는 순간 새로운 PCRE 매치를 실행하며, 그 매치가 공유 캡처 상태를 덮어씁니다. 캡처가 LEN 단계에서 측정된 후 VALUE 단계가 그 캡처를 다시 쓰기 전에 정규식 map이 실행되면, 두 단계가 서로 불일치하게 됩니다:
map 입력이 공격자의 영향을 받을 수 있는 경우($request_body, $http_*, $arg_*, $uri, $ssl_preread_server_name 등) 두 방향 모두 원격으로 트리거 가능합니다.
스캐너는 다음 조건이 모두 하나의 2단계 버퍼에, 익스플로잇 가능한 순서로 들어올 때 location 또는 server를 표시합니다:
location ~, server_name ~, rewrite,
if (... ~ ...), 또는 캡처 그룹이 있는 정규식 map.~ 또는 ~* 정규식 매치 키를 가진 map(http 또는 stream)으로,
그 출력 변수로 참조되는 것.return, set, add_header, proxy_method,
proxy_pass, rewrite, index 등): 두 참조가 같은 값 안에 있음.proxy_set_header, proxy_set_body,
fastcgi_param, scgi_param, uwsgi_param, grpc_set_header): 이들은
요청마다 계열 전체에 대해 하나의 버퍼를 구성하므로, 두 참조가 같은
location 내의 서로 다른 지시문에 있을 수 있음.# scan a single config (follows include directives by default)
python3 nginx_capture_clobber_scan.py /etc/nginx/nginx.conf
# scan a directory (uses nginx.conf if present, else all *.conf)
python3 nginx_capture_clobber_scan.py /etc/nginx/
# scan several roots
python3 nginx_capture_clobber_scan.py site-a.conf site-b.conf
# machine-readable output
python3 nginx_capture_clobber_scan.py /etc/nginx/nginx.conf --json
# do not expand include directives
python3 nginx_capture_clobber_scan.py /etc/nginx/nginx.conf --no-includes
| 옵션 | 효과 |
|---|---|
--json | 텍스트 대신 JSON 보고서를 출력합니다. |
--no-includes | include 지시문을 따르지 않습니다. |
| 코드 | 의미 |
|---|---|
0 | 취약한 구성이 발견되지 않았습니다. |
1 | 하나 이상의 취약한 구성이 발견되었습니다. |
2 | 사용 오류 (경로가 제공되지 않았거나 찾을 수 없음). |
취약한 구성은 0이 아닌 코드로 종료되므로 CI에서 사용할 수 있습니다:
python3 nginx_capture_clobber_scan.py /etc/nginx/nginx.conf || echo "review needed"
텍스트 모드는 각 발견 항목에 대해 파일과 줄, 둘러싸는 범위, 싱크 지시문, 관련된 캡처 및 맵 변수, 트리거링 맵, 그리고 한 줄짜리 이유를 출력합니다. 정리된 섹션은 안전한 순서의 공존 항목을 나열합니다. --json은 다음을 생성합니다:
{
"vulnerable": true,
"findings": [
{
"file": "/etc/nginx/conf.d/api.conf",
"line": 12,
"scope": "location ~ ^/api/(.+)$",
"directive": "proxy (family buffer)",
"captures": ["$1"],
"map_vars": ["$is_bot"],
"triggers": ["$is_bot <- regex-map on $http_user_agent [nginx.conf:30]"],
"reason": "..."
}
],
"cleared_safe_order": [],
"regex_maps": [],
"missing_includes": []
}
ngx_http_script_check_length())를 추가하여 VALUE 패스가 할당된 버퍼를 넘어 쓰는 것을 방지하고, 반환되는 문자열 길이를 LEN 패스 측정값이 아닌 실제로 기록된 바이트 수로부터 계산함으로써 오버플로와 정보 유출 양방향을 모두 차단합니다.map 변수를 $1~$9 또는 명명된 캡처 참조와 함께 참조하지 마십시오.(?P<name>...) 그룹을 여러 정규식 map에 걸쳐 재사용하지 마십시오.proxy_set_header 또는 fastcgi_param 계열에 함께 두지 마십시오.set된 변수가 생성하는 값은 해석할 수 없습니다.include 대상(예: 로컬에 존재하지 않는 절대 경로)은 조용히 건너뛰지 않고 missing_includes 아래에 보고됩니다. 전체 범위를 확보하려면 구성이 해석되는 호스트에서 실행하십시오.취약점 분석 및 익스플로잇 체인: https://cyberstan.co.uk/nginx-rce/