Lab — Week 7: Detection and Monitoring
Due: 14 August 2026
Submission: GitLab repo secdevops-s26-<CECS>
- Overview
- Prerequisites
- Part 1: Wazuh Rules, Tuning, and Active Response
- Part 2: Suricata Integration and File Integrity Monitoring
- Submission
Overview
Build the detection layer on top of the preventive controls: knowing when an attack is happening, what it’s doing, and how to respond.
- Part 1 — Wazuh Rules, Tuning, and Active Response writes custom detection rules, tests them by triggering the attack from Kali, and configures an active response that automatically blocks a brute-force source.
- Part 2 — Suricata Integration and File Integrity Monitoring adds network-layer detection by integrating Suricata with Wazuh, writes a custom Suricata rule, and completes FIM — closing the final gaps in your detection stack.
Prerequisites
- Week 4 Part 2 complete — Wazuh agent active on ubuntu-server
- Week 6 Part 2 complete — nftables running on ubuntu-server (required for the firewall-drop active response in Part 1)
- Suricata installed on ubuntu-server (by Ansible) — for Part 2
Part 1: Wazuh Rules, Tuning, and Active Response
Built-in Wazuh rules cover standard Linux events well but know nothing about DVWA’s specific log format or your threat model’s priority threats. This part writes two custom detection rules, tests them by triggering the attack from Kali, and configures an active response that automatically blocks a brute-force source.
Custom Rule: DVWA Login Brute Force
-
On the Wazuh manager (10.10.10.30), create
/var/ossec/etc/rules/local_rules.xmlif it does not exist. - Write a rule pair:
- A parent rule (level 3, id in range 100001–100099) that matches any nginx access log line referencing
/dvwa/login.php - A child rule (level 10) using
frequencyandtimeframethat fires when the parent rule matches 5 or more times from the same source IP within 60 seconds
- A parent rule (level 3, id in range 100001–100099) that matches any nginx access log line referencing
- Test the rule syntax without restarting:
/var/ossec/bin/wazuh-logtestPaste a sample nginx log line for
/dvwa/login.phpand confirm the parent rule matches. -
Restart the manager:
sudo systemctl restart wazuh-manager - From Kali, trigger the brute-force rule:
for i in {1..7}; do curl -s -o /dev/null -X POST http://10.10.10.20/dvwa/login.php \ -d "username=admin&password=wrong&Login=Login" done - Confirm the level-10 alert fires in the Wazuh dashboard. Take a screenshot showing the rule ID, level, and source IP.
Custom Rule: Unexpected Container Spawn
-
Write a second rule (level 12, id in range 100100–100199) in the same
local_rules.xmlthat fires when adocker runordocker execcommand appears in the auditd log outside of thedocker composeprocess tree.Use
<match>or<regex>targeting theexecvesyscall withdocker runin the arguments, and<if_matched_group>or<different_user>to distinguish ad-hoc runs from compose-managed ones if possible. -
Test from ubuntu-server:
docker run --rm hello-world -
Confirm the alert fires in the dashboard. Take a screenshot.
Active Response
- On the Wazuh manager, configure
firewall-dropto trigger when the DVWA brute-force rule (your level-10 rule) fires:<active-response> <command>firewall-drop</command> <location>local</location> <rules_id>YOUR_RULE_ID</rules_id> <timeout>3600</timeout> </active-response>Add this stanza to
/var/ossec/etc/ossec.confon the manager, inside<ossec_config>. -
Restart the manager:
sudo systemctl restart wazuh-manager -
From Kali, trigger the brute-force rule again (5+ POST requests in 60 seconds).
- On ubuntu-server, confirm the active response fired:
sudo tail -20 /var/ossec/logs/active-responses.log sudo nft list ruleset | grep 10.10.10.10 -
Take a screenshot showing the blocked IP in nftables.
- Unblock Kali:
sudo nft delete element inet ... @blocked_ips { 10.10.10.10 }or wait for the 3600-second timeout.
Deliverables
Create lab13/ in your repo containing:
local_rules.xml— both custom ruleswazuh-logtestoutput — showing the parent brute-force rule matching a sample log line- Brute-force alert screenshot — level-10 alert with correct rule ID and source IP
- Container spawn alert screenshot — level-12 alert for
docker run hello-world - Active response log —
active-responses.logentries showing the block action - nftables screenshot — Kali IP blocked after active response fires
lab13/lab13.md— for each rule: what it detects, which threat model entry it addresses, and one scenario that would evade it (honest gap analysis)
Part 2: Suricata Integration and File Integrity Monitoring
Network and host detection are complementary layers. Suricata sees packet contents; auditd sees syscalls. Neither sees everything the other does. This part adds network-layer detection by integrating Suricata EVE logs with Wazuh, writes a custom Suricata rule targeting a known attack pattern, and completes the FIM configuration to detect unauthorized changes to critical files — closing the final gaps in your detection stack.
Part 1 must be complete — Wazuh custom rules working.
Suricata Setup
- Enable and start Suricata in IDS mode on ubuntu-server, monitoring the primary interface (check
ip ato confirm the interface name — likelyens19orens18):sudo sed -i 's/- interface: eth0/- interface: ens19/' /etc/suricata/suricata.yaml sudo systemctl enable --now suricata sudo suricata --build-info | grep "AF_PACKET" # confirm AF_PACKET support - Confirm Suricata is writing EVE JSON:
sudo tail -5 /var/log/suricata/eve.json | python3 -m json.tool
Wazuh–Suricata Integration
- On ubuntu-server, add the following to
/var/ossec/etc/ossec.confinside<ossec_config>:<localfile> <log_format>json</log_format> <location>/var/log/suricata/eve.json</location> </localfile> -
Restart the Wazuh agent:
sudo systemctl restart wazuh-agent - From Kali, generate traffic that will produce Suricata events:
nmap -sV 10.10.10.20 - Confirm Suricata alert events appear in the Wazuh dashboard filtered by
rule.groups: suricata. Take a screenshot.
Custom Suricata Rule
- Write a custom Suricata rule in
/etc/suricata/rules/local.rulesthat detects nmap SYN scans:alert tcp any any -> $HOME_NET any ( msg:"Nmap SYN scan detected"; flags:S,12; threshold:type threshold, track by_src, count 10, seconds 2; sid:9000001; rev:1; ) -
Reference the rule file in
/etc/suricata/suricata.yamlunderrule-files:. -
Reload Suricata rules:
sudo suricatasc -c reload-rules -
Trigger the rule from Kali:
nmap -sS 10.10.10.20 - Confirm the custom rule fires in both
eve.jsonand the Wazuh dashboard. Take a screenshot of the Wazuh alert showing your rule’smsgfield.
File Integrity Monitoring
- On ubuntu-server, configure Wazuh FIM in
/var/ossec/etc/ossec.confto monitor:/etc(all files, check_all=”yes”)/etc/nginx/(all files)- The directory containing your
docker-compose.yml
Set
<frequency>300</frequency>(5-minute check interval). -
Restart the Wazuh agent:
sudo systemctl restart wazuh-agent - Force an immediate FIM baseline scan:
sudo /var/ossec/bin/agent_control -r -u <agent-id> - Simulate post-compromise tampering from ubuntu-server itself:
echo "# tampered" | sudo tee -a /etc/nginx/nginx.conf -
Wait up to 5 minutes, or force a rescan. Confirm the FIM alert fires in the Wazuh dashboard. Take a screenshot showing the modified file path and the before/after hash.
- Restore the file:
sudo sed -i '/# tampered/d' /etc/nginx/nginx.conf
Threat Model — Final
- In
lab02/threat-model.md, mark all remaining OPEN threats with either MITIGATED (and the control), DETECTED (and the Wazuh/Suricata rule), or ACCEPTED RISK (with rationale). By the end of this lab, every original threat entry must have a non-OPEN status.
Deliverables
Create lab14/ in your repo containing:
- Wazuh–Suricata screenshot — Suricata events visible in Security Events dashboard
local.rules— your custom Suricata rule- Custom rule alert screenshot — Wazuh alert showing your rule’s
msgfield triggered by nmap - FIM configuration — the
<syscheck>block fromossec.conf - FIM alert screenshot — Wazuh alert showing
/etc/nginx/nginx.confmodified with before/after hashes - Fully updated
lab02/threat-model.md— every entry resolved (MITIGATED, DETECTED, or ACCEPTED RISK with rationale) lab14/lab14.md— a brief gap analysis: which threats are detected but not prevented, and which remain accepted risk with the reason why
Submission
Commit all files for both parts — lab13/ and lab14/ — and push to your GitLab repo. The lab is considered submitted when the commit appears in GitLab before the due date.