Threat Hunting with Wazuh: SOC Dashboards
Write advanced detection rules, build a SOC dashboard, and hunt threats with Wazuh.
Introduction
30 Second Summary
When attackers break into a system, they don't just look around and leave. They set up hidden ways to come back. Scheduled tasks, rogue accounts, registry keys that run malware on every login. These persistence techniques are what keep security teams up at night.
In this project, you will write 4 advanced detection rules targeting real-world persistence techniques, simulate all 4 attacks, build a custom threat hunting dashboard, and conduct a structured hypothesis-driven threat hunt to identify attacker behavior.
What You'll Build
A complete threat hunting workflow on top of your existing SOC lab, expanding your detection coverage with custom rules, visualizing security data in a purpose-built dashboard, and practicing the exact hunting process SOC analysts use in production.
By the end of this project, you'll have:
- 4 new custom Wazuh detection rules (IDs 100103-100106) mapped to MITRE ATT&CK techniques covering persistence and stealth.
- A custom SOC Threat Hunting Dashboard with a pie chart, vertical bar chart, and data table giving you at-a-glance security visibility.
- A completed structured threat hunt where you formulate a hypothesis, query your SIEM, identify IOCs, and build an attacker activity timeline.
- Secret Mission: Write a formal threat hunt report with executive summary, findings, IOC table, MITRE mapping, and actionable remediation recommendations.
Are there any prerequisites?
This project builds directly on your work from the "Build a Home SOC Lab with Wazuh SIEM" project. You need your Wazuh Docker stack deployed, your Windows endpoint enrolled with Sysmon, and your original custom detection rules (100100-100102) already written.
No new tools are required. You will use the same environment you already have.
Resume Your SOC Lab
Your SOC lab from the previous project has everything you need to start threat hunting: a Wazuh stack running in Docker, a Windows endpoint enrolled with Sysmon, and three custom detection rules already written.
Before writing new rules, you need to confirm all components are healthy. In this step, you will bring the Docker containers back online, verify your agent is reporting in, and confirm your existing rules are still firing.
In this step, get ready to:
- Start the Wazuh Docker containers and verify all three services are running.
- Confirm the dashboard loads and your Windows agent shows Active status.
- Verify your existing custom rules (100100-100102) are loaded by checking for historical alerts.
Start the Docker containers
Your Wazuh containers may have stopped since the last project. You need all three services running before you can access the dashboard or receive alerts.
- Make sure Docker Desktop is running. If it is not, press the Windows key to open your search bar, type Docker Desktop, and press Enter to launch it.
- Wait for Docker Desktop to show "Engine running" in the bottom-left corner before continuing.
- Open a terminal. Press the Windows key, type PowerShell, and press Enter.
- Navigate to your Wazuh Docker directory by running this command:
cd ~/Desktop/wazuh-docker/single-node
- Start all three Wazuh containers by running:
docker compose start
What does this command do?
`docker compose start` resumes existing containers that were previously stopped. It does not recreate them or reset any data inside them.
This means your custom rules, indexed alerts, and agent enrollment all remain intact from the previous project.
- Verify all three containers are running by checking their status:
docker compose ps
You should see three containers listed with status Up: single-node-wazuh.manager-1, single-node-wazuh.indexer-1, and single-node-wazuh.dashboard-1.
Containers not starting?
- If you see an error about the Docker daemon, Docker Desktop is not fully started yet. Wait for the engine status to show "running" and try again.
- If the containers show as "Exited" and won't start, your containers may have been removed. Run docker compose up -d instead to recreate them. Note that custom rules and indexed data will need to be recreated if volumes were deleted.
- If you see a port conflict error, another process is using port 443 or 9200. Close any other local web servers or containers, then retry.
Help me troubleshoot my Wazuh Docker containers not starting
Confirm your dashboard and agent status
With the containers running, you can now access the Wazuh dashboard and verify your Windows endpoint is still enrolled and actively reporting.
- Open your browser and navigate to https://localhost.
- Your browser will show a security warning because the certificate is self-signed. Click Advanced, then Proceed to localhost (or Accept the Risk and Continue in Firefox).
- Log in with username admin and password SecretPassword.
Why does the browser show a warning?
The Wazuh Docker deployment uses a self-signed TLS certificate for HTTPS. Your browser does not trust it by default because no public certificate authority issued it. This is expected for local lab environments.
- Click the upper-left menu icon (the three horizontal lines).
- Expand Agents management and select Summary.
- Confirm your Windows agent appears in the list with status Active.
Agent showing Disconnected?
- Make sure the Wazuh agent service is running on your Windows machine. Open Services (press the Windows key, type Services), find Wazuh Agent, and click Start if it is stopped.
- Wait 1-2 minutes after starting the agent service. The dashboard needs time to receive the agent's first keepalive before updating the status.
Help me get my Wazuh agent reconnected to the manager
Verify your existing custom rules are loaded
Your previous project created three custom detection rules (100100-100102) that detect PowerShell downloads, certutil abuse, and Defender tampering. You need to confirm these rules are still loaded and have generated historical alerts.
- In the Wazuh dashboard, click Threat Hunting in the sidebar navigation menu.
- In the search bar at the top, type the following filter and press Enter:
rule.id:(100100 OR 100101 OR 100102)
- Confirm that you see historical alerts from the previous project. These alerts prove your custom rules survived the container restart and are still active in the Wazuh manager.
What if I see no alerts?
If you completed the previous project and triggered all three rules, you should see at least one alert per rule. If you see zero results, expand the time range picker in the top-right corner of the Threat Hunting module. Set it to cover the date range when you completed the first project.
If you still see nothing after expanding the time range, your alert index data may have been lost (e.g., Docker volumes were deleted). Your rules will still work. You will confirm they fire correctly in Step 3 when you simulate new attacks.
Threat Hunting page not loading?
- Give the indexer 2-3 minutes after container start to fully initialize. Refresh the page and try again.
- If you see a red banner about index patterns, the wazuh-alerts-* index may not exist yet. This resolves itself once the manager generates at least one alert. Proceed to Step 3 and come back to verify after simulating attacks.
Help me fix the Threat Hunting module not showing data
Your SOC lab is back online and healthy. Next up, you will write four new detection rules targeting persistence techniques that real attackers use to survive reboots and maintain long-term access.
Write Advanced Detection Rules
Your Docker containers are running, your agent is reporting in, and your original rules are loaded. Now it is time to expand your detection coverage into a critical gap: persistence.
Attackers use persistence techniques to survive reboots and maintain access even after their initial entry point is closed. Your current rules catch download activity and defense evasion, but they are blind to an attacker planting scheduled tasks, creating rogue accounts, or modifying registry Run keys.
In this step, get ready to:
- Write 4 new custom detection rules (100103-100106) covering Scheduled Tasks, Local Account Creation, BITS Jobs, and Registry Run Keys.
- Restart the Wazuh manager to load the updated ruleset.
- Confirm all containers are healthy after the restart.
Open a shell in the Wazuh manager and write the rules
Each new rule chains off Sysmon Event ID 1 (process creation, parent rule 92000) and uses PCRE2 regex to match specific attacker command-line patterns. You will overwrite the entire local_rules.xml file with a version that includes both your original 3 rules and the 4 new ones.
- Open a shell inside the Wazuh manager container by running this command:
docker exec -it single-node-wazuh.manager-1 bash
What does this command do?
This opens an interactive bash session inside the running Wazuh manager container. You are now working directly inside the container's filesystem where the rules engine lives.
- Write the updated rules file containing all 7 rules by running this command inside the container:
cat > /var/ossec/etc/rules/local_rules.xml << 'EOF'
<group name="custom_soc_lab,windows,">
<rule id="100100" level="10">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)(Invoke-WebRequest|wget|curl|DownloadFile|DownloadString)</field>
<description>PowerShell download activity detected on $(win.system.computer).</description>
<mitre>
<id>T1105</id>
</mitre>
</rule>
<rule id="100101" level="10">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)certutil.*(-urlcache|-decode)</field>
<description>Certutil used for download or decode on $(win.system.computer).</description>
<mitre>
<id>T1140</id>
</mitre>
</rule>
<rule id="100102" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)Set-MpPreference.*-DisableRealtimeMonitoring</field>
<description>Attempt to disable Windows Defender real-time protection on $(win.system.computer).</description>
<mitre>
<id>T1562.001</id>
</mitre>
</rule>
<rule id="100103" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)schtasks.*/create</field>
<description>Scheduled task creation detected on $(win.system.computer). Possible persistence mechanism.</description>
<mitre>
<id>T1053.005</id>
</mitre>
</rule>
<rule id="100104" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)net\s+user.*\/add</field>
<description>New local user account created on $(win.system.computer). Possible persistence via rogue account.</description>
<mitre>
<id>T1136.001</id>
</mitre>
</rule>
<rule id="100105" level="10">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)bitsadmin.*\/transfer</field>
<description>BITS job transfer detected on $(win.system.computer). Possible stealthy file download.</description>
<mitre>
<id>T1197</id>
</mitre>
</rule>
<rule id="100106" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)reg\s+add.*CurrentVersion\\\\Run</field>
<description>Registry Run key modification detected on $(win.system.computer). Possible persistence mechanism.</description>
<mitre>
<id>T1547.001</id>
</mitre>
</rule>
</group>
EOF
What do the 4 new rules detect?
- Rule 100103 (level 12) detects schtasks /create commands. Attackers use Scheduled Tasks (MITRE T1053.005) to run malicious code on a timer or at logon.
- Rule 100104 (level 12) detects net user /add commands. Rogue local accounts (MITRE T1136.001) give attackers a backup way in even if you close their original access.
- Rule 100105 (level 10) detects bitsadmin /transfer commands. BITS Jobs (T1197) are stealthy because transfers survive reboots and bypass many security controls. This rule is level 10 (not 12) because BITS is also used legitimately by Windows Update.
- Rule 100106 (level 12) detects reg add commands targeting the CurrentVersion\Run registry key. Registry Run Keys (MITRE T1547.001) execute a program every time a user logs in.
Why use a heredoc with single-quoted EOF?
The single quotes around EOF tell bash to treat the content literally. Without them, bash would try to interpret $(win.system.computer) as a command substitution and break your XML.
Verify the XML and restart the Wazuh manager
- Read the file back to confirm it was written correctly by running:
cat /var/ossec/etc/rules/local_rules.xml
- Confirm you see all 7 rules (IDs 100100 through 100106) in the output. Each rule should have its own <rule> block with the correct <mitre> ID.
- Restart the Wazuh manager to load the new rules by running:
systemctl restart wazuh-manager
You should see no error output. The command may take a few seconds to complete as all Wazuh daemons stop and restart.
Seeing a systemctl error inside the container?
- Some Docker environments do not support systemctl inside containers. If you see an error about systemd or dbus, use the Wazuh process control script instead: /var/ossec/bin/wazuh-control restart.
- If the restart fails with an XML parsing error, your rules file has a syntax issue. Run cat /var/ossec/etc/rules/local_rules.xml and check for missing closing tags or mismatched angle brackets.
Help me troubleshoot my Wazuh manager restart failure.
Exit the container and confirm all services are healthy
- Exit the container shell by running:
exit
- Confirm all three containers are running by navigating to your wazuh-docker/single-node/ directory and running:
docker compose ps
You should see all three containers listed with a status of Up: single-node-wazuh.manager-1, single-node-wazuh.indexer-1, and single-node-wazuh.dashboard-1.
Manager container not showing Up?
- If the manager container exited, an XML syntax error in your rules file is the most common cause. Re-enter the container with docker exec -it single-node-wazuh.manager-1 bash and check the rules file for typos.
- If the container will not start at all, check its logs with docker logs single-node-wazuh.manager-1 to see the specific error message.
Help me fix my Wazuh manager container.
✔️ Awesome, I've got everything!
Great. Double check that all three containers show Up status in your docker compose ps output.
ⓧ I'd like to double check the full code
Here is the complete /var/ossec/etc/rules/local_rules.xml file with all 7 rules:
<group name="custom_soc_lab,windows,">
<rule id="100100" level="10">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)(Invoke-WebRequest|wget|curl|DownloadFile|DownloadString)</field>
<description>PowerShell download activity detected on $(win.system.computer).</description>
<mitre>
<id>T1105</id>
</mitre>
</rule>
<rule id="100101" level="10">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)certutil.*(-urlcache|-decode)</field>
<description>Certutil used for download or decode on $(win.system.computer).</description>
<mitre>
<id>T1140</id>
</mitre>
</rule>
<rule id="100102" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)Set-MpPreference.*-DisableRealtimeMonitoring</field>
<description>Attempt to disable Windows Defender real-time protection on $(win.system.computer).</description>
<mitre>
<id>T1562.001</id>
</mitre>
</rule>
<rule id="100103" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)schtasks.*/create</field>
<description>Scheduled task creation detected on $(win.system.computer). Possible persistence mechanism.</description>
<mitre>
<id>T1053.005</id>
</mitre>
</rule>
<rule id="100104" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)net\s+user.*\/add</field>
<description>New local user account created on $(win.system.computer). Possible persistence via rogue account.</description>
<mitre>
<id>T1136.001</id>
</mitre>
</rule>
<rule id="100105" level="10">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)bitsadmin.*\/transfer</field>
<description>BITS job transfer detected on $(win.system.computer). Possible stealthy file download.</description>
<mitre>
<id>T1197</id>
</mitre>
</rule>
<rule id="100106" level="12">
<if_sid>92000</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)reg\s+add.*CurrentVersion\\\\Run</field>
<description>Registry Run key modification detected on $(win.system.computer). Possible persistence mechanism.</description>
<mitre>
<id>T1547.001</id>
</mitre>
</rule>
</group>
Your detection rules are loaded and ready. Next up, you will simulate all 4 attacks on your Windows endpoint and watch each rule fire in real time.
Simulate Attacks and Validate Rules
Your detection rules are loaded and ready. Now you need to prove they actually work by triggering each one with the same commands a real attacker would use.
In this step, you will run native Windows commands that simulate four persistence techniques. Sysmon captures each process creation, Wazuh matches the command line against your rules, and alerts appear in the dashboard with their MITRE ATT&CK technique IDs.
In this step, get ready to:
- Simulate scheduled task creation and local account creation (T1053.005, T1136.001).
- Simulate BITS job transfer and registry Run key modification (T1197, T1547.001).
- Validate all 4 alerts in the Wazuh Threat Hunting module with correct MITRE mappings.
Simulate scheduled task and local account creation
The first two attacks target persistence. An attacker creates a scheduled task to run malware on a timer, and creates a rogue local account as a backup way in.
- Press the Windows key to open your search bar.
- Type PowerShell, then click Run as administrator.
- Click Yes on the User Account Control prompt.
Why run as administrator?
Several of these commands (like creating user accounts) require elevated privileges. Running PowerShell as administrator ensures all four simulations succeed without permission errors.
- Simulate T1053.005 (Scheduled Task creation) by running this command:
schtasks /create /tn "SOCLabTest" /tr "C:\temp\test.exe" /sc once /st 23:59
What does this command do?
This creates a Windows scheduled task named SOCLabTest that would execute C:\temp\test.exe at 11:59 PM. The executable does not need to exist. What matters is that Sysmon captures the schtasks /create command line, which triggers rule 100103.
- Simulate T1136.001 (Local Account Creation) by running this command:
net user hacker Password123! /add
What does this command do?
This creates a local Windows user account named hacker. Real attackers create rogue accounts so they can log back in even if the original access method is discovered and closed. Sysmon captures the net user /add command line, triggering rule 100104.
Both commands should complete with a success message. The alerts are already generated the moment Sysmon captures the process creation.
- Clean up the scheduled task by running:
schtasks /delete /tn "SOCLabTest" /f
- Clean up the rogue user account by running:
net user hacker /delete
Both cleanup commands should confirm the deletion succeeded. The alerts in Wazuh are permanent records. Removing the artifacts from your host does not remove the alerts.
Seeing "Access is denied"?
Make sure you launched PowerShell with Run as administrator. The net user /add command requires elevated privileges. Close your current PowerShell window and reopen it by right-clicking and selecting Run as administrator.
Help me troubleshoot permission errors when running attack simulations in PowerShell.
Simulate BITS job and registry Run key persistence
The next two attacks use stealthier techniques. BITS Jobs abuse a legitimate Windows service to download files under the radar. Registry Run keys ensure malware launches every time a user logs in.
- Create the destination directory for the BITS transfer by running:
mkdir C:\temp 2>$null
- Simulate T1197 (BITS Jobs) by running this command:
bitsadmin /transfer SOCLabTest /download /priority foreground https://example.com/test.txt C:\temp\test.txt
What does this command do?
This uses the Background Intelligent Transfer Service (BITS) to download a file. Attackers favor BITS because transfers are stealthy, survive reboots, and bypass many network security controls. The download target is harmless. What matters is that Sysmon captures the bitsadmin /transfer command line, triggering rule 100105.
This command may take a moment to complete or may show an error if the URL is unreachable. Either outcome is fine. The detection fires on the process creation, not on whether the download succeeded.
- Simulate T1547.001 (Registry Run Key persistence) by running this command:
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v SOCLabTest /t REG_SZ /d "C:\temp\test.exe" /f
What does this command do?
This adds a value to the Windows Registry Run key. Any program listed under CurrentVersion\Run automatically launches every time the user logs in. Attackers use this to survive reboots without needing a separate service or scheduled task. Sysmon captures the reg add command line, triggering rule 100106.
- Clean up the BITS job by running:
bitsadmin /cancel SOCLabTest
- Clean up the registry Run key by running:
reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v SOCLabTest /f
Both cleanup commands should confirm deletion. All four attack simulations are now complete and cleaned up.
BITS cancel says the job was not found?
If the BITS transfer already completed or errored out, the job may have been removed automatically. This is fine. The important thing is that the bitsadmin /transfer command already ran and Sysmon captured it. The detection alert will still appear in Wazuh.
Help me troubleshoot bitsadmin cleanup issues in my SOC lab.
Validate all 4 alerts in the Wazuh dashboard
With all four attacks simulated, your Wazuh instance should have processed the Sysmon events and generated alerts. Time to confirm every rule fired correctly.
- Switch back to your browser with the Wazuh dashboard at https://localhost.
- Click Threat Hunting in the sidebar navigation menu.
- In the search bar at the top of the events list, type rule.id:100103 OR rule.id:100104 OR rule.id:100105 OR rule.id:100106 and press Enter.
You should see alerts for all 4 rule IDs. Expand any alert to confirm the MITRE technique ID (T1053.005, T1136.001, T1197, or T1547.001) appears in the event details.
What should I see?
Each alert row shows the rule description, severity level, and timestamp. When you expand an alert, look for the rule.mitre.id field to confirm the correct technique mapping. You should see one alert per technique:
- Rule 100103: "Scheduled task creation detected" with T1053.005.
- Rule 100104: "New local user account created" with T1136.001.
- Rule 100105: "BITS job transfer detected" with T1197.
- Rule 100106: "Registry Run key modification detected" with T1547.001.
Alerts not showing up yet?
Wazuh can take 1-2 minutes to process and index new events. If you do not see all 4 alerts, wait a minute and refresh the page. Also check that your time filter in the top-right corner covers the last 15 minutes.
- Click on your agent name in the sidebar to open the agent view.
- Click MITRE ATT&CK in the agent's navigation menu.
This module shows a matrix view of all MITRE techniques your rules have detected. You should see coverage across the Persistence tactic from your new rules, plus any techniques triggered by your original rules (100100-100102).
Why does MITRE coverage matter?
Real SOC teams measure their detection coverage against the MITRE ATT&CK matrix. Gaps in coverage mean blind spots where attackers can operate undetected. Your 7 custom rules now cover techniques across multiple tactics: Execution, Defense Evasion, and Persistence.
Still missing some alerts?
If specific rule IDs are missing, return to the previous step and confirm your local_rules.xml has the correct regex for that rule. A common issue is the net user rule (100104) which uses \s+ to match the space between net and user. Also verify the Wazuh manager was restarted after saving the rules file.
Help me figure out why my custom Wazuh rules are not generating alerts.
All four detection rules are validated end-to-end. Your SIEM detects real persistence techniques the moment they happen. Next up, you will build a custom dashboard that makes this alert data visual and actionable for threat hunting.
Build a Threat Hunting Dashboard
Your detection rules are firing and the SIEM is collecting evidence of attacker behavior across multiple persistence techniques.
Raw alerts are useful, but scrolling through individual events is slow and error-prone. A purpose-built dashboard gives you an at-a-glance view of your threat landscape. In this step, you will create three visualizations and combine them into a custom threat hunting dashboard.
In this step, get ready to:
- Create a pie chart showing MITRE technique distribution across your alerts.
- Create a bar chart and data table for alert severity analysis.
- Assemble all visualizations into a custom SOC dashboard.
Create the MITRE Technique Distribution pie chart
The pie chart gives you instant visibility into which MITRE ATT&CK techniques are most active in your environment. Each slice represents a different technique ID.
- Click the upper-left menu icon (three horizontal lines) in the Wazuh dashboard.
- Select Explore, then click Visualize.
- Click Create new visualization.
- Select the Pie visualization format.
- Choose wazuh-alerts-* as the index pattern.
Now configure the chart's data source and slicing logic.
- In the Data section, under Slice size in Metrics, set Aggregation to Count.
- Click Add under Buckets, then select Split slices.
- Set Aggregation to Terms.
- Set Field to rule.mitre.id.
- Set Order by to Metric: Count.
- Set Order to Descending.
- Set Size to 10.
- Click the Update button to preview the chart.
You should see a pie chart with slices for each MITRE technique ID that has fired alerts (T1053.005, T1136.001, T1197, T1547.001, and others from your earlier project).
- Click the Save button in the top right corner.
- Enter MITRE Technique Distribution as the title.
- Click Save to confirm.
Why a pie chart for technique distribution?
SOC analysts need to quickly identify which attack techniques dominate their environment. A pie chart gives you proportional awareness at a glance.
If one slice is disproportionately large, it indicates a focused campaign or a noisy detection rule that may need tuning.
Pie chart showing no data?
Make sure your time range (top right of the dashboard) covers the period when you ran your attack simulations. Try setting it to Last 24 hours or Last 7 days.
Also confirm you selected wazuh-alerts-* as the index pattern, not a different one.
Help me troubleshoot my empty pie chart
Create the Alert Severity and High Severity Detail visualizations
The bar chart shows you when alerts spike over time, colored by severity level. The data table provides a drill-down view of exactly which rules are firing.
Start with the vertical bar chart.
- Click the upper-left menu icon.
- Select Explore, then click Visualize.
- Click Create new visualization.
- Select the Vertical Bar visualization format.
- Choose wazuh-alerts-* as the index pattern.
Configure the axes and series split.
- Under Metrics, confirm the Y-axis Aggregation is set to Count.
- Under Buckets, click Add and select X-axis.
- Set Aggregation to Date Histogram.
- Set Field to timestamp.
- Click Add again under Buckets and select Split series.
- Set Sub aggregation to Terms.
- Set Field to rule.level.
- Click the Update button to preview.
You should see bars grouped by time with different colors representing severity levels (10 and 12 from your rules).
- Click Save in the top right corner.
- Enter Alert Severity Over Time as the title.
- Click Save to confirm.
What does this chart tell you?
When hunting threats, timeline matters. A cluster of high-severity alerts in a short window suggests a coordinated attack. Scattered alerts over days may indicate slow-and-low persistence activity.
This chart helps you spot those patterns immediately.
Now create the data table for detailed alert breakdowns.
- Click the upper-left menu icon.
- Select Explore, then click Visualize.
- Click Create new visualization.
- Select the Data Table visualization format.
- Choose wazuh-alerts-* as the index pattern.
Configure the table rows and sub-buckets.
- Under Metrics, confirm Aggregation is set to Count.
- Under Buckets, click Add and select Split rows.
- Set Aggregation to Terms.
- Set Field to rule.description.
- Set Size to 20.
- Click Add again under Buckets and select Split rows to add a sub-bucket.
- Set Sub aggregation to Terms.
- Set Field to rule.mitre.id.
- Click the Update button to preview.
You should see a table with rule descriptions, their alert counts, and the associated MITRE technique IDs.
- Click Save in the top right corner.
- Enter High Severity Alert Details as the title.
- Click Save to confirm.
Not seeing the fields you expect?
If a field like rule.mitre.id does not appear in the dropdown, start typing the field name in the search box. The field list can be long and the one you need may not be visible without filtering.
Help me find the right field in my Wazuh visualization
Assemble the SOC Threat Hunting Dashboard
Individual visualizations are helpful, but a combined dashboard lets you see all three perspectives at once. This is what SOC analysts use during active threat hunts.
- Click the upper-left menu icon.
- Select Explore, then click Dashboards.
- Click Create new dashboard.
- Click Add an existing in the toolbar.
- Select MITRE Technique Distribution from the list.
- Select Alert Severity Over Time from the list.
- Select High Severity Alert Details from the list.
- Close the add panel by clicking the X or clicking outside it.
Arrange the panels by dragging them into a layout that works for you. A common layout places the pie chart in the top left, the bar chart in the top right, and the data table spanning the full width below.
- Click Save in the top right corner.
- Enter SOC Threat Hunting Dashboard as the dashboard title.
- Click Save to confirm.
Your dashboard is now saved. You should see all three visualizations populated with your alert data from the attack simulations.
What makes this dashboard useful for threat hunting?
Each visualization answers a different hunting question. The pie chart answers "which techniques are most active?" The bar chart answers "when did activity spike?" The data table answers "what exactly fired and which MITRE technique does it map to?"
Together, they let you form and test hypotheses without writing queries from scratch every time.
Dashboard shows empty panels?
Check the time picker in the top right corner of the dashboard. Set it to cover the time period when your attack simulations ran. Each visualization inherits the dashboard's time range.
If one panel is empty but others have data, return to Explore > Visualize, open that visualization directly, and verify its field configuration matches the instructions above.
Help me fix my empty dashboard panels
Your threat hunting dashboard is ready. Next up, you will use it to conduct a structured, hypothesis-driven threat hunt across your alert data.
Conduct a Structured Threat Hunt
You now have detection rules that fire and a custom dashboard that visualizes attack data. The missing piece is the analyst workflow that ties them together.
In this step, you will perform a hypothesis-driven threat hunt. This means starting with a specific theory about attacker behavior, then using your SIEM data to prove or disprove it. This is the exact process SOC analysts follow in production environments.
In this step, get ready to:
- Formulate a threat hunt hypothesis about attacker persistence.
- Query and investigate persistence alerts using the Discover module.
- Document IOCs, build an attacker timeline, and confirm your hypothesis.
Formulate your hypothesis and review the dashboard
Every structured threat hunt begins with a hypothesis. A hypothesis is a specific, testable statement about what an attacker may have done on your systems.
What is a threat hunting hypothesis?
A hypothesis gives your hunt direction. Instead of aimlessly scrolling through logs, you search for specific evidence that supports or refutes your theory.
A good hypothesis is scoped to one tactic or technique family. "Something bad happened" is too vague. "An attacker established persistence mechanisms on this endpoint" is specific enough to hunt for.
Your hypothesis for this hunt is:
"An attacker has established multiple persistence mechanisms on this Windows endpoint."
- Return to your SOC Threat Hunting Dashboard in the Wazuh dashboard.
- If you navigated away, click the upper-left menu icon, then Explore, then Dashboards.
- Select SOC Threat Hunting Dashboard from the list.
- Look at the MITRE Technique Distribution pie chart.
The pie chart shows which MITRE ATT&CK technique IDs have fired. You should see slices for your persistence-related techniques: T1053.005 (Scheduled Task), T1136.001 (Local Account Creation), T1197 (BITS Jobs), and T1547.001 (Registry Run Keys).
What should I see?
The pie chart shows the relative distribution of alerts by technique ID. If all 4 persistence techniques appear as slices, you already have preliminary evidence supporting your hypothesis.
You may also see slices for techniques from the previous project (T1105, T1140, T1562.001). That's expected. Focus on the persistence-related slices for now.
- Note which persistence techniques appear in the chart and their relative proportions.
- Check the Alert Severity Over Time bar chart to see when the persistence alerts fired.
- Check the High Severity Alert Details table to see which rule descriptions correspond to your persistence rules.
Your dashboard gives you the high-level picture. The pie chart tells you what happened. The bar chart tells you when. The table tells you the details. Now you need to dig deeper into the raw event data.
Investigate persistence events in the Discover module
The dashboard shows aggregated views. To investigate individual events, you need the Discover module, which lets you query raw alert data and expand individual events to see every field.
- Click the upper-left menu icon.
- Click Explore, then Discover.
- Make sure the index pattern is set to wazuh-alerts-* in the dropdown on the left.
Now apply a filter to narrow your results to persistence-related alerts only.
- Click Add filter (below the search bar).
- Set the field to rule.mitre.tactic.
- Set the operator to is.
- Set the value to Persistence.
- Click Save to apply the filter.
- Add a second filter for your agent name. Set the field to agent.name, operator to is, and the value to your Windows agent's name.
- Click Save to apply.
You should now see a filtered list of events related to the Persistence tactic from your endpoint.
Not seeing any results?
Check the time range in the upper-right corner of the Discover view. If it's set to a short window (e.g., last 15 minutes), expand it to cover when you ran your attack simulations.
Also confirm the spelling of the filter value. The tactic name is Persistence with a capital P.
Help me troubleshoot my Discover module filters in Wazuh.
Now investigate the individual events to extract the attacker's exact commands.
- Click the expand arrow (>) on the first event in the results list.
- Locate the win.eventdata.commandLine field. This shows the exact command that triggered the alert.
- Locate the win.eventdata.user field. This shows which user account ran the command.
- Note the timestamp field at the top of the expanded event.
- Repeat this for each event in the filtered results. Record the command line, user, and timestamp for each one.
What am I building here?
By expanding each event, you are building a timeline of attacker activity. Each expanded event gives you an IOC (Indicator of Compromise), the user context, and the exact time it occurred.
In a real SOC, this is how analysts reconstruct what an attacker did, in what order, and with what level of access.
You should find events matching all 4 persistence techniques. Each event's win.eventdata.commandLine field reveals the attacker's exact command.
Document your threat hunt findings
The final step of any threat hunt is documenting what you found. This transforms raw observations into actionable intelligence.
- List the IOCs (Indicators of Compromise) you identified. You should have at least 4:
- The schtasks /create command used to create a scheduled task (T1053.005).
- The net user /add command used to create a rogue local account (T1136.001).
- The bitsadmin /transfer command used for stealthy file download (T1197).
- The reg add command modifying the CurrentVersion\Run registry key (T1547.001).
- Build a timeline by ordering your events from earliest to latest based on the timestamps you recorded.
- For each event in your timeline, note which MITRE ATT&CK technique it maps to and under which tactic (all 4 fall under Persistence).
- Determine whether your hypothesis is confirmed or refuted.
Is the hypothesis confirmed?
If you found evidence of multiple persistence mechanisms on the endpoint (scheduled task, rogue account, BITS job, registry Run key), your hypothesis is confirmed. The attacker did establish multiple persistence paths.
In a real environment, confirming a persistence hypothesis would trigger an incident response workflow. The next action would be to remove all persistence artifacts and rotate affected credentials.
- Write a short summary of your findings. Include your hypothesis, the IOCs you found, the timeline, the confirmed MITRE techniques, and your conclusion.
Structure your summary clearly
A clean format for your summary is: Hypothesis at the top, then a numbered timeline of events (timestamp + command + technique ID), then your conclusion (confirmed/refuted + reasoning). Keep it concise. You will expand this into a full formal report in the Secret Mission.
You just completed a full hypothesis-driven threat hunt, the same process professional SOC analysts use daily. You went from a theory, to data, to evidence, to conclusions. That's the core of threat hunting.
Secret mission
Write a Formal Threat Hunt Report
SOC analysts don't just find threats. They communicate them. Can you write a professional-grade mini threat hunt report that would pass review by a SOC manager?
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally using Docker containers, so there are no ongoing monetary costs. However, the Wazuh stack consumes approximately 4GB of RAM while running. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Docker containers (single-node-wazuh.manager-1, single-node-wazuh.indexer-1, single-node-wazuh.dashboard-1) consuming approximately 4GB RAM while running.
- Custom detection rules (IDs 100100-100106) stored inside the manager container volume at /var/ossec/etc/rules/local_rules.xml.
- Saved visualizations and SOC Threat Hunting Dashboard stored in the Wazuh indexer.
- threat_hunt_report.md file on your local machine (Secret Mission).
Keep everything running
No action needed. Choose this if you are still actively building or plan to extend your lab with more detection rules and dashboards.
- Your Wazuh stack continues collecting telemetry from your Windows endpoint.
- Your SOC Threat Hunting Dashboard and all saved visualizations remain accessible at https://localhost.
- All 7 custom detection rules (100100-100106) continue firing on matching events.
Pause - I'll come back to this later
Shut down running containers to free up RAM. Your data, rules, and dashboards are preserved in Docker volumes and will be available when you start them again.
- Open your terminal and navigate to the wazuh-docker/single-node/ directory.
- Stop the containers by running:
docker compose stop
- When you want to resume, navigate back to wazuh-docker/single-node/ and run:
docker compose start
- Verify everything is back by running docker compose ps and confirming all three containers show as Up.
Delete - I don't want to use this again
Remove all containers, volumes, indexed data, custom rules, and saved dashboards permanently. This cannot be undone.
- Open your terminal and navigate to the wazuh-docker/single-node/ directory.
- Remove all containers and volumes by running:
docker compose down -v
What does this remove?
The -v flag removes all Docker volumes associated with the stack. This permanently deletes your custom detection rules (local_rules.xml), all indexed alert data, and your saved visualizations and dashboard.
- Confirm the containers are gone by running:
docker compose ps
You should see no containers listed.
- If you completed the Secret Mission, delete your local report file. In PowerShell, navigate to the folder where you saved it and run:
Remove-Item threat_hunt_report.md
- If you want to remove the entire wazuh-docker repository folder from your machine, navigate to the parent directory and run:
Remove-Item -Recurse -Force wazuh-docker
Nice Work!
Nice Work!
You just built a complete threat hunting workflow on top of your SOC lab. You went from writing custom detection rules all the way through to conducting a structured hunt and identifying attacker persistence across your environment.
You've learned how to:
- Write custom Wazuh detection rules targeting persistence techniques (Scheduled Tasks, Account Creation, BITS Jobs, Registry Run Keys) and map them to MITRE ATT&CK technique IDs.
- Build a custom SOC Threat Hunting Dashboard with three visualizations (pie chart, vertical bar chart, data table) providing at-a-glance security visibility across your environment.
- Conduct a structured, hypothesis-driven threat hunt using the Discover module to identify IOCs and build an attacker activity timeline.
- Secret Mission: Wrote a formal threat hunt report with an executive summary, findings, IOC table, MITRE mapping, and actionable remediation recommendations.
Ready to quiz yourself?