비공개 Nginx Rift ASLR 랩, 익스플로잇 체인 및 데모 녹화
CVE-2026-42945에 대한 RCE 개념 증명(PoC)으로, 2008년에 도입된 NGINX ngx_http_rewrite_module의 치명적인 힙 버퍼 오버플로입니다. 이 버그는 rewrite 및 set 지시문을 사용하는 서버에 대해 인증 없이 원격 코드 실행을 가능하게 합니다.
이 포크는 NGINX 오버플로를 일반적인 동일 호스트 LFI/임의 파일 읽기 프리미티브와 결합한 ASLR 우회 체인으로 기존 PoC를 확장합니다. 파일 읽기 프리미티브는 nginx 워커 맵, libc, 그리고 라이브 /proc/<worker>/mem을 복구한 다음, 원격으로 system() 주소와 사용 가능한 힙 대상을 도출하는 데 사용됩니다.
이 랩의 초기 버전은 의도적으로 nginx 워커를 크래시시켜 서비스가 코어 덤프를 쓰도록 만든 다음, 파일 읽기 프리미티브를 통해 해당 코어 덤프를 가져와 파싱하여 힙 대상을 포함한 ASLR 민감 프로세스 상태를 복구했습니다. 이 저장소에서 coreless는 단지 "읽을 수 있는 크래시 코어 덤프가 없다"는 뜻의 약칭일 뿐입니다. 현재 기본 경로는 크래시 코어 의존성을 라이브 procfs 메모리 읽기로 대체하며, 보존된 레거시 core-guided 경로는 여전히 생성된 워커 코어 덤프를 사용합니다.
이 취약점은 다른 세 가지 메모리 손상 문제(CVE-2026-42946, CVE-2026-40701, CVE-2026-42934)와 함께 NGINX 소스를 온보딩(등록)하는 단 한 번의 클릭으로 depthfirst의 보안 분석 시스템에 의해 자율적으로 발견되었습니다.
자신의 코드에서도 이런 문제를 찾고 싶으신가요? **https://depthfirst.com/open-defense**에서 동일한 시스템을 사용해 보세요.
NGINX 스크립트 엔진은 2-pass 프로세스를 사용합니다. 먼저 필요한 버퍼 크기를 계산한 다음 데이터를 복사합니다. is_args 플래그는 rewrite 대체 문자열에 ?가 포함될 때 메인 엔진에 설정되지만, 길이 계산 패스는 새로 0으로 초기화된 하위 엔진에서 실행됩니다. 즉:
is_args = 0을 확인 → 원시 캡처 길이를 반환합니다.is_args = 1을 확인 → NGX_ESCAPE_ARGS와 함께 ngx_escape_uri를 호출하여 이스케이프 가능한 각 바이트를 3바이트로 확장합니다.복사는 공격자가 제어하는 URI 데이터로 크기가 부족한 힙 버퍼를 오버플로합니다. 익스플로잇은 요청 간 힙 펭슈이를 사용하여 인접한 ngx_pool_t의 cleanup 포인터를 손상시키고(POST 본문을 통해 스프레이됨, URI 바이트는 null 바이트를 포함할 수 없으므로), 이를 가짜 ngx_pool_cleanup_s로 리디렉션하여 풀 파괴 시 system()을 호출합니다.
이 버그에 대한 자세한 내용은 기술 문서에서 확인하세요.
| 제품 | 영향 버전 | 수정 버전 |
|---|---|---|
| NGINX Open Source | 0.6.27 – 1.30.0 | 1.31.0, 1.30.1 |
| NGINX Plus | R32 – R36 | R36 P4, R35 P2, R32 P6 |
공급업체 전체 권고문: https://my.f5.com/manage/s/article/K000160932



이 포크는 원래 공개 PoC를 그대로 유지하면서, 보다 현실적인 질문에 초점을 맞춘 두 번째 연구 트랙을 추가합니다:
ASLR이 활성화된 실제 x86_64 Linux VM에서 하드코딩된 Docker/랩 오프셋에 의존하지 않고 이 버그를 악용할 수 있을까요?
이 연구 포크에서의 답변은 가능하지만, 중요한 제약이 있습니다. 작동하는 체인은 ASLR을 비활성화하지 않으며 원래의 하드코딩된 힙/libc 주소를 사용하지 않습니다. 대신 동일 포트 HTTP 접근 가능 프리미티브를 통해 런타임 상태를 도출한 다음, 원격으로 획득한 공개 데이터에서 최종 힙 대상을 선택합니다.
이제 두 가지 ASLR 지원 익스플로잇 트랙이 있으며, coreless 경로가 현재 최고의 PoC로 취급됩니다:
nginx_rifter.py: 깔끔하고 자체 포함된 평가 및 통합 익스플로잇 진입점입니다. 기본 익스플로잇 방식은 이제 coreless /proc/<nginx-worker>/mem 체인입니다.nginx_rifter_core_v2_1.py: 보존된 레거시 core-guided 버전의 nginx_rifter.py입니다. 이전에 VM에서 테스트된 크래시 코어 연구 경로를 재현하는 데 유용하지만 더 이상 선호되는 PoC는 아닙니다.tools/proc_mem_coreless_exploit.py: 초기의 독립형 coreless 연구 하네스입니다. 그 논리는 nginx_rifter.py에 병합되었으며, 이 도구는 원시 실험 재생을 위해 남아 있습니다.대상 토폴로지는 의도적으로 동일 포트입니다:
/api/.../lfi.php?file=.../phpinfo.php현재 coreless proc-mem 경로는 다음의 높은 수준의 단계를 수행합니다:
/proc/<pid>/maps 및 매핑된 libc 파일을 읽습니다.system() 주소를 계산합니다./proc/<worker>/mem에서 매핑된 범위를 읽습니다.레거시 core-guided 경로는 유사한 기본 주소 도출을 수행한 다음, 의도적으로 워커를 크래시시키고, LFI를 통해 생성된 코어 파일을 읽고, 스프레이된 가짜 cleanup 슬롯에 대해 해당 코어를 마이닝합니다. 이는 유용한 연구 교두보였지만, 기본 배포에서는 흔하지 않은 코어 덤프 정책과 파일시스템 권한에 의존합니다.
이것은 원래의 결정적 Docker 데모와 동일하지 않습니다. x86_64 VM 경로는 일반적인 Linux ASLR을 활성화 상태로 두고 실행할 때마다 프로세스별 주소를 다시 계산합니다. Docker coreless 경로도 ASLR을 활성화 상태로 두고 비정상적인 읽기 가능 코어 요구 사항을 제거하지만, 대상 클래스에 대해 검증해야 하는 procfs 권한 동작에 의존합니다.
이 포크는 통제된 연구 랩입니다. ASLR 지원 체인은 보편적인 프로덕션 가정이 아닌 강력한 조건에 의존합니다:
/proc/<pid>/maps, 매핑된 libc 및 큰 매핑 오프셋에서 /proc/<pid>/mem을 읽을 수 있어야 합니다./proc/<pid>/maps, 매핑된 libc 및 생성된 워커 코어를 읽을 수 있어야 합니다.phpinfo()와 /proc/<pid>/maps는 PIE/libc 기본 주소를 복구하기에 충분하지만, 이 익스플로잇에 필요한 정확한 힙 객체/윈도우를 복구하기에는 그 자체로 충분하지 않습니다. 이전 체인은 최종 공개를 위해 읽을 수 있는 크래시 코어를 사용했습니다. 현재 기본 체인은 대신 /proc/<worker>/mem을 사용하는데, 이는 코어 덤프 정책을 변경하지 않고 라이브 워커 메모리를 노출하므로 동일 UID 배포에서 실제 임의 파일 읽기 결과에 더 가깝습니다.
남아 있는 중요한 한계:
/proc/<pid>/mem은 ptrace 게이트가 적용됩니다. Docker 랩과 공식 nginx:stable 이미지 모델에 대한 동일 UID 검사에서는 작동했지만, 기본 procfs 보호 하에서는 다른 UID 앱 프로세스는 실패해야 합니다.현재 깔끔한 진입점은 nginx_rifter.py입니다. 이는 HTTP로 접근 가능한 로컬 파일 읽기 프리미티브가 있는 알려진 취약한 nginx 배포를 승인된 테스터가 평가하는 방식에 더 가깝게 설계된 평가 우선 도구입니다.
초기 데모 러너와 비교하여 nginx_rifter.py는 여러 방식으로 워크플로를 개선합니다:
--exploit가 명시적으로 제공되지 않는 한 크래시 익스플로잇을 실행하지 않습니다.HOST:PORT로 제공되며, 파일 읽기 프리미티브는 --file-read-template을 통해 모듈화됩니다./proc/self/status, /proc/self/maps, 동일 UID 워커 procfs 도달 가능성을 포함하여 LFI 프리미티브에 의존하기 전에 이를 프로파일링합니다.system(), 빌드 ID, 바이너리 해시, OS 세부 정보, proc-mem/core 설정을 발견합니다.rewrite + set 경로 후보에 플래그를 지정합니다.nginx_rifter.py에 통합되어 있습니다. 기본 방식은 coreless proc-mem입니다.현재 nginx_rifter.py는 자체 포함되어 있습니다. 평가 또는 익스플로잇을 위해 더 이상 이전 데모 PoC 버전이나 tools/proc_mem_coreless_exploit.py를 import하거나 셸 아웃하지 않습니다.
이전 core-guided nginx_rifter.py 구현은 nginx_rifter_core_v2_1.py로 보존됩니다.
최신 artifacts/nginx_rifter_v3_coreless_exploit_20260519.gif는 병합된 v3 nginx_rifter.py coreless 익스플로잇 경로를 보여줍니다. demo4.gif는 이전 올인원 core-guided 도구의 평가 및 명시적 익스플로잇 흐름을 보여줍니다. 이전 nginx-aslr-demo.gif는 원래 ASLR 지원 익스플로잇 데모로 남아 있습니다.
Ubuntu 24.04.3 LTS에서 테스트되었습니다.
원래 ASLR 비활성화 Docker 재현:
./setup.sh — 컨테이너를 빌드합니다.docker compose -f env/docker-compose.yml up — 취약한 NGINX 서버를 시작합니다.python3 poc.py --shell — 셸을 획득합니다.로컬 Docker 재현 흐름은 LAB.md를 참조하세요.
레거시 ASLR 지원 VM core-guided 체인:
./nginx_rifter_core_v2_1.py --target <target-host>:19321 --exploit --cmd id --fast
평가 우선 v3 도구:
./nginx_rifter.py --target <target-host>:19321
nginx_rifter.py는 현재 실제 환경 지향 평가자이자 통합 PoC 진입점입니다. 기본 모드는 크래시 익스플로잇 경로를 실행하지 않습니다. HTTP 파일 읽기 프리미티브를 프로파일링하고, 범위 및 바이너리 읽기를 확인하고, OS/nginx/libc를 핑거프린팅하고, nginx 워커와 ASLR 관련 맵을 발견하고, 동일 UID /proc/<worker>/mem 읽기 가능성을 테스트하고, pid/cmdline/config 읽기를 통해 nginx 구성 경로 복구를 시도하고, 취약한 rewrite + set 경로 후보에 플래그를 지정하고, 현재 coreless 체인에 대한 실행 가능성 매트릭스를 출력합니다.
현재 nginx_rifter.py는 자체 포함되어 있습니다. 평가 또는 익스플로잇을 위해 더 이상 이전 데모 PoC 버전이나 독립형 proc-mem 연구 하네스를 import하거나 셸 아웃하지 않습니다.
사용자 정의 LFI/다운로드 형태의 경우:
./nginx_rifter.py --target <target-host>:19321 \
--file-read-template 'http://{host}:{port}/download?path={path_url}{range_query}'
익스플로잇 실행은 명시적입니다:
./nginx_rifter.py --target <target-host>:19321 --exploit --cmd id --fast
# Discovery-only exploit smoke test, no spray/probe
./nginx_rifter.py --target <target-host>:19321 --exploit --derive-only --cmd id