Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 

Repository files navigation

SLIPS-Wazuh

Repositório de estudo para integração do IDS SLIPS com o SIEM Wazuh.

Anexo A — Estrutura do Repositório

Desafio_2_IA_BigData/
├── ml/                    # Notebooks e modelos treinados
│   ├── 01_eda.ipynb
│   ├── 02_train_classifiers.ipynb
│   ├── 03_predict.py
│   ├── 04_lstm_anomaly.ipynb
│   ├── models/            # rf_darknet.joblib
│   └── metrics/           # classification_report, confusion_matrix, *.png
├── pipeline/              # Integrações Wazuh + Shuffle + SLIPS
│   ├── wazuh_rules/       # api_attacks.xml
│   ├── wazuh_decoders/    # slips.xml
│   ├── docker-compose.yml
│   ├── shuffle_workflow_wazuh.json
│   └── retrain_cron.sh
├── dashboard/             # Exports dos dashboards OpenSearch
│   └── wazuh_dashboards.ndjson
├── relatorio/             # Fonte .md + .odt final
├── pcaps/                 # CICDarknet2020 (Dataset/PCAPs/)
└── docs/                  # Diagramas, referências

A separação segue o princípio de separation of concerns: ML (offline), integração (runtime), apresentação (UI). Cada camada tem seu próprio versionamento em git, permitindo que um engenheiro reproduza o pipeline independentemente.

Anexo B — Ambiente Python e requirements.txt

# requirements.txt
pandas>=2.0
numpy>=1.24
scikit-learn>=1.3
matplotlib>=3.7
seaborn>=0.12
shap>=0.42
jupyter>=1.0
joblib>=1.3

Bootstrap do ambiente (com uv):

cd /opt/Desafio_2_IA_BigData
uv venv .venv --python 3.11
source .venv/bin/activate
uv pip install -r requirements.txt

Anexo C — Snippet completo do classificador Random Forest

import pandas as pd, numpy as np, joblib
from pathlib import Path
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report

DATA = Path('pcaps/CICDarknet2020/Darknet.csv')
df = pd.read_csv(DATA, low_memory=False)
df = df.apply(pd.to_numeric, errors='coerce').fillna(0)
df = df.select_dtypes(include='number')
y = pd.read_csv(DATA, usecols=['Label'], low_memory=False)['Label']

Xtr, Xte, ytr, yte = train_test_split(df, y, test_size=0.2,
                                      random_state=42, stratify=y)
rf = RandomForestClassifier(n_estimators=300, max_depth=20,
                            class_weight='balanced', n_jobs=-1, random_state=42)
rf.fit(Xtr, ytr)
ypred = rf.predict(Xte)
print(classification_report(yte, ypred, digits=4))
joblib.dump(rf, 'ml/models/rf_darknet.joblib')
joblib.dump(list(df.columns), 'ml/models/feature_names.json')

Snippet LSTM/Autoencoder (apêndice, opcional):

import torch, torch.nn as nn

class LSTMAE(nn.Module):
    def __init__(self, n_features, hidden=64):
        super().__init__()
        self.enc = nn.LSTM(n_features, hidden, batch_first=True)
        self.dec = nn.LSTM(n_features, hidden, batch_first=True)
        self.out = nn.Linear(hidden, n_features)

    def forward(self, x):
        _, (h, _) = self.enc(x)
        h = h.repeat(x.size(1), 1, 1).permute(1, 0, 2)
        return self.out(self.dec(h)[0])

Anexo D — Regras Wazuh custom + decoders + detectores RCF

Regras customizadas (pipeline/wazuh_rules/api_attacks.xml):

<group name="api,">
  <rule id="100100" level="10" frequency="10" timeframe="60">
    <if_matched_sid>31100</if_matched_sid>
    <regex>POST \/api\/v\d+\/(login|auth|token)</regex>
    <description>API: brute-force / token abuse em /auth</description>
  </rule>
  <rule id="100110" level="12">
    <decoded_as>json</decoded_as>
    <field name="integration">modsecurity</field>
    <field name="ruleId">^(942|941|932)$</field>
    <description>API: WAF bloqueou SQLi/XSS/RCE</description>
  </rule>
  <rule id="100120" level="6">
    <time>00:00-06:00</time>
    <match>POST|PUT|DELETE</match>
    <description>API: escrita fora do horário comercial (revisar)</description>
  </rule>
</group>

Decoder do SLIPS (pipeline/wazuh_decoders/slips.xml):

<decoder name="slips">
  <program_name>slips</program_name>
</decoder>
<decoder name="slips-json">
  <parent>slips</parent>
  <json />
  <order>srcip,dstip,srcport,dstport,profile,threat_level,evidence,confidence</order>
</decoder>

Detector RCF failed-logins-anomaly:

{
  "name": "failed-logins-anomaly",
  "time_field": "timestamp",
  "indices": ["wazuh-alerts-*"],
  "filter_query": {
    "bool": {
      "must": [{"match_phrase": {"rule.id": "5503"}}]
    }
  },
  "feature_attributes": [
    {"feature_name": "failed_login_count", "feature_type": "count"}
  ],
  "detection_interval": "10m"
}

Detector RCF api-bursts-00h-06h:

{
  "name": "api-bursts-00h-06h",
  "time_field": "timestamp",
  "indices": ["wazuh-alerts-*"],
  "filter_query": {
    "bool": {"must": [{"terms": {"rule.id": ["100100", "100110", "100120"]}}]}
  },
  "feature_attributes": [
    {"feature_name": "api_writes_per_hour", "feature_type": "count"}
  ],
  "detection_interval": "1h"
}

Detector RCF tor-vpn-traffic-spike:

{
  "name": "tor-vpn-traffic-spike",
  "time_field": "timestamp",
  "indices": ["wazuh-alerts-*"],
  "filter_query": {
    "bool": {
      "must": [
        {"match_phrase": {"decoder.name": "slips-json"}},
        {"range": {"data.threat_level": {"gte": 3}}}
      ]
    }
  },
  "feature_attributes": [
    {"feature_name": "darknet_flows_per_min", "feature_type": "count"}
  ],
  "detection_interval": "5m"
}

Anexo E — Docker Compose (Wazuh + Shuffle + SLIPS)

version: "3.8"
# Wazuh 4.14 + Shuffle SOAR + SLIPS -- protótipo do pipeline
# Requisitos: 8 GB RAM, kernel >= 5.10 (cap_net_admin)
services:
  wazuh.manager:
    image: wazuh/wazuh-manager:4.14.2
    hostname: wazuh-manager
    network_mode: host
    volumes:
      - ./wazuh_rules/api_attacks.xml:/var/ossec/etc/rules/api_attacks.xml:ro
      - ./wazuh_decoders:/var/ossec/etc/decoders:ro
      - slips_alerts:/var/slips/output:ro
    cap_drop: [ALL]
    cap_add: [CHOWN, SETUID, SETGID]

  shuffle:
    image: ghcr.io/shuffle/shuffle:latest
    ports: ["3443:3443"]
    environment: [SHUFFLE_APP=shuffle]
    depends_on: [wazuh.manager]

  slips:
    image: stratosphereips/slips:latest
    command: ["python3", "slips.py", "-f", "/data/darknet.pcap",
              "-o", "/var/slips/output", "-c", "/config/slips_darknet.yaml"]
    volumes:
      - ./pcaps:/data:ro
      - slips_alerts:/var/slips/output
      - ./slips_config:/config:ro
    network_mode: host
    cap_add: [NET_ADMIN]

volumes:
  slips_alerts:

Comando de inicialização (em ambiente de produção):

docker compose -f pipeline/docker-compose.yml up -d
docker compose ps  # esperado: todos "healthy"

Anexo F — Workflow do Shuffle SOAR

Pseudo-workflow JSON (estrutura exportada do Shuffle UI):

{
  "name": "Wazuh -> Shuffle -> Response",
  "trigger": {"type": "webhook"},
  "actions": [
    {"name": "ParseAlert",      "app": "Shuffle Tools", "action": "json"},
    {"name": "AbuseIPDBLookup", "app": "AbuseIPDB",     "action": "check"},
    {"name": "SwitchScore",     "app": "Shuffle Tools", "action": "if"},
    {"name": "WazuhBlockIP",    "app": "Wazuh",         "action": "active-response"},
    {"name": "SlackNotify",     "app": "Slack",         "action": "post-message"},
    {"name": "JiraCreate",      "app": "Jira",          "action": "create-issue"}
  ]
}

Lógica condicional do nó SwitchScore:

if abuse_confidence_score > 50:
    call Wazuh.active-response(block IP)
    call Slack.post-message(channel=#soc-alerts)
else if ml_confidence > 0.85:
    call Wazuh.active-response(block IP)
else:
    call Jira.create-issue(type=review, severity=medium)

Configuração do webhook no Wazuh (/var/ossec/etc/ossec.conf):

<integration>
  <name>shuffle</name>
  <hook_url>https://<YOUR_SHUFFLE_URL>/api/v1/hooks/<HOOK_ID></hook_url>
  <level>3</level>
  <alert_format>json</alert_format>
</integration>

About

Repositório de Estudo - tentativa de integração do IDS SLips com o SIEM Wazuh

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors