Custom Active Respond in Windows

37 views
Skip to first unread message

Isaac

unread,
Nov 21, 2025, 2:03:04 AM (yesterday) Nov 21
to Wazuh | Mailing List
Hello Wazuh Team

I have programed a custom responder based on netsh.exe for outgoing connections and for enabling the FW profile in Windows.

Testing it in cmd (admin privileges) it works there is the input and the output:

c:\Users\test\Downloads>echo '{"command": "add","parameters": {"alert": {"dstip": "192.168.0.1"}}}' | .\profile.exe
Adding block rule for outgoing connection to: 192.168.0.1 (single IP or segment)

--- Windows Firewall Pre-Check ---
Checking Windows Firewall status for all profiles...
Firewall Domain profile: DISABLED - attempting to enable...
Enabling Windows Firewall for domainprofile...
Successfully enabled firewall for domainprofile
Firewall Private profile: DISABLED - attempting to enable...
Enabling Windows Firewall for privateprofile...
Successfully enabled firewall for privateprofile
Firewall Public profile: DISABLED - attempting to enable...
Enabling Windows Firewall for publicprofile...
Successfully enabled firewall for publicprofile
Attempted to enable 3 firewall profile(s)
--- End Firewall Pre-Check ---

Successfully blocked outgoing connections to 192.168.0.1


In Wazuh i have enabled the AR in manager ossec.conf file and executes in console (dev tools) this instruction:

PUT /active-response?agents_list=005
{
"command": "profile0",
"alert":{
      "data": {
      "dstip":"192.168.0.1"
      }
    }
}

and i get the next response:

{
  "data": {
    "affected_items": [
      "005"
    ],
    "total_affected_items": 1,
    "total_failed_items": 0,
    "failed_items": []
  },
  "message": "AR command was sent to all agents",
  "error": 0
}

But the outgoing rule is not added and the firewall in windows is not enabled.

Considerations:
- the profile.exe responder is in C:\Program Files (x86)\ossec-agent\active-response\bin
- The firewall is not under control of any Active Directory policy or AV
- There are not logs in the ossec.log and active-responses.log in the agent files.

Isaac

Bony V John

unread,
Nov 21, 2025, 2:29:11 AM (yesterday) Nov 21
to Wazuh | Mailing List
Hi, 

Please allow me some time, I'm working on this and will get back to you with an update as soon as possible.

Bony V John

unread,
Nov 21, 2025, 5:39:16 AM (yesterday) Nov 21
to Wazuh | Mailing List
Hi,

I have replicated this same scenario on my side by creating a custom Python script, and it is working fine for me.
The script is triggered correctly and blocks the IP address that we pass from the Dev Tools in the Wazuh dashboard, along with an argument to decide whether it should be blocked or unblocked.

You can follow the steps below to achieve this:


On the Windows agent
Create a Python script at: C:\Program Files (x86)\ossec-agent\active-response\bin\wazuh_fw_block.py

Add the following script:
#!/usr/bin/env python3
import sys
import json
import subprocess
from datetime import datetime

LOG_PATH = r"C:\Program Files (x86)\ossec-agent\active-response\ar_debug.log"

def log(msg):
    try:
        with open(LOG_PATH, "a", encoding="utf-8") as f:
            f.write(f"[{datetime.now()}] {msg}\n")
    except Exception:
        pass

def read_payload():
    line = sys.stdin.readline()
    if not line:
        log("No stdin. Exiting.")
        sys.exit(0)
    line = line.strip()
    log(f"Raw stdin: {line}")
    try:
        return json.loads(line)
    except Exception as e:
        log(f"JSON parse error: {e}")
        sys.exit(1)

def shell_run_cmdline(cmd_line: str):
    """Run a command via shell and log everything."""
    try:
        log(f"CMDLINE: {cmd_line}")
        result = subprocess.run(
            cmd_line,
            shell=True,
            capture_output=True,
            text=True
        )
        log(f"RETURNCODE: {result.returncode}")
        log(f"STDOUT: {result.stdout.strip()}")
        log(f"STDERR: {result.stderr.strip()}")
    except Exception as e:
        log(f"Exception running cmdline: {e}")

def enable_firewall_profiles():
    log("Enabling firewall profiles via PowerShell+netsh...")
    cmd = (
        'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass '
        '"netsh advfirewall set allprofiles state on"'
    )
    shell_run_cmdline(cmd)

def add_block_rule(dstip: str):
    rule_name = f"Wazuh_AR_Block_{dstip}"
    log(f"Adding block rule for {dstip}")

    cmd_del = (
        'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass '
        f'"netsh advfirewall firewall delete rule name=\'{rule_name}\' dir=out"'
    )
    shell_run_cmdline(cmd_del)

    cmd_add = (
        'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass '
        f'"netsh advfirewall firewall add rule name=\'{rule_name}\' '
        f'dir=out action=block remoteip={dstip} protocol=any"'
    )
    shell_run_cmdline(cmd_add)

    cmd_show = (
        'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass '
        f'"netsh advfirewall firewall show rule name=\'{rule_name}\'"'
    )
    shell_run_cmdline(cmd_show)

def delete_block_rule(dstip: str):
    rule_name = f"Wazuh_AR_Block_{dstip}"
    log(f"Deleting block rule for {dstip}")

    cmd_del = (
        'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass '
        f'"netsh advfirewall firewall delete rule name=\'{rule_name}\' dir=out"'
    )
    shell_run_cmdline(cmd_del)

    cmd_show = (
        'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass '
        f'"netsh advfirewall firewall show rule name=\'{rule_name}\'"'
    )
    shell_run_cmdline(cmd_show)

def main():
    payload = read_payload()

    params = payload.get("parameters") or {}
    alert = params.get("alert") or payload.get("alert") or {}
    data = alert.get("data", {}) if isinstance(alert, dict) else {}

    dstip = None
    if isinstance(data, dict):
        dstip = data.get("dstip")
    if not dstip and isinstance(alert, dict):
        dstip = alert.get("dstip")

    log(f"Parsed dstip = {dstip}")

    if not dstip:
        log("No dstip in payload, exiting.")
        sys.exit(0)

    action = str(payload.get("command", "")).lower()
    if isinstance(data, dict) and data.get("action"):
        action = str(data.get("action")).lower()

    log(f"Final action = {action}")

    if action == "add":
        enable_firewall_profiles()
        add_block_rule(dstip)
    elif action == "delete":
        delete_block_rule(dstip)
    else:
        log(f"Unknown action '{action}', defaulting to add.")
        enable_firewall_profiles()
        add_block_rule(dstip)

    log("Execution completed.\n")
    sys.exit(0)

if __name__ == "__main__":
    main()


Save and close the file.

Make the script executable (create EXE), open PowerShell as Administrator and run:
cd "C:\Program Files (x86)\ossec-agent\active-response\bin"
pyinstaller --onefile wazuh_fw_block.py
copy ".\dist\wazuh_fw_block.exe" "."



On the Wazuh manager

Add the following command configuration in the ossec.conf file:

<command>
  <name>windows_fw_profile</name>
  <executable>wazuh_fw_block.exe</executable>
</command>

Save the file and restart the Wazuh manager:
systemctl restart wazuh-manager


Testing from the Wazuh dashboard

On the Wazuh dashboard, go to:

Hamburger menu on the top left > Server management > Dev tools

Run the following request:

PUT /active-response?agents_list=005
{
  "command": "!wazuh_fw_block.exe",
  "arguments": [],
  "alert": {
    "data": {
      "dstip": "192.168.0.18",
      "action": "add"
    }
  }
}

This will execute the active response script on the agent with ID 005 and block the IP 192.168.0.18.
The "action": "add" parameter tells the script to create the blocking firewall rule. If you change "add" to "delete", it will remove the firewall rule instead.

Then on PowerShell, run the below command as admin to check the rule:

netsh advfirewall firewall show rule name="Wazuh_AR_Block_192.168.0.18"

I have tested this, and it is working fine on my side.
You can also refer to the Wazuh active response documentation for more details on creating custom active response scripts.

Adding firewall rule to block IP:

Screenshot 2025-11-21 160505.png


Screenshot 2025-11-21 160659.png


Deleting firewall rule:

Screenshot 2025-11-21 160753.png


Screenshot 2025-11-21 160820.png

Isaac

unread,
2:37 AM (20 hours ago) 2:37 AM
to Wazuh | Mailing List
Hello Bony

Thank you for your response. I have tested again the profile.exe with the next API instruction:

PUT /active-response?agents_list=005
{
  "command": "!profile.exe",
  "arguments": [],
  "alert": {
    "data": {
      "dstip": "10.152.30.64",
      "action": "add"
    }
  }
}

and i have seen the next:

- The wazuh agent call the profile.exe
- in task manager there is a "profile.exe" process that does not finish


When i test the profile.exe in a cmd with admin privileges:

- In Downloads folder the exe is executed well
- in C:\Program Files (x86)\ossec-agent\active-response\bin the exe is executed but does not finish.

I guess that are some permissions in the folder  C:\Program Files (x86)\ossec-agent\active-response\bin, the profile.exe is based in the netsh.exe from wazuh.

I going to check the code.

Regards
Isaac
Reply all
Reply to author
Forward
0 new messages