CYBER RESEARCH

Matias QuirozJanuary 9, 2025 6 minute read

CVE-2024-44771 - Stored Cross-site Scripting (XSS) in BigId PrivacyPortal v.179

A Stored XSS vulnerability in BigID PrivacyPortal v.179 lets authenticated users inject JavaScript via the label form parameter in report templates, enabling session hijacking, unauthorized user actions, and other malicious actions. This blog details the discovery process, obstacles encountered, exploitation, impact analysis, recommendations for the vendor, and analysis of the patch provided.

Discovered by: Matias Quiroz, Security Researcher with contributions from Mark Wuergler and Anibal Irrera of Appgate’s Threat Advisory Services, also known as Immunity Inc.

The Discovery: Stored Cross-Site Scripting (XSS) in report templates via label parameter

In December 2023, during a penetration test conducted by Appgate’s Threat Advisory Services (TAS) for the BigID PrivacyPortal application, The TAS team found that it was possible to inject JavaScript code into form templates, particularly in the label field, resulting in a stored XSS vulnerability.

This discovery indicated that persistent, or stored cross-site scripting (XSS), vulnerabilities allow an attacker or a malicious user to inject arbitrary scripts into rendered web pages of unknowing victims. This allows the attacker to hijack control or take over the victim’s user experience, which can lead to session hijacking (stealing the user’s active session). The hijacked session can then initiate actions that appear to be performed by the victim, including adding the attacker as a user to the system, stealing session information, modifying settings, etc. The attacker can also set up sophisticated phishing campaigns or undertake other unwanted behaviors:

Obstacle #1: Client-side validations for malicious (script-based) input

Values for the vulnerable label parameter do not seem vulnerable at first because the client-side logic for validations of this input prevents entering characters commonly used in scripting attacks. For example, characters such as < and > were not permitted as a precaution against injection attacks.

Overcoming Obstacle #1: Bypass client-side validations and send malicious input directly to the API

The server-side logic that accepts the label parameter does not perform the same validations on input as the client-side logic; thus, the integrity of the payloads in the request are controlled and scrutinized by logic that can be bypassed by the attacker simply by sending the payload directly to the API.

However, in this case, the backend did in fact perform input validations, restricting the use of certain attack payloads but the client-side and server-side validations were not the same. This difference in behavior became part of the attack but presented a new obstacle to overcome to achieve a successful cross-site scripting attack.

Obstacle #2: Server-side validations modifying and removing malicious input

Appgate’s TAS team observed that the backend would remove the value of the src parameter and entire event handlers. This is a good practice and a preventative measure against cross-site scripting types of attacks.

Input sent directly to API Result after backend validations
<img src=x onerror=alert(1)> <img src=>

In some cases, when the server-side logic securely and accurately validates the input and strips out unnecessary, unexpected, unauthorized, or other malicious input, the attack cannot proceed further, and the attacker would move on to another exploitable condition. In this instance, though, Appgate’s TAS analysts found a bypass for the second obstacle.

Overcoming Obstacle #2: Objects and encoding

Operating under the assumption that the server-side filters and validations were triggering on known-malicious HTML/JavaScript, TAS analysts attempted to construct a payload that would trick the filters into accepting the malicious content as safe. For this, the HTML <object> was used because it allows encoding of its contents.

For this example, we take the previous XSS attack that was blocked by the server-side filters and encode it using base64:

Plaintext Attack Payload Encoded Attack Payload for Object Value
<img src=x onerror=alert(1)> PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==

Putting it all together, the testing payload would be constructed like so:

Final Attack Object Value
<object data="text/html,base64,PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg=="></object>

After sending this attack payload, the second obstacle was cleared. But now, the attacker would face the third and final obstacle: a Content Security Policy (CSP) blocking this type of in-line execution.

Obstacle #3: Content Security Policy

BigID PolicyPortal utilizes a CSP configuration typically deployed to prevent unauthorized in-line scripts and external sources from rendering and executing within the session (by acting much like an allow list to dictate which scripts are allowed to execute and which should be blocked). Only scripts granted permission in the policy are allowed to execute, and in this case, only the following domains are allowed to execute:

The knowledge of how to bypass all previous preventative measures and execute arbitrary scripts in the context of the users’ session with the object encoding bypass means nothing without a bypass for the CSP. The CSP limits which domains can execute scripts. So, the next phase is to determine if there are domains that have scripting capabilities.

Overcoming Obstacle #3: Abusing trusted domains in the Content Security Policy

After researching content hosted by the trusted domains in the CSP, Appgate Threat Advisory analysts found two of the four trusted domains that could host malicious content to achieve XSS:

  • Google.com (using JSONP functionality)
  • Gstatic.com (hosting vulnerable versions of AngularJS)

CSP Bypass #1 - Abusing trust between Google.com and the Content Security Policy

As a result of the comprehensive investigation, it was determined that it was possible to insert a payload into the label parameter to trigger an alert on the user interface by using Google’s JSONP functionality. The details are as follows:

Putting It All Together: Proof of concept, “Exploit Payload” example #1

Plaintext PoC Exploit Payload
<script src="https://www.google.com/complete/search?client=chrome&q=immunity&callback=alert#1"></script>
Encoded Exploit PoC Payload (Overcoming all Obstacles)
<object data="text/html,base64,PHNjcmlwdCBzcmM9Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vY29tcGxldGUvc2VhcmNoP2NsaWVudD1jaHJvbWUmcT1pbW11bml0eSZjYWxsYmFjaz1hbGVydCMxIj48L3NjcmlwdD4="></object>

To replicate this attack, the attacker will send the payload to the API, as follows:

Figure 1: Sending the PoC exploit payload to the API in the vulnerable label parameter.

The malicious payload will then be embedded persistently in the rendered HTML and executed in the context of all victim users’ active BigID Privacy Portal Session:

Figure 2: The exploit PoC Payload is now embedded in the form of malicious <script> tags in the BigID webpage. All viewers of this page will execute the attacker's script.

 

Figure 3: Overcoming all obstacles to achieve a successful XSS attack PoC using payload from CSP Bypass #1.

Putting It All Together: CSP Bypass #2 - Abusing trust between gstatic.com and the Content Security Policy

In theory, it would also be possible to abuse the trust of gstatic.com in the CSP by loading a vulnerable version of AngularJS to achieve persistent XSS, but the team did not have enough time to pursue this approach. Even with the time constraints, the team did, however, receive evidence that the method would work by triggering an exception (indicating that the script did execute and the obstacles and CSP were successfully bypassed, although the script itself threw an exception). With enough time, the scripting error will ultimately be fixed, and this will be another path an attacker can take to launch a successful CSP bypass and XSS attack.

Proof of Concept Exploit Payload Example #2:

Plaintext PoC Exploit Payload

<script src="https://www.gstatic.com/fsn/angular_js-bundle1.js">

</script><div ng-app ng-csp><div ng-focus=“x=$event;” id=f tabindex=0>foo</div><div ng-repeat="(key, value) in x.view"><div ng-if="key == 'window'"></div></div></div>

Encoded Exploit PoC Payload (Overcoming all Obstacles)
<object data="text/html,base64,PHNjcmlwdCBzcmM9Imh0dHBzOi8vd3d3LmdzdGF0aWMuY29tL2Zzbi9hbmd1bGFyX2pzLWJ1bmRsZTEuanMiPjwvc2NyaXB0Pgo8ZGl2IG5nLWFwcCBuZy1jc3A+PGRpdiBuZy1mb2N1cz3igJx4PSRldmVudDvigJ0gaWQ9ZiB0YWJpbmRleD0wPmZvbzwvZGl2PjxkaXYgbmctcmVwZWF0PSIoa2V5LCB2YWx1ZSkgaW4geC52aWV3Ij48ZGl2IG5nLWlmPSJrZXkgPT0gJ3dpbmRvdyciPjwvZGl2PjwvZGl2PjwvZGl2Pg=="></object>

The above PoC payload will successfully pull down a vulnerable version of AngularJS from gstatic.com and then the trigger will be embedded in the victim’s session:

Figure 4: The malicious PoC successfully loaded into the victim's session.

In its current state, the PoC will cause an exception, but this still demonstrates that the script executed and bypassed all obstacles and CSP policies.

Figure 5: Another view of the malicious AngularJS is loaded into the victim's browser session.

Figure 6: Even though the PoC is incomplete and triggers an exception, it still demonstrates that the attack path is valid and bypasses all intended protections.

Original Remediation Suggestion

The application has undergone some keyword sanitization, but not enough to prevent XSS exploitation. Appgate’s TAS team recommends the following:

  • Sanitize all user input on the frontend and backend, and correct encoding of HTML special characters before they are displayed to the user on the frontend.
  • Perform a correct configuration of the CSP protection following the OWASP guidelines.
  • Make it impossible to import code from public sites when it isn’t necessary. If it is necessary to import public modules, directly reference necessary scripts using the sha256 flag in the CSP configuration.

Vendor Remediation

One month following delivery of the penetration test report on BigId/PrivacyPortal by Appgate’s TAS team, a patch was generated and deployed to solve the input sanitization problem that allowed malicious attackers to exploit the XSS vulnerability reported here. The patch created the following regular expression that filtered the type of input, thus removing the ability to inject characters that can be used in these types of attacks:

^ [+\\p{L}\\s\"'`@().:,/&#0-9-_\\{\\{\\p{Pd}!\u00A0\u2019\uFF08\uFF09\uff0c\u3001\u3002\u30FB\u30A0\uFF1D]{0,}$

 Against the following properties of the form field:

  • Field Title
  • Hint Value
  • Default Value
  • Tooltip Value

On 01/25/2024, the Appgate TAS team performed a retest on BigID PrivacyPortal to confirm that the solution implemented in the patch was sufficient to prevent the XSS exploit under the same conditions as demonstrated in the original finding.

Timeline
12/05/2023Discovery of XSS in BigID Privacy Portal v179.
12/05/2023Discovery of XSS in BigID Privacy Portal v179.
12/07/2023Discovery of CSP Bypass in BigID Privacy Portal v179.
01/25/2024Vendor provided patch.
01/25/2024Retest of the original issue was conducted.
01/25/2024The issue was remediated by regular expression input validation in the patch provided.
04/15/2024Responsible disclosure: Contact with the vendor.
04/15/2024Responsible disclosure: BigID's (PSIRT) Product Security Incident Response Team responded.
04/25/2024Responsible disclosure: New contact with the vendor. No response.
05/24/2024Responsible disclosure: New contact with the vendor. No response.
08/14/2024Full disclosure: CVE submission.
09/06/2024Full disclosure: CVE assigned (“reserved” status until public post has been made).
01/09/2025Full disclosure: Releasing technical details on appgate.com.

Receive News and Updates From Appgate