Add auxiliary scanner module for Citrix NetScaler memory leak (CVE-2026-3055)#21204
Add auxiliary scanner module for Citrix NetScaler memory leak (CVE-2026-3055)#21204sfewer-r7 wants to merge 7 commits intorapid7:masterfrom
Conversation
documentation/modules/auxiliary/scanner/http/citrix_netscaler_cve_2026_3055.md
Outdated
Show resolved
Hide resolved
Co-authored-by: jheysel-r7 <Jack_Heysel@rapid7.com>
There was a problem hiding this comment.
Pull request overview
Adds a new Metasploit auxiliary scanner module and accompanying documentation to detect/exploit Citrix NetScaler/ADC CVE-2026-3055 (SAML IdP configuration) by triggering a memory leak and extracting session cookies from the leaked data.
Changes:
- Introduces
auxiliary/scanner/http/citrix_netscaler_cve_2026_3055scanner module to trigger the leak and search forSESSID/NITRO_SKandNSC_AAACcookies. - Implements
checklogic and reporting for “appears vulnerable” vs. “safe/unknown” outcomes. - Adds user documentation with verification steps and example output.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| modules/auxiliary/scanner/http/citrix_netscaler_cve_2026_3055.rb | New scanner module that triggers the overread, counts leaked bytes, and searches leaked memory for session cookies. |
| documentation/modules/auxiliary/scanner/http/citrix_netscaler_cve_2026_3055.md | New module documentation with usage steps and scenario examples. |
| return Exploit::CheckCode::Unknown("Unexpected response code #{res.code}") unless res.code == 302 | ||
|
|
||
| cookies = res.get_cookies | ||
|
|
||
| return Exploit::CheckCode::Safe('Response has no cookies') if cookies.empty? | ||
|
|
||
| return Exploit::CheckCode::Safe('Response has no NSC_TASS cookie') unless cookies.include? 'NSC_TASS=' | ||
|
|
||
| Exploit::CheckCode::Appears('Response contains an NSC_TASS cookie.') |
There was a problem hiding this comment.
check_host currently treats the target as vulnerable purely based on a 302 + presence of an NSC_TASS cookie. The module later notes that patched systems may still return NSC_TASS but not as base64; this check will likely produce false positives. Consider validating that the NSC_TASS value is plausibly base64/leaked data (e.g., round-trip base64 decode/encode or other lightweight validation) before returning CheckCode::Appears.
There was a problem hiding this comment.
I think this Copilot suggestions is based of some misleading comments in the source, I reworked the comment to better reflect things: fc01284
| bytes = Rex::Text.decode_base64(v) | ||
|
|
||
| # A patched system will not return a base64 encoded NSC_TASS value, so if we can decode it, it's a strong | ||
| # indicator of a vulnerable system. Even if the memory we leak doesn't contain session cookies. | ||
| leaked_data_count += bytes.bytesize | ||
|
|
There was a problem hiding this comment.
Rex::Text.decode_base64 does not inherently validate that the input is actually base64. If a patched appliance returns a non-base64 NSC_TASS value, this code may still “decode” to non-empty bytes and increment leaked_data_count, causing a false vulnerable result. Add explicit validation that the cookie value is valid base64 (or that the decoded data matches expected leaked-memory structure) before counting bytes / reporting vulnerability.
modules/auxiliary/scanner/http/citrix_netscaler_cve_2026_3055.rb
Outdated
Show resolved
Hide resolved
| bytes.scan(/SESSID=([0-9a-f]{32})/i).each do |match| | ||
| sessid_value = match.first | ||
|
|
||
| next if found_cookies.include?("SESSID=#{sessid_value}") | ||
|
|
||
| found_cookies.add("SESSID=#{sessid_value}") | ||
|
|
||
| nitro_sk_match = bytes.match(/NITRO_SK=([^\s;,]+)/i) | ||
|
|
||
| if nitro_sk_match | ||
| nitro_sk_value = nitro_sk_match[1] | ||
|
|
||
| print_good("#{peer} - Leaked cookie pair: SESSID=#{sessid_value}; NITRO_SK=#{nitro_sk_value}") | ||
| else | ||
| print_good("#{peer} - Leaked cookie: SESSID=#{sessid_value}") | ||
| end |
There was a problem hiding this comment.
found_cookies de-duplicates solely on SESSID=<value>, so if the first leak contains only SESSID and a later leak contains the corresponding NITRO_SK, the later (more usable) cookie pair will never be reported. Consider tracking whether NITRO_SK has been observed for a given SESSID and emitting an updated pair when it becomes available.
modules/auxiliary/scanner/http/citrix_netscaler_cve_2026_3055.rb
Outdated
Show resolved
Hide resolved
| You can check if the target is vulnerable. THe leaked data is not inspected. Intended to identify | ||
| patched and vulnerable systems. |
There was a problem hiding this comment.
This section says check is intended to identify patched vs vulnerable systems, but the module’s check_host currently only looks for presence of an NSC_TASS cookie (not whether it contains leaked/base64 data). Either strengthen the check logic accordingly or adjust the documentation to clarify that check is only a heuristic and may return false positives.
| You can check if the target is vulnerable. THe leaked data is not inspected. Intended to identify | |
| patched and vulnerable systems. | |
| You can run a heuristic check to see if the target appears vulnerable. The leaked data is not inspected | |
| during this check; it currently only looks for the presence of an `NSC_TASS` cookie and may return false | |
| positives when identifying patched versus vulnerable systems. |
documentation/modules/auxiliary/scanner/http/citrix_netscaler_cve_2026_3055.md
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ignore and report a verbose error if there is unepxected charachters in the value
…cookie values, so rework these comments to better reflect that (Copilot review sugesting fixes off the previous comments).
|
To get a NetScaler appliance into a SAMP IdP configuration suitable for testing, I had Claude reconfigure an appliance and produce these setup steps. This will hopefully be useful for validating the module. (You will need to adjust the VIP based on your local network setup). |
| end | ||
|
|
||
| def run_host(_target_host) | ||
| # We track the number of bytes we leak to report back to teh user and help determine if we triggered the vuln or not. |
There was a problem hiding this comment.
| # We track the number of bytes we leak to report back to teh user and help determine if we triggered the vuln or not. | |
| # We track the number of bytes we leak to report back to the user and help determine if we triggered the vuln or not. |
| end | ||
|
|
||
| # A vulnerable host will return 302, but may occasionally return a 200 error, we test for this and keep | ||
| # going if we see teh 200 error, otherwise we bail out early. |
There was a problem hiding this comment.
| # going if we see teh 200 error, otherwise we bail out early. | |
| # going if we see the 200 error, otherwise we bail out early. |
| next unless k == 'NSC_TASS' | ||
|
|
||
| # Validate an NSC_TASS cookie value is well-formed base64 before attempting to decode it. | ||
| unless v.match?(%r{\A[A-Za-z0-9+/]*={0,2}\z}) |
There was a problem hiding this comment.
| unless v.match?(%r{\A[A-Za-z0-9+/]*={0,2}\z}) | |
| unless v.match?(%r{\A[A-Za-z0-9+/]+={0,2}\z}) |
A valid base64 string contains at least a non-= char
Overview
This auxiliary module exploits CVE-2026-3055, an info leak in Citrix NetScaler (when configured as an SAML IdP). Similar to the other CitrixBleed vulns, we can leak memory and potentially discover session cookies.
This module is based upon the technical analysis published by watchTowr: https://labs.watchtowr.com/please-we-beg-just-one-weekend-free-of-appliances-citrix-netscaler-cve-2026-3055-memory-overread-part-2/
Example
Targeting a vulnerable
NS13.1: Build 59.19.ncinstance which has been configured as a SAML IdP. An admin sessionin the management interface was established separately, so we know that a valid session is available to leak.