Python script to block the execution of ConnectWise installers

  • Even if we pretend downloading/installing CW (via xxx.top, xxx.help and so on) does not work, a scammer might use another remote tool and then they will still try to install CW while watching our screen.
  • I wrote a python script that you can run in the background when you fire up your VM to block the execution of the CW installers. Bare with me, it’s the first time I wrote a script like that.

Script Summary: ConnectWise Detection and Blocking Script

This script is designed to monitor the user’s Downloads folder for executable files (.exe) and automatically verify their digital signatures using the signtool. If it detects a file issued by ConnectWise, LLC (I tried a couple of support.client.exe files and they all have it, independent of the file name), the script will block its execution by modifying file permissions.

Key Features:

  • Continuously scans the Downloads folder every 10 seconds (you can change the folder if you want or the interval if it slows down your VM).
  • Verifies executable files for the ConnectWise, LLC signature using signtool.
  • Blocks execution of identified malicious files.
  • Logs activities for review and troubleshooting.

Required Libraries:
This script relies on the following libraries (pip install them if they give you errors, I had all of them installed):

  • os: Standard library for operating system interactions.
  • logging: Standard library for logging events.
  • subprocess: Standard library to run external commands.

You will need to install signtool separately for the script to work. It is included with the Windows SDK. To install it:

  1. Download the Windows SDK from the official Microsoft website.
  2. During installation, make sure to select the option to install the Windows App Certification Kit, which includes signtool. (the installation is pretty big, maybe you don’t need all I just installed all of them)

Starting / stopping the script:

  • Make sure to start the script with admin rights.
  • When you start the script it will disappear from your screen (but still run in the background).
  • If you want to stop the script hit ESC (you can see if it stopped in the log file. The log file has the same name as your script).

File Permissions:
Files detected as ConnectWise-related will have their execution blocked [and you + the scammer will see a warning which you can’t bypass!], but this may lead to complications when attempting to delete these files. To delete blocked files, follow this workaround (or reset your VM to an older Snapshot):

  1. Right-click the blocked file and select Properties.
  2. Navigate to the Security tab.
  3. Click Advanced.
  4. Select Everyone and click Edit.
  5. Check the Allow box next to Full control and apply the changes.

After adjusting the permissions, you should be able to delete the files as needed.

Notes:

  • I only tested it in my VMware Win10 machine with a couple of support.client.exe CW installation files you get from the .top/.help sites. If you find any other files and they are not detected/blocked please let me know.
  • Review the log file created by the script for details on detected files and actions taken.

If you have any ideas on how to change/improve it, please let me know.

Here’s the current version of the script:

import os
import logging
import subprocess
import time
import ctypes
import threading

# Setup logging
script_name = os.path.splitext(os.path.basename(__file__))[0]
log_filename = f'{script_name}.log'
logging.basicConfig(filename=log_filename, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Define the target directory to scan
TARGET_DIRECTORY = os.path.expanduser(r"~\Downloads")  # Use Downloads folder

# Variable to control the scanning loop
running = True

def extract_signature_info(filepath):
    """Extract and log specific issuer information from the given executable file using signtool."""
    try:
        logging.info(f"Verifying file: {filepath}")  # Log the file being verified

        # Call signtool to verify the digital signature
        result = subprocess.run(
            ['signtool', 'verify', '/pa', '/v', filepath],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )

        if result.returncode == 0:
            # Signtool succeeded, parse the output to find the issuer name
            output_lines = result.stdout.splitlines()
            issuer_name = None

            for i, line in enumerate(output_lines):
                if 'Issued to:' in line:
                    if 'Connectwise, LLC' in line:
                        issuer_name = line.split(':', 1)[1].strip()
                        logging.info(f"Relevant issuer found - File: {filepath} - Issuer: {issuer_name}")
                        block_execution(filepath)
                        break

                    if 'Issued to:' in line and "Connectwise, LLC" in output_lines[i + 3]:
                        issuer_name = output_lines[i + 3].strip()
                        logging.info(f"Relevant issuer found - File: {filepath} - Issuer: {issuer_name}")
                        block_execution(filepath)
                        break

            if issuer_name is None:
                logging.info(f"File: {filepath} - No relevant issuer information found.")
        else:
            logging.error(f"File: {filepath} - Signature verification failed. Error: {result.stderr.strip()}")

    except Exception as e:
        logging.error(f"Failed to extract information for {filepath}: {e}")

def block_execution(filepath):
    """Block execution of the file by changing permissions to deny read and execute."""
    try:
        result = subprocess.run(
            ['icacls', filepath, '/deny', 'Everyone:RX'],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )

        if result.returncode == 0:
            logging.info(f"Execution successfully blocked for {filepath}")
        else:
            logging.warning(f"Failed to block execution for {filepath}. Error: {result.stderr.strip()}")

    except Exception as e:
        logging.error(f"Failed to block execution for {filepath}: {e}")

def scan_directory():
    """Scan the specified directory for executable files and extract digital signature information."""
    scanned_files = set()  # Keep track of already scanned files
    while running:
        for root, _, files in os.walk(TARGET_DIRECTORY):
            for file in files:
                if file.lower().endswith(".exe"):  # Check for any .exe file
                    filepath = os.path.join(root, file)
                    if filepath not in scanned_files:  # Check if the file has already been scanned
                        scanned_files.add(filepath)
                        extract_signature_info(filepath)
                        logging.info(f"New file detected: {filepath}")  # Log if a new file is found
        time.sleep(10)  # Wait for 10 seconds before scanning again

def hide_console():
    """Hide the console window."""
    ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)

def on_exit():
    """Stop the script gracefully."""
    global running
    running = False
    logging.info("Stopping the script...")

if __name__ == "__main__":
    # Hide the console window
    hide_console()

    # Start the scanning thread
    scanning_thread = threading.Thread(target=scan_directory, daemon=True)
    scanning_thread.start()

    # Allow the user to stop the script using the ESC key
    print("Press ESC to stop the script.")
    while running:
        if ctypes.windll.user32.GetAsyncKeyState(0x1B):  # ESC key
            on_exit()
            break

    scanning_thread.join()  # Wait for the scanning thread to finish
    logging.info("Script terminated.")  # Log termination
2 Likes

Just a quick feedback on how the script worked on my end and gave it a small update.

  • I tested it with a bunch of scammers, as expected the made me install UV or something else and then they tried to download the CW installer from their fake pages (they tried several ones, which is good for reporting).
  • Took them up to half an hour to give up and move on in their script (they even tried to uninstall/disable Windows defender w/o success).
  • One of them got around it, I’m not sure if he was quick enough or if he dl’ed a different CW installer (will keep an eye open).

Besides that: as the Windows SDK is kinda big for your VM, I cross-checked what you need on installation:

only click

  • Application verifier for windows
  • Windows App Certification Kit
    (this is 250MB only compared to 2,5GB)

Make sure to add “signtool” (needed for the script) to PATH as well:
search “edit the system environment variables”

  • Click Environment variables
    (for user only or overall system):

Click Path / Click Edit / Add New:
C:\Program Files (x86)\Windows Kits\10\App Certification Kit

then open a NEW cmd, to test type “signtool”

Here’s the update (any feedback is welcome):

  • Changed the key to stop the script from ESC to PAUSE (as it’s less likely they hit it, you can change it to whatever you want), below is the updated script (I was thinking about automatically starting it with the VM as well but not sure if that works properly… maybe in a later stage)
import os
import logging
import subprocess
import time
import ctypes
import threading

# Setup logging
script_name = os.path.splitext(os.path.basename(__file__))[0]
log_filename = f'{script_name}.log'
logging.basicConfig(filename=log_filename, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Define the target directory to scan
TARGET_DIRECTORY = os.path.expanduser(r"~\Downloads")  # Use Downloads folder

# Variable to control the scanning loop
running = True

def extract_signature_info(filepath):
    """Extract and log specific issuer information from the given executable file using signtool."""
    try:
        logging.info(f"Verifying file: {filepath}")  # Log the file being verified

        # Call signtool to verify the digital signature
        result = subprocess.run(
            ['signtool', 'verify', '/pa', '/v', filepath],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )

        if result.returncode == 0:
            # Signtool succeeded, parse the output to find the issuer name
            output_lines = result.stdout.splitlines()
            issuer_name = None

            for i, line in enumerate(output_lines):
                if 'Issued to:' in line:
                    if 'Connectwise, LLC' in line:
                        issuer_name = line.split(':', 1)[1].strip()
                        logging.info(f"Relevant issuer found - File: {filepath} - Issuer: {issuer_name}")
                        block_execution(filepath)
                        break

                    if 'Issued to:' in line and "Connectwise, LLC" in output_lines[i + 3]:
                        issuer_name = output_lines[i + 3].strip()
                        logging.info(f"Relevant issuer found - File: {filepath} - Issuer: {issuer_name}")
                        block_execution(filepath)
                        break

            if issuer_name is None:
                logging.info(f"File: {filepath} - No relevant issuer information found.")
        else:
            logging.error(f"File: {filepath} - Signature verification failed. Error: {result.stderr.strip()}")

    except Exception as e:
        logging.error(f"Failed to extract information for {filepath}: {e}")

def block_execution(filepath):
    """Block execution of the file by changing permissions to deny read and execute."""
    try:
        result = subprocess.run(
            ['icacls', filepath, '/deny', 'Everyone:RX'],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )

        if result.returncode == 0:
            logging.info(f"Execution successfully blocked for {filepath}")
        else:
            logging.warning(f"Failed to block execution for {filepath}. Error: {result.stderr.strip()}")

    except Exception as e:
        logging.error(f"Failed to block execution for {filepath}: {e}")

def scan_directory():
    """Scan the specified directory for executable files and extract digital signature information."""
    scanned_files = set()  # Keep track of already scanned files
    while running:
        for root, _, files in os.walk(TARGET_DIRECTORY):
            for file in files:
                if file.lower().endswith(".exe"):  # Check for any .exe file
                    filepath = os.path.join(root, file)
                    if filepath not in scanned_files:  # Check if the file has already been scanned
                        scanned_files.add(filepath)
                        extract_signature_info(filepath)
                        logging.info(f"New file detected: {filepath}")  # Log if a new file is found
        time.sleep(10)  # Wait for 10 seconds before scanning again

def hide_console():
    """Hide the console window."""
    ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)

def on_exit():
    """Stop the script gracefully."""
    global running
    running = False
    logging.info("Stopping the script...")

if __name__ == "__main__":
    # Hide the console window
    hide_console()

    # Start the scanning thread
    scanning_thread = threading.Thread(target=scan_directory, daemon=True)
    scanning_thread.start()

    # Allow the user to stop the script using the Pause/Break key
    print("Press Pause/Break to stop the script.")
    while running:
        if ctypes.windll.user32.GetAsyncKeyState(0x13):  # Pause/Break key
            on_exit()
            break

    scanning_thread.join()  # Wait for the scanning thread to finish
    logging.info("Script terminated.")  # Log termination
1 Like

here’s a quick solution to that (worked on my end):

Implement the Script into VM’s Autostart

To automatically start your Python script when your VM powers on, follow these steps:

  1. Prepare the Script:
  • Save your Python script in a folder on your VM (e.g., C:\Scripts\), and give it a unique name like scambaiting_script.py (something less obvious of course).
  1. Create a Batch File:
  • Create a .bat file in the same folder with the following content:
@echo off
cd "C:\Path\To\Your\Script"  # Replace with your script’s folder
python scambaiting_script.py  # Replace with your script’s name
  1. Add to Autostart:
  • Open the Startup folder by pressing Win + R, typing shell:startup, and hitting Enter.
  • Copy the .bat file into the Startup folder to make it run automatically when the VM starts.
  1. Admin Rights (if needed):
  • If necessary, set the .bat file to run as an administrator. Right-click on the .bat file, go to Properties > Compatibility, and check Run as administrator.
1 Like

Nice work!

1 Like