Custom Script (ip-bloc.py)
The script is located in /var/ossec/active-response/bin/ and is written in Python. It reads the alert data from stdin, extracts the source IP (srcip), and sends an API request to pfSense to create blocking rules. Here's the code:
#!/usr/bin/python3
import sys
import json
import requests
with open("/tmp/ip-bloc.log", "a") as f:
f.write(f"Script called with data: {sys.stdin.read()}\n")
sys.stdin.seek(0)
# Disable SSL warnings (not recommended for production)
requests.packages.urllib3.disable_warnings()
# Configuration
PF_HOST = "http://10.10.10.2"
api_key = "bd5f92db4a2920ecfa8edf0665c480f0"
# Récupération de l'entrée JSON envoyée par Wazuh (stdin)
alert_data = json.loads(sys.stdin.read())
# Extraire l'adresse IP de l'attaquant
try:
malicious_ip = alert_data['parameters']['alert']['data']['srcip']
except KeyError:
print("❌ Impossible d'extraire l'adresse IP de l'attaquant.")
sys.exit(1)
print(f"🚨 IP malveillante détectée: {malicious_ip}")
# Headers API
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"X-API-Key": api_key
}
# Étape 1 : récupérer les règles existantes
try:
r = requests.get(f"{PF_HOST}/api/v2/firewall/rules", headers=headers, verify=False)
current_rules = r.json()["data"]
except Exception as e:
print(f"❌ Erreur lors de la récupération des règles : {e}")
sys.exit(1)
# Étape 2 : créer les règles de blocage
def create_rule(protocol):
rule = {
"type": "block",
"interface": ["lan"],
"ipprotocol": "inet",
"protocol": protocol,
"source": malicious_ip,
"source_port": None,
"destination": "any",
"destination_port": None,
"descr": f"Block {protocol} from {malicious_ip}",
"disabled": False,
"log": True,
"quick": True,
"direction": "any",
"statetype": "keep state"
}
if protocol == "icmp":
rule["icmptype"] = ["any"]
return rule
# Liste des règles à ajouter
block_rules = [
create_rule("tcp/udp"),
create_rule("icmp")
]
# Ajout en haut de la liste
new_rules = block_rules + current_rules
# Étape 3 : remplacer les règles
try:
put_r = requests.put(f"{PF_HOST}/api/v2/firewall/rules", headers=headers, json=new_rules, verify=False)
print("✅ Règles mises à jour !")
except Exception as e:
print(f"❌ Erreur de mise à jour des règles : {e}")
sys.exit(1)
# Étape 4 : appliquer les changements
try:
apply_r = requests.post(f"{PF_HOST}/api/v2/firewall/apply", headers=headers, verify=False)
if apply_r.status_code == 200:
print("✅ Changements appliqués au pare-feu.")
else:
print("⚠️ Problème lors de l'application des changements.")
except Exception as e:
print(f"❌ Erreur application des changements : {e}")
🧩 Wazuh Manager Configuration
Here's my configuration in ossec.conf::

✅ Manual Test
When I run the script manually:
❌ Problem
When I launch a real SSH brute-force attack using:
hydra -l root -P /usr/share/wordlists/rockyou.txt ssh://
10.10.10.15
the alert appears in Wazuh, but the firewall rule is not created automatically.
💭 What I've Checked
-
The alert matches one of the rules_id listed (e.g., 5710).
-
Permissions on the script are correct.
-
The script works manually.
-
The log /var/ossec/logs/ossec.log doesn't show any clear error about script execution.
❓ Any ideas why the script is not triggered automatically during real-time attacks?
Any help or suggestions would be appreciated 🙏
Thanks in advance!
Best regards,
Hamza Arfaoui