Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2023-41564-research — Detailed analysis and proof-of-concept for CVE-2023-41564, a stored XSS vulnerability in Cockpit CMS <=2.6.3, with code-level root cause and mitigation guidance. | Kitploit
Tools/GitHubGitHub/sota70/cve-2023-41564-research
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubsota70/cve-2023-41564-research

cve-2023-41564-research

Detailed analysis and proof-of-concept for CVE-2023-41564, a stored XSS vulnerability in Cockpit CMS <=2.6.3, with code-level root cause and mitigation guidance.

View Repository
351 year agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2023-41564 Vulnerability Overview

CVE-2023-415641 is a stored XSS vulnerability in the CMS Cockpit (<= v2.6.3).
When a .shtml HTML file is uploaded during file upload, JavaScript is executed the moment the uploaded file is opened.

1: https://nvd.nist.gov/vuln/detail/CVE-2023-41564

Attack Execution Flow

First, we will explain the attack method based on the PoC2 published by the person believed to be the vulnerability reporter.
First, log in to the site with an account that has file upload permissions.
cms login cms assets Then upload an shtml file like the following:

root@kitploit:~

Copy the URL of the uploaded file (Asset). cms link When you access the copied link, the script described in the above HTML is executed. cms xss
2: https://github.com/LongHair00/Mitre_opensource_report/blob/main/CockpitCMS-StoredXSS.md

Specific Occurrence Details

From here, I will explain the results of my further investigation.
The Assets upload process starts with a POST request to the /assets/upload path.
The upload request processing is defined in line 513 of modules/Assets/bootstrap.php.
The code is shown below:

root@kitploit:~
// assets api
$this->module('assets')->extend([

    // omitted
    'upload' => function(string|array $param = 'files', array $meta = [], bool $isUpload = true) {

        $files = [];

        if (is_string($param) && isset($this->app->request->files[$param])) {
            $files = $this->app->request->files[$param];
        } elseif (is_array($param) && isset($param['name'], $param['error'], $param['tmp_name'])) {
            $files = $param;
        }

        $finfo      = finfo_open(FILEINFO_MIME_TYPE);
        $uploaded  = [];
        $failed    = [];
        $_files     = [];
        $assets    = [];

        $allowed   = $this->app->retrieve('assets/allowed_uploads', '*');
        $allowed   = $allowed == '*' ? true : str_replace([' ', ','], ['', '|'], preg_quote(is_array($allowed) ? implode(',', $allowed) : $allowed));
        $max_size  = $this->app->retrieve('assets/max_upload_size', 0);

        $forbiddenExtension = ['bat', 'exe', 'sh', 'php', 'phar', 'phtml', 'phps', 'htm', 'html', 'xhtml', 'htaccess'];
        $forbiddenMime = [
            'application/x-httpd-php', 'application/x-php', 'text/x-php',
            'text/html', 'application/xhtml+xml'
        ];

        if (isset($files['name']) && is_array($files['name'])) {

            $cnt = count($files['name']);

            for ($i = 0; $i < $cnt; $i++) {

                $_file  = $this->app->path('#tmp:').'/'.$files['name'][$i];
                $_mime = $finfo->file($files['tmp_name'][$i]);
                $_isAllowed = $allowed === true ? true : preg_match("/\.({$allowed})$/i", $_file);
                $_sizeAllowed = $max_size ? filesize($files['tmp_name'][$i]) < $max_size : true;

                $extension = strtolower(pathinfo(parse_url($_file, PHP_URL_PATH), PATHINFO_EXTENSION));

                if (!$extension) {
                    $_isAllowed = false;
                }

                // prevent uploading php / html files
                if ($_isAllowed && (
                    in_array($extension, $forbiddenExtension) ||
                    in_array(strtolower($_mime), $forbiddenMime)
                )) {
                    $_isAllowed = false;
                }

                if (!$files['error'][$i] && $_isAllowed && $_sizeAllowed && ($isUpload ? move_uploaded_file($files['tmp_name'][$i], $_file) : rename($files['tmp_name'][$i], $_file))) {

                    $_files[]   = $_file;
                    $uploaded[] = $files['name'][$i];

                    if (\preg_match('/\.(svg|xml)$/i', $_file)) {
                        file_put_contents($_file, \SVGSanitizer::clean(\file_get_contents($_file)));
                    }

                } else {
                    $failed[] = $files['name'][$i];
                }
            }
        }

        if (count($_files)) {

            $assets = $this->add($_files, $meta, isset($meta['_id']));

            foreach ($_files as $file) {
                unlink($file);
            }
        }

        return ['uploaded' => $uploaded, 'failed' => $failed, 'assets' => $assets];
    },
    // omitted
]);

The upload function is stored in a member variable of the App class that holds functions of the Assets module, called registry['modules']['assets'].
Therefore, when calling the upload function, it is called as $this->module('assets')->upload('file', $file);.
The upload function registered here is called by the Assets class4.

root@kitploit:~
public function upload() {
    this->helper('session')->close();
    this->hasValidCsrfToken(true);
    if (!this->isAllowed('assets/upload')) {
        return $this->stop(['error' => 'Upload not allowed'], 401);
    }
    $meta = ['folder' => $this->param('folder', '')];
    return $this->module('assets')->upload('files', $meta);
}

As you can see, the upload function registered in registry['modules']['assets'] is being called.
Now let's look at the upload function described in bootstrap.php.
Here, forbidden extensions are defined in the $forbiddenExtension variable.
However, the shtml extension is missing.
Therefore, this is a flaw, making it possible to upload shtml files.

3: https://github.com/Cockpit-HQ/Cockpit/blob/2.6.3/modules/Assets/bootstrap.php#L51
4: https://github.com/Cockpit-HQ/Cockpit/blob/2.6.3/modules/Assets/Controller/Assets.php#L140

Countermeasure

Since the cause is that shtml is not forbidden, it can be mitigated by adding shtml to forbiddenExtension.

root@kitploit:~
$forbiddenExtension = ['bat', 'exe', 'sh', 'php', 'phar', 'phtml', 'phps', 'htm', 'html', 'xhtml', 'htaccess', 'shtml'];
Download Tool