In our continuous effort to help secure open-source projects and improve our Clean Code solution, we regularly scan open-source projects via SonarCloud and evaluate the findings. When scanning the popular C# Content Management System Squidex, we were faced with the following finding reported by SonarCloud:
SonarCloud detected that this event listener does not verify the event’s origin. This doesn’t feel like a big deal, does it?
As we will see in this blog post, it is a big deal and allows attackers to fully take over a vulnerable Squidex instance by tricking a user into clicking on a malicious link. The blog post will detail how attackers can leverage this seemingly minor issue of a missing origin check to achieve code execution and explain how you can discover similar issues in your own code.
Impact
Squidex version 7.8.2 and below is prone to Cross-Site Scripting (XSS) vulnerability via event listener (CVE-2023-46252). Attackers can combine this vulnerability with an authenticated Arbitrary File Write (CVE-2023-46253) to gain remote code execution (RCE) on a Squidex instance:
Both vulnerabilities were fixed with Squidex version 7.9.0.
Technical Details
In this section, we describe the technical details of both of these vulnerabilities.
XSS due to Missing Origin Check (CVE-2023-46252)
Before we dive into the technical details of this vulnerability, let’s see how we were able to discover it within seconds. On SonarCloud, an application can quickly be analyzed by adding the corresponding GitHub repository. For public repositories, this is even free, regardless of their size or language. Once the repository is added, SonarCloud starts to analyze the code and we can inspect the findings a few seconds later:
Let’s have a look at the reported eventListener
function, which is registered in the SquidexFormField
pseudo-class:
Although the event listener checks the source of the event (event.source
), it is indeed missing a check of its origin (event.origin
). Because of this as well as the lack of X-Frame-Options and Content-Security-Policy, a malicious website can include the Squidex website in an iframe and use the postMessage method to trigger the execution of the event listener in the context of the included Squidex website:
Looking at the different type
values attackers can submit this way, the valueChanged
type caught our attention. When the SquidexFormField
receives a message with this type, the value
property is updated and the function raiseValueChanged
is called:
The raiseValueChanged
function invokes the valueHandler
callback, which can be registered via the onValueChanged
function:
The SquidexFormField
class is for example used in the editor-editorjs.html file, which can be accessed via the public wwwroot
folder. It uses the onValueChanged
method to register a callback function, which passes the value provided from the message event to the editor.render
function:
The editor.render
function used here is part of the editorjs npm package. Passing an attacker-controlled value to this function introduces a Cross-Site Scripting (XSS) vulnerability. Since the registered message event listener in editor-sdk.js
does not verify the origin of the received message, attackers can include the editor-editorjs.html
page in an iframe and send a message to it in order to trigger the execution of arbitrary JavaScript code. This did not only affect self-hosted Squidex instances but also Squidex Cloud:
When determining the impact of this vulnerability, we identified a second vulnerability. This vulnerability is an authenticated file write, which attackers can combine with the XSS vulnerability to execute arbitrary code.
Arbitrary File Write (CVE-2023-46253)
Squidex allows users with the squidex.admin.restore
permission to create and restore backups. Part of these backups are uploaded assets. For each asset, the backup zip archive contains a .asset
file with the actual content of the asset as well as a related AssetCreatedEventV2
event, which is stored in a JSON file (4.json
):
Amongst other things, the JSON file contains the event type (AssetCreatedEventV2
), the ID of the asset (46c05041-9588-4179-b5eb-ddfcd9463e1e
), its original filename (test.txt
), and its file version (0
):
When a backup with this event is restored, the corresponding asset needs to be re-created. This is done by:
- determining the name of the
.asset
file in the zip archive, - reading its content, and
- storing the content in the filestore (by default
FolderAssetStore
).
However, the filename used to store the content in the filestore is populated with the ID of the asset. Since this asset ID is taken from the provided JSON file, attackers can set this to an arbitrary value when restoring a backup. This allows attackers to insert a path traversal sequence (../
) and write the .asset
file from the backup zip archive to an arbitrary location on the file system.
The by-default appended file version, which is not a string
but a long
, would usually restrict the name of the written file. However, attackers can overcome this by setting the fileVersion
to -1
, which makes the application omit the file version:
Thus attackers can fully control the name and the content of the file written. This ability can be turned into arbitrary code execution by, for example, overwriting the dotnet-gcdump.dll
file and triggering gcdump
via the /api/diagnostics/gcdump
endpoint.
In summary, the seemingly minor issue of a missing origin check can be leveraged by attackers to craft a malicious link, which triggers an XSS attack to gain remote code execution via this additional arbitrary file write vulnerability.
Patch
The XSS vulnerability (CVE-2023-46252) was fixed by adding the missing origin verification. Since there are valid use cases for certain origins to send messages to a Squidex website, a dynamic configuration was introduced:
The arbitrary file write vulnerability (CVE-2023-46253) was fixed by preventing a path traversal attack. An additional check was added to the FilePathHelper
class, which ensures that files are only created within the intended destination folder:
Timeline
Date | Action |
2023-10-11 | We report all issues to the maintainers. |
2023-10-26 | We ask the maintainers for an update. |
2023-10-26 | The maintainers confirm the issues. |
2023-10-27 | We help the maintainers to fix both issues. |
2023-11-08 | The maintainers release the patched version 7.9.0. |
Summary
In this blog post, we outlined the importance of verifying an event’s origin. We have seen how the absence of a check like this can quickly result in a severe impact. For Squidex, attackers could leverage the missing check to craft a malicious link, which triggers an XSS attack to gain remote code execution via an additional arbitrary file write vulnerability.
From a developer’s point of view, a check like this can be easily forgotten because it needs to be consistently applied to all event listeners throughout the whole code base. That’s where our SAST-based Clean Code solution provides irreplaceable benefits. By leveraging the analysis power of SonarQube or SonarCloud you can ensure that your code stays consistent, intentional, adaptable, and responsible. You don’t even want to introduce issues in the first place? With SonarLint you can follow a Clean as You Code approach right from your IDE of choice.
At last, we would like to thank the Squidex maintainers for confirming our findings and working together with us on a patch to fix these. Thank you!
Related Blog Posts
- pfSense Security: Sensing Code Vulnerabilities with SonarCloud
- Unzipping Dangers: OpenRefine Zip Slip Vulnerability
- Pimcore: One click, two security vulnerabilities
- OpenEMR - Remote Code Execution in your Healthcare System