3-layer detection architecture: Network signatures (Suricata) + Machine learning behavioral analysis (SLIPS + Zeek) + Centralized SIEM correlation with MITRE ATT&CK mapping (Wazuh). Fully open source, Docker-deployable.
Stealthy exfiltration techniques (DNS tunneling, C2 beaconing, low-and-slow transfers) mimic legitimate traffic and evade traditional signature-based IDS. Each layer targets a different family of indicators:
| Layer | Tool | What It Detects |
|---|---|---|
| Network signatures | Suricata | Known documented threats (Emerging Threats ruleset) |
| Traffic logging | Zeek | All network behaviors, without judgment |
| ML behavioral | SLIPS | Statistical anomalies, zero-day attacks, DGA, beaconing |
| SIEM correlation | Wazuh | Unified view, custom rules, MITRE ATT&CK mapping, active response |
flowchart TD
subgraph ATTACKER["🖥️ Compromised Host"]
W1[DNS Tunneling\nMassive SCP\nLong Connection]
end
subgraph SOC["🛡️ SOC Server — Kali Linux"]
subgraph CAPTURE["Layer 1 · Network Signatures"]
S[Suricata 8.0.3\nNIDS · Emerging Threats\neve.json]
end
subgraph BEHAVIORAL["Layer 2 · Behavioral Analysis"]
SLIPS[SLIPS + Zeek\nMachine Learning\nDGA · Beaconing · Long Connection\nalerts.json]
REDIS[Redis\nML Inter-module Bus]
end
subgraph SIEM["Layer 3 · SIEM Correlation — Docker single-node"]
AGT[Wazuh Agent\nLog Collection\nTCP 1514 AES-256]
MGR[Wazuh Manager\nCustom Rules 100200→100221\nMITRE ATT&CK Mapping]
IDX[Wazuh Indexer\nOpenSearch]
DSH[Wazuh Dashboard\nSOC · Alerts · PDF Report]
end
subgraph RESPONSE["Active Response"]
AR[firewall-drop\niptables · 1h block\nRule 100210]
end
end
W1 -->|wlan0| S
W1 -->|wlan0| SLIPS
REDIS <-->|internal bus| SLIPS
S -->|eve.json| AGT
SLIPS -->|alerts.json| AGT
AGT -->|TCP 1514 AES-256| MGR
MGR --> IDX
IDX --> DSH
MGR -->|DNS Tunneling detected| AR
- OS: Kali Linux (or any Debian/Ubuntu distribution)
- Wazuh 4.14.3 (Manager + Indexer + Dashboard) — Docker single-node
- Suricata 8.0.3 — native on OS
- SLIPS (StratosphereLinuxIPS, latest) + Zeek (integrated in SLIPS container) — Docker Compose
- Redis 7 (Alpine) — SLIPS sidecar
- Docker 29.x + Docker Compose v5.x
# Check Docker and Docker Compose
docker --version
docker compose version
# Install required tools
sudo apt-get update
sudo apt-get install -y gnupg apt-transport-https suricatagit clone https://github.com/wazuh/wazuh-docker.git -b v4.14.3
cd wazuh-docker/single-node/
# Generate SSL/TLS certificates
docker compose -f generate-indexer-certs.yml run --rm generator
# Start the stack (Manager + Indexer + Dashboard)
docker compose up -dThe Dashboard is accessible at https://<MACHINE_IP> — default credentials: admin / SecretPassword (change immediately).
# Import the official GPG key
curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --no-default-keyring \
--keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import
chmod 644 /usr/share/keyrings/wazuh.gpg
# Add the Wazuh 4.x repository
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" \
| tee -a /etc/apt/sources.list.d/wazuh.list
apt-get update
# Install the agent pointing to the Manager
WAZUH_MANAGER="<MACHINE_IP>" apt-get install wazuh-agent
# Enable and start
systemctl daemon-reload
systemctl enable wazuh-agent
systemctl start wazuh-agent
# Verify
systemctl status wazuh-agentsudo apt-get update
sudo apt-get install -y suricatacd /tmp
curl -LO https://rules.emergingthreats.net/open/suricata-6.0.8/emerging.rules.tar.gz
sudo tar -xvzf emerging.rules.tar.gz
sudo mkdir -p /etc/suricata/rules
sudo mv rules/*.rules /etc/suricata/rules/
sudo find /etc/suricata/rules -name "*.rules" -exec chmod 777 {} \;Edit /etc/suricata/suricata.yaml:
vars:
address-groups:
HOME_NET: "[192.168.0.0/16]" # adapt to your network
EXTERNAL_NET: "any"
default-rule-path: /etc/suricata/rules
rule-files:
- "*.rules"
stats:
enabled: yes
af-packet:
- interface: eth0 # adapt to your active interface (eth0, wlan0, enp0s3...)sudo systemctl restart suricataAdd to /var/ossec/etc/ossec.conf (agent):
<ossec_config>
<localfile>
<log_format>json</log_format>
<location>/var/log/suricata/eve.json</location>
</localfile>
</ossec_config>Suricata alerts are automatically forwarded to Wazuh via the parent rule 86600 (0515-suricata_rules.xml, included by default).
Zeek is natively integrated into the SLIPS container — no separate installation needed.
mkdir -p ~/slips-docker/{config,output,dataset}
cd ~/slips-dockergit clone https://github.com/stratosphereips/StratosphereLinuxIPS.git
cp -r StratosphereLinuxIPS/config ~/slips-docker/configservices:
redis:
image: redis:7-alpine
container_name: slips-redis
restart: unless-stopped
network_mode: host
command: redis-server --port 6379 --daemonize no
slips:
image: stratosphereips/slips:latest
container_name: slips
restart: unless-stopped
network_mode: host
cap_add:
- NET_ADMIN
- NET_RAW
deploy:
resources:
limits:
memory: 4G
cpus: '0.35'
depends_on:
- redis
volumes:
- ./config:/StratosphereLinuxIPS/config
- ./output:/StratosphereLinuxIPS/output
- ./dataset:/StratosphereLinuxIPS/dataset
entrypoint: [
"bash", "-c",
"python3 /StratosphereLinuxIPS/slips.py -i wlan0 -o /StratosphereLinuxIPS/output & sleep 15 && /StratosphereLinuxIPS/webinterface.sh"
]Adapt
-i wlan0to your active network interface. The SLIPS web interface is accessible on port55001(to avoid conflict with Wazuh Manager API on port55000).
cd ~/slips-docker
docker compose up -dAdd to /var/ossec/etc/ossec.conf (agent):
<localfile>
<log_format>json</log_format>
<location>/home/<user>/slips-docker/output/alerts.json</location>
</localfile>Create /var/ossec/etc/decoders/slips_decoders.xml in the Manager container:
<decoder name="Slips">
<prematch>"Nom": "Slips"</prematch>
</decoder>
<decoder name="Slips">
<parent>Slips</parent>
<use_own_name>true</use_own_name>
<plugin_decoder>JSON_Decoder</plugin_decoder>
</decoder>Create /var/ossec/etc/rules/slips_rules.xml in the Manager container:
<!-- Base rule: any SLIPS event -->
<rule id="100200" level="0">
<decoded_as>Slips</decoded_as>
<description>SLIPS: JSON event received</description>
<group>slips,exfiltration,behavioral</group>
</rule>
<!-- DNS Tunneling / DGA — T1071.004 -->
<rule id="100218" level="13">
<if_sid>100200</if_sid>
<field name="Description">dns tunneling|dns exfiltration|NXDOMAIN|long subdomain|DGA</field>
<description>SLIPS: DNS Tunneling exfiltration detected - T1071.004</description>
<mitre><id>T1071.004</id></mitre>
<group>slips,exfiltration,dns,</group>
</rule>
<!-- C2 Beaconing — T1071.001 -->
<rule id="100219" level="8">
<if_sid>100200</if_sid>
<field name="Description">beaconing|C2|periodic connection</field>
<description>SLIPS: C2 Beaconing behavior detected - T1071.001</description>
<mitre><id>T1071.001</id></mitre>
<group>slips,c2,beaconing,exfiltration,behavioral</group>
</rule>
<!-- Low and Slow persistent connection — T1041 -->
<rule id="100220" level="10">
<if_sid>100200</if_sid>
<field name="Description">long connection|persistent connection|Low and Slow</field>
<description>SLIPS: Suspicious persistent connection - Low and Slow channel - T1041</description>
<mitre><id>T1041</id></mitre>
<group>slips,exfiltration,persistence,behavioral</group>
</rule>
<!-- Abnormal upload volume — T1048 -->
<rule id="100221" level="12">
<if_sid>100200</if_sid>
<field name="Description">large data upload|volume|traffic</field>
<description>SLIPS: Abnormal upload volume - Probable exfiltration - T1048</description>
<mitre><id>T1048</id></mitre>
<group>slips,exfiltration,traffic,behavioral</group>
</rule>Apply the files in the Manager container:
docker exec -it single-node-wazuh.manager-1 bash
# Copy files to /var/ossec/etc/decoders/ and /var/ossec/etc/rules/
# Then restart the manager
systemctl restart wazuh-managerAdd to /var/ossec/etc/ossec.conf on the Manager:
<ossec_config>
<command>
<name>firewall-drop</name>
<executable>firewall-drop</executable>
<timeout_allowed>yes</timeout_allowed>
</command>
<active-response>
<disabled>no</disabled>
<command>firewall-drop</command>
<location>local</location>
<rules_id>100210</rules_id> <!-- triggers only on SLIPS DNS Tunneling alert -->
<timeout>3600</timeout> <!-- IP blocked for 1h, then automatically revoked -->
</active-response>
</ossec_config>
⚠️ Warning: Enable only after a 1–2 week passive calibration phase to establish a legitimate traffic baseline. SLIPS can generate false positives on normal behaviors (Teams sessions, browsers, CDN) if thresholds are not tuned.
# PowerShell (from a Windows machine on the same network)
for ($i=1; $i -le 10; $i++) {
Resolve-DnsName "random-domain-$i.invalid" -ErrorAction SilentlyContinue
}Expected result: SLIPS generates a HIGH alert (DGA/DNS tunneling detected), correlated in Wazuh as rule 100218 level 13 within ~5 minutes.
# Create a test file
dd if=/dev/urandom of=/tmp/large-file.bin bs=1M count=150
# Transfer to a target machine
scp /tmp/large-file.bin user@<TARGET_IP>:/tmp/Expected result: SLIPS reports Large data upload, Wazuh correlates as rule 100221 level 12.
Open a browser tab pointing to an external address and keep it open for more than 20 minutes. SLIPS reports Long Connection — this scenario also illustrates the false positive case and the need to calibrate long_connection_threshold in slips.yaml.
| Attack Technique | MITRE ID | Detected By | Wazuh Rule | Level |
|---|---|---|---|---|
| DNS Tunneling / DGA | T1071.004 | SLIPS + Suricata | 100218 | 13 |
| C2 Beaconing | T1071.001 | SLIPS | 100219 | 8 |
| Low and Slow Connection | T1041 | SLIPS + Zeek | 100220 | 10 |
| Large Data Upload | T1048 | SLIPS | 100221 | 12 |
- Wazuh Documentation
- Suricata Documentation
- StratosphereLinuxIPS (SLIPS)
- Zeek Documentation
- MITRE ATT&CK — Exfiltration (TA0010)
- Emerging Threats Open Rules
Yc-jafar — Blue Team | SOC | Threat Detection
Feel free to ⭐ the repo if it helped you, and open an Issue for feedback or improvements!