Build a SOC Home Lab with Wazuh SIEM
Deploy a SIEM, simulate a brute-force attack, and write an incident report.
Introduction
30 Second Summary
Every company with a computer network needs someone watching for attackers trying to break in. Security Operations Center (SOC) analysts are the people who monitor security alerts, investigate suspicious activity, and respond to threats. The skill that gets you hired isn't memorizing textbook definitions. It's proving you can actually detect and investigate an attack.
In this project, you will deploy an enterprise-grade SIEM (Security Information and Event Management) tool called Wazuh on your local machine, simulate a real brute-force attack against it, write a custom detection rule that catches the attack, and produce a professional incident report for your portfolio.
What You'll Build
A complete SOC detection pipeline running locally using Docker, from deploying the SIEM to documenting your investigation in a professional report.
By the end of this project, you'll have:
- A running Wazuh SIEM with a web dashboard you can log into and explore.
- A custom detection rule mapped to the MITRE ATT&CK framework that fires when you simulate a brute-force SSH attack.
- A professional incident report documenting the attack, your investigation, and your response, ready for your portfolio.
- Secret Mission: Configure Wazuh Active Response to automatically block the attacker's IP address when your brute-force rule fires.
Are there any prerequisites?
You'll need a Windows 10 or 11 PC with at least 8GB of RAM and hardware virtualization enabled in your BIOS. This project uses WSL 2 (Windows Subsystem for Linux) and Docker Desktop, both of which you'll install in Step 1.
No prior cybersecurity experience is required. You'll learn Linux basics, Docker, and SIEM operations as you go.
Install WSL 2 and Docker Desktop
Your SOC home lab runs entirely inside Docker containers on your Windows machine. To make that work, you need two foundational pieces: WSL 2 (Windows Subsystem for Linux) to provide a real Linux kernel, and Docker Desktop to manage the containers.
In this step, you will install WSL 2 with Ubuntu, install Docker Desktop for Windows, and confirm everything is connected by running a test container from your Linux terminal.
In this step, get ready to:
- Install WSL 2 with Ubuntu on your Windows machine.
- Install Docker Desktop for Windows with the WSL 2 backend.
- Verify Docker is working from the WSL 2 terminal.
Install WSL 2 with Ubuntu on your Windows machine
WSL 2 gives your Windows PC a full Linux kernel without needing a separate virtual machine. Docker Desktop uses this kernel to run containers efficiently on Windows.
- Open PowerShell as Administrator by right-clicking the Start menu and selecting Terminal (Admin) or Windows PowerShell (Admin).
- Install WSL 2 and the default Ubuntu distribution by running this command:
wsl --install
What does this command do?
The wsl --install command enables the WSL and Virtual Machine Platform features, downloads the latest Linux kernel, sets WSL 2 as the default version, and installs the Ubuntu distribution.
- When the command finishes, restart your computer. Windows requires a reboot to activate the new kernel components.
- After your PC restarts, an Ubuntu terminal window opens automatically. It will ask you to create a UNIX username and password.
- Enter a username (all lowercase, no spaces) and a password you will remember. This password is used for sudo commands later.
Your password won't show as you type
When Linux prompts for a password, no characters appear on screen as you type. This is normal Linux security behavior. Type your password and press Enter.
- Verify WSL 2 is working by opening a new PowerShell window and running:
wsl --list --verbose
✔️ I see Ubuntu listed with VERSION 2
WSL 2 is ready to go. You should see a line showing Ubuntu with 2 in the VERSION column. Move on to the next substep.
ⓧ I see the WSL help text instead
This means WSL is already partially installed on your machine but no distribution is registered.
- Run the following command to explicitly install Ubuntu:
wsl --install -d Ubuntu
- Restart your computer when prompted, then complete the Ubuntu username and password setup.
ⓧ Command not found or error
Your Windows version may not support the simplified install command.
- Press Windows key + R, type winver, and press Enter.
- Confirm you are running Windows 10 version 2004 (Build 19041) or higher, or Windows 11.
- If your build is older, update Windows through Settings then Windows Update, then try wsl --install again.
Install Docker Desktop for Windows with the WSL 2 backend
Docker Desktop provides the container engine that will run your Wazuh SIEM stack. It integrates directly with WSL 2 so your Linux terminal can manage containers.
- Open your web browser and go to the Docker Desktop install page:
- https://docs.docker.com/desktop/setup/install/windows-install/
- Click the download button for Docker Desktop for Windows - x86_64.
- Double-click Docker Desktop Installer.exe to run the installer.
- When the installer asks about the backend, make sure Use WSL 2 instead of Hyper-V is checked.
- Follow the remaining prompts and click Close when the installation finishes.
- Docker Desktop may prompt you to log out or restart. If it does, complete that step before continuing.
Why Docker Desktop and not just Docker Engine?
Docker Desktop handles the networking bridge between Windows and WSL 2 automatically. Without it, you would need to manually configure the Docker daemon inside WSL, set up networking, and manage startup scripts.
Docker Desktop also includes Docker Compose, which you will use in the next step to deploy the entire Wazuh stack with a single command.
- Launch Docker Desktop by pressing the Windows key, typing Docker Desktop, and pressing Enter.
- Wait for the Docker Desktop window to finish loading. You will see a green status indicator or the Docker dashboard when it is ready.
Now install Git inside your Ubuntu environment so you can clone repositories in the next step.
- Open your Ubuntu terminal by pressing the Windows key, typing Ubuntu, and pressing Enter.
- Install Git by running this command:
sudo apt update && sudo apt install -y git
What does this command do?
The first part (sudo apt update) refreshes the list of available packages from Ubuntu's repositories. The second part (sudo apt install -y git) installs Git without asking for confirmation.
- Enter your Ubuntu password when prompted (the one you created during WSL setup).
- Confirm Git installed successfully by running:
git --version
- You should see a version number like git version 2.x.x in the output.
Seeing permission denied or unable to locate package?
- Make sure you typed sudo at the start of the command. Without it, Ubuntu does not have permission to install packages.
- If you see network errors, check that your Windows internet connection is active. WSL 2 uses your Windows network connection.
Why can't I install Git in WSL?
Verify Docker is working from the WSL 2 terminal
The final check confirms that Docker Desktop is correctly sharing its engine with your WSL 2 environment. If this works, you are ready to deploy Wazuh.
- In your Ubuntu terminal, check the Docker version by running:
docker --version
- You should see output showing a Docker version number.
- Now run a test container to confirm the full pipeline works:
docker run hello-world
✔️ I see Hello from Docker!
Docker is fully working from your WSL 2 terminal. The test container downloaded, ran, and printed its greeting successfully. You are ready to deploy Wazuh.
ⓧ I see a permission denied or connection error
Docker Desktop may not be sharing its engine with your WSL 2 distribution.
- Open Docker Desktop on Windows.
- Click the gear icon (Settings) in the top right.
- Select Resources, then WSL integration.
- Toggle on your Ubuntu distribution.
- Click Apply & restart.
- Return to your Ubuntu terminal and run docker run hello-world again.
ⓧ Command not found
Docker Desktop is either not running or not installed correctly.
- Check that Docker Desktop is running on Windows (look for the whale icon in the system tray near your clock).
- If it is not running, launch it and wait for it to finish starting.
- If it is running, close your Ubuntu terminal, reopen it, and try docker --version again.
Why can't my WSL terminal find Docker?
Your environment is locked and loaded. Next up, you will deploy the full Wazuh SIEM stack using Docker Compose and access your security dashboard for the first time.
Deploy Wazuh SIEM with Docker
Your environment is ready with WSL 2, Docker, and Git all working together. Now it's time to deploy the actual SIEM that will power your SOC lab.
Wazuh is an enterprise-grade, open-source security platform used in production SOCs worldwide. You'll deploy it using Docker Compose, which spins up three containers (a manager, an indexer, and a dashboard) in a single command.
In this step, get ready to:
- Clone the Wazuh Docker repository and generate TLS certificates.
- Configure the kernel memory setting and start the Wazuh stack.
- Access the Wazuh dashboard and log in.
Clone the Wazuh Docker repository and generate certificates
Wazuh provides an official Docker repository with pre-configured compose files for single-node deployments. You'll clone this repository at a specific version tag to ensure a stable, reproducible setup.
- Switch to your WSL 2 Ubuntu terminal.
- Navigate to your home directory by running this command:
cd ~
- Clone the Wazuh Docker repository at version v4.14.5 by running this command:
git clone https://github.com/wazuh/wazuh-docker.git -b v4.14.5
- Wait for the clone to complete. You should see output ending with a message about checking out the branch.
- Navigate into the single-node deployment directory by running:
cd wazuh-docker/single-node/
Why single-node?
Wazuh supports multi-node clusters for high availability in production. For a portfolio home lab, single-node gives you the full SIEM experience (manager, indexer, and dashboard) without the extra RAM overhead of running duplicate services.
The Wazuh containers communicate over TLS, so you need to generate certificates before starting the stack.
- Generate the TLS certificates by running this command:
docker compose -f generate-indexer-certs.yml run --rm generator
What does this command do?
This runs a temporary Docker container (wazuh/wazuh-certs-generator:0.0.4) that creates self-signed TLS certificates for each node in the stack.
The --rm flag removes the generator container after it finishes. The certificates are saved to config/wazuh_indexer_ssl_certs/ on your host.
- Confirm the certificates were generated by running:
ls config/wazuh_indexer_ssl_certs/
- You should see several .pem files listed, including root-ca.pem and files for the indexer, manager, and dashboard.
Not seeing any certificate files?
- Make sure Docker Desktop is running on Windows. The certificate generator runs as a Docker container and needs the Docker daemon.
- Confirm you are inside the wazuh-docker/single-node/ directory by running pwd. The compose file references relative paths.
Help me troubleshoot why my Wazuh certificate generation failed in WSL 2.
Configure the kernel setting and start the stack
The Wazuh indexer (based on OpenSearch) needs a higher virtual memory map limit than the default. Without this setting, the indexer container will crash on startup.
- Set the vm.max_map_count kernel parameter by running this command:
sudo sysctl -w vm.max_map_count=262144
What is vm.max_map_count?
This kernel setting controls the maximum number of memory-mapped areas a process can use. OpenSearch (the indexer engine) requires at least 262144 to function. The default Linux value is too low.
This setting resets when you close WSL 2. You'll need to run this command again if you restart your machine and want to bring the stack back up.
Getting a permission denied error?
- Make sure you included sudo at the start of the command. Setting kernel parameters requires elevated privileges.
- If prompted for a password, enter the password you chose when Ubuntu was first set up in WSL 2.
Help me fix a permission error when setting vm.max_map_count in WSL 2.
Now you're ready to start all three Wazuh containers.
- Start the Wazuh stack in detached mode by running this command:
docker compose up -d
What does this command do?
This starts three containers: the Wazuh manager (collects and analyzes logs), the Wazuh indexer (stores and searches alert data), and the Wazuh dashboard (web UI you'll use to investigate alerts).
The -d flag runs everything in the background so you get your terminal back.
- Wait about 1-2 minutes for all containers to fully initialize.
- Verify all three containers are running by executing:
docker compose ps
- You should see three containers listed with a status of running: wazuh.manager, wazuh.indexer, and wazuh.dashboard.
Seeing containers in a restarting or exited state?
- If the indexer is crashing, confirm you set vm.max_map_count correctly by running sysctl vm.max_map_count. The value should be 262144.
- If containers failed to pull images, check your internet connection and ensure Docker Desktop is running.
- If you see memory-related errors, close other heavy applications on Windows. The Wazuh stack needs significant RAM.
Help me troubleshoot why my Wazuh containers are crashing after docker compose up.
Access the Wazuh dashboard and log in
With all three containers running, you can access the Wazuh dashboard through your Windows browser. Docker Desktop maps port 443 from the dashboard container to your localhost.
- Open your web browser on Windows (Chrome, Edge, or Firefox).
- Navigate to https://localhost in the address bar.
Why does the browser show a security warning?
The certificates you generated earlier are self-signed. Your browser does not recognize the issuing authority, so it displays a warning that it cannot verify the certificate's authenticity.
This is completely expected for a local lab environment. In production, you would use certificates from a trusted certificate authority.
- When you see the certificate warning, click Advanced (or Show Details in Safari).
- Click Proceed to localhost (or Accept the Risk and Continue in Firefox).
- On the login page, enter admin in the Username field.
- Enter SecretPassword in the Password field.
- Click Log In.
You should see the Wazuh dashboard home page with a summary of your environment.
Dashboard not loading?
- The dashboard container can take 1-2 minutes to fully start after docker compose up -d. Wait and refresh the page.
- Make sure you're using https:// (not http://). The dashboard only serves over HTTPS on port 443.
- Run docker compose ps in your WSL 2 terminal and confirm all three containers show running status.
Help me troubleshoot why I can't access the Wazuh dashboard at https://localhost.
Your SIEM is live. Next up, you'll simulate a real brute-force attack against it and watch the alerts roll in.
Simulate a Brute-Force Attack
Your Wazuh SIEM is deployed and watching. Now it needs something to detect.
In a real Security Operations Center, you would be monitoring for threats hitting your infrastructure 24/7. To prove your detection pipeline works, you need to generate real attack traffic. In this step, you will simulate a brute-force SSH attack using Hydra, the same tool penetration testers use in the real world.
In this step, get ready to:
- Install Hydra and set up SSH on the Wazuh manager container.
- Run a brute-force attack and generate authentication failure events.
- Observe the alerts in the Wazuh dashboard Threat Hunting module.
Install Hydra in your WSL 2 environment
Hydra is an open-source login cracker that supports dozens of protocols including SSH. Security professionals use it to test whether systems are vulnerable to brute-force credential attacks.
- Install Hydra by running this command in your WSL 2 Ubuntu terminal:
sudo apt update && sudo apt install -y hydra
What does this command do?
`sudo apt update` refreshes the package list so Ubuntu knows the latest available software versions.
`sudo apt install -y hydra` installs Hydra without prompting for confirmation. The `-y` flag automatically answers "yes" to the installation prompt.
- Confirm Hydra is installed by running:
hydra -h
You should see Hydra's help output listing supported protocols and options.
Command not found?
If you see a "command not found" error, the installation may have failed. Re-run the install command and check for error messages in the output. Make sure you have internet connectivity in your WSL 2 environment.
help me troubleshoot why Hydra didn't install in my WSL 2 Ubuntu environment
Prepare the Wazuh manager container for the attack
The Wazuh manager container does not run an SSH server by default. To simulate a realistic brute-force attack that Wazuh can detect, you need to install and start SSH inside the container. This way, Hydra's login attempts generate real authentication failure logs that the Wazuh manager monitors automatically.
- Open a shell inside the Wazuh manager container by running:
docker exec -it single-node-wazuh.manager-1 bash
- Inside the container, install the OpenSSH server by running:
apt-get update && apt-get install -y openssh-server
- Start the SSH service inside the container by running:
service ssh start
You should see a message indicating that the SSH service has started.
- Exit the container shell by running:
exit
Why install SSH inside the container?
The Wazuh manager monitors its own system logs. When SSH authentication failures occur inside the container, the manager detects them through its built-in rules (like rule 5503 for PAM authentication failures). This is exactly how a real SIEM detects brute-force attacks against monitored endpoints.
- Get the Wazuh manager container's IP address by running:
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' single-node-wazuh.manager-1
Note the IP address that appears (it will be something like `172.x.x.x`). You will use this as the target for your attack.
Container name not found?
If you get an error about the container name, run `docker ps` to see your running containers. The manager container should be named `single-node-wazuh.manager-1`. If the name differs slightly, use the name shown in the output.
help me find my Wazuh manager container name
Create a password list and run the brute-force attack
Real attackers use wordlists containing thousands of common passwords. You will create a small list and use Hydra to attempt each password against the SSH service running in the Wazuh manager container.
- Create a password list file by running:
cat > ~/passwords.txt << EOF
password123
admin
letmein
123456
qwerty
password
12345678
abc123
monkey
master
EOF
What does this command do?
`cat > ~/passwords.txt << EOF` creates a file at `~/passwords.txt` and writes everything between the two `EOF` markers into it. This is called a "heredoc" in bash. The file ends up containing 10 common passwords that Hydra will try one by one against the target.
- Confirm the file was created by running:
cat ~/passwords.txt
You should see all 10 passwords listed one per line.
- Launch the brute-force SSH attack against the Wazuh manager container by running the following command. Replace the IP address with the one you noted earlier:
sudo hydra -l badguy -P ~/passwords.txt [[MANAGER_IP="the container IP you noted earlier (e.g. 172.18.0.2)"]] ssh
What does this command do?
`-l badguy` tells Hydra to use "badguy" as the username for every login attempt. This is a fake username that will definitely fail authentication.
`-P ~/passwords.txt` points Hydra to your password list file. Hydra will try each password in sequence.
The IP address at the end is your target, and `ssh` tells Hydra to use the SSH protocol. Each attempt generates an authentication failure event that Wazuh detects.
Hydra will attempt all 10 passwords and report that none worked. This is expected. The goal is not to gain access. The goal is to generate authentication failure events that your SIEM can detect.
Hydra showing connection errors?
If Hydra reports "Connection refused" or cannot connect, SSH may not be running inside the container. Re-run `docker exec -it single-node-wazuh.manager-1 bash`, then `service ssh start`, then `exit`. Verify SSH is running with `docker exec single-node-wazuh.manager-1 service ssh status`.
help me troubleshoot why Hydra cannot connect to SSH on my Wazuh manager container
Observe the alerts in the Wazuh dashboard
Your attack just generated multiple authentication failure events. The Wazuh manager detected them in real-time using its built-in detection rules. Now you will see those alerts on the dashboard.
- Switch back to your browser with the Wazuh dashboard at `https://localhost`.
- Click the menu icon (three horizontal lines) in the top left corner.
- Select Threat Hunting from the menu.
- Wait 1-2 minutes for the events to be indexed and appear in the dashboard.
What should I see?
You should see authentication failure alerts with rule IDs like 5503, 5710, or 5711. These rules detect PAM authentication failures and invalid SSH login attempts. The alerts will show the username "badguy" and the source IP address from your attack.
You can filter the results by typing `rule.id:(5503 OR 5710 OR 5711 OR 5712)` in the search bar to show only brute-force related alerts.
Give it a minute
The Wazuh indexer needs a moment to process and index new events. If you do not see alerts immediately, wait 1-2 minutes and refresh the page. The alerts will appear under the Threat Hunting module once indexing is complete.
No alerts appearing?
Make sure you waited at least 2 minutes after running the Hydra attack. Check that the Wazuh manager container is still running with `docker ps`. If it shows as running but alerts still do not appear, try running the Hydra attack again to generate fresh events.
help me troubleshoot why brute-force alerts are not showing up in my Wazuh dashboard Threat Hunting module
You just ran a real attack simulation and watched your SIEM detect it in real-time. In the next step, you will write a custom detection rule that goes beyond the defaults and maps directly to the MITRE ATT&CK framework.
Write a Custom Detection Rule with MITRE ATT&CK Mapping
In the previous step, you saw Wazuh generate individual alerts for each failed SSH login attempt. Those alerts come from Wazuh's built-in rule 5760, which fires once per failed password event.
Individual alerts are noisy. A real SOC analyst needs a rule that says "this is a coordinated attack" by correlating multiple failures into a single high-severity alert. That is exactly what you will build in this step.
In this step, get ready to:
- Create a custom detection rule that fires when 5+ SSH login failures occur within 2 minutes.
- Map the rule to MITRE ATT&CK technique T1110 (Brute Force).
- Test, deploy, and verify the rule fires on the Wazuh dashboard.
Create a custom rule in local_rules.xml
Wazuh stores custom detection rules in /var/ossec/etc/rules/local_rules.xml inside the manager. This file is separate from the default ruleset, so your changes survive upgrades.
You will write a frequency-based rule that correlates multiple hits of built-in rule 5760 (individual SSH authentication failures) into a single brute-force alert.
- 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 terminal session inside the running Wazuh manager container. The container name single-node-wazuh.manager-1 comes from the Docker Compose single-node deployment you set up earlier.
- Open the custom rules file for editing by running:
nano /var/ossec/etc/rules/local_rules.xml
No nano? Use vi instead
If nano is not installed in the container, run vi /var/ossec/etc/rules/local_rules.xml instead. Press i to enter insert mode, paste your rule, then press Esc followed by :wq to save and quit.
- Replace the contents of the file with the following custom rule:
<group name="local,syslog,sshd,">
<rule id="100001" level="10" frequency="5" timeframe="120">
<if_matched_sid>5760</if_matched_sid>
<description>SSH brute-force attack detected: 5+ failed logins in 2 minutes</description>
<mitre>
<id>T1110</id>
</mitre>
<group>authentication_failures,</group>
</rule>
</group>
What does this rule do?
This rule correlates multiple individual SSH authentication failure events into a single high-severity alert. Here is how each part works:
- id="100001" assigns a unique ID in the custom rule range (100000-120000).
- level="10" sets a high severity so the alert stands out on the dashboard.
- frequency="5" timeframe="120" means the rule fires when 5 matching events occur within 120 seconds (2 minutes).
- if_matched_sid tells Wazuh which existing rule to correlate against. Rule 5760 is Wazuh's built-in rule for individual SSH authentication failures.
- The <mitre><id>T1110</id></mitre> block maps this detection to the MITRE ATT&CK Brute Force technique.
What is MITRE ATT&CK?
MITRE ATT&CK is a knowledge base of adversary tactics and techniques observed in real-world cyberattacks. SOC teams use it as a common language to classify threats.
T1110 (Brute Force) describes attackers systematically trying many passwords to gain access. Mapping your rule to T1110 means it will appear in Wazuh's MITRE ATT&CK dashboard alongside other detections of the same technique.
- Save the file and exit the editor.
Seeing a permission denied error?
Make sure you ran docker exec with the correct container name single-node-wazuh.manager-1. You should be root inside the container by default. If not, prefix the edit command with sudo.
help me fix permission errors when editing local_rules.xml inside the Wazuh Docker container
Test the rule with wazuh-logtest
Before restarting the manager, Wazuh provides a tool called /var/ossec/bin/wazuh-logtest that lets you test rules against sample log lines without affecting live alerts.
- While still inside the manager container, launch the log test tool by running:
/var/ossec/bin/wazuh-logtest
- Paste the following sample SSH failure log line and press Enter:
Aug 5 13:57:37 wazuh-manager sshd[1234]: Failed password for badguy from 172.17.0.1 port 50948 ssh2
- Paste the same log line at least 5 more times, pressing Enter each time.
After the 5th or 6th paste, you should see output referencing your custom rule ID 100001 with the description "SSH brute-force attack detected: 5+ failed logins in 2 minutes".
- Press Ctrl+C to exit the log test tool.
Why test before restarting?
The wazuh-logtest tool reads your saved rule files without needing a restart. This lets you catch XML typos or logic errors before they affect production alerts. If you see a parsing error instead of the expected rule match, check your XML for missing closing tags.
Rule not matching after 5+ pastes?
Make sure you pasted the same log line at least 6 times (the frequency threshold is 5 additional matches after the first). Also confirm if_matched_sid is set to 5760 in your rule, not another ID.
help me debug why my custom Wazuh rule 100001 is not firing in wazuh-logtest after pasting multiple SSH failure log lines
Restart the manager and verify the rule fires on the dashboard
Testing confirmed your rule works. Now you need to restart the Wazuh manager so it loads the new rule for real-time alerting.
- Exit the container shell by running:
exit
- Navigate to the single-node directory and restart the Wazuh manager service by running these commands:
cd ~/wazuh-docker/single-node/
docker compose restart wazuh.manager
Wait about 30 seconds for the manager to reload its configuration and rules.
- Re-run your Hydra brute-force attack to trigger the new rule:
sudo hydra -l badguy -P ~/passwords.txt 172.17.0.1 ssh
Why 172.17.0.1?
This is the Docker bridge network IP that routes to your Wazuh manager container's SSH port. It is the same target you used in the previous step when you first ran the Hydra attack.
- Return to the Wazuh dashboard at https://localhost in your browser.
- Navigate to the Threat Hunting module.
- Look for an alert with Rule ID 100001 and description "SSH brute-force attack detected: 5+ failed logins in 2 minutes".
You should see your custom rule firing alongside the individual rule 5760 alerts from earlier.
- Click on the alert to expand its details. You should see the MITRE ATT&CK T1110 technique listed in the alert metadata.
Don't see rule 100001 on the dashboard?
Give the dashboard 1-2 minutes to index new alerts. Refresh the page and make sure you are looking at the correct time range (set it to "Last 15 minutes").
If still missing, exec back into the container and check that the manager restarted cleanly:
docker exec -it single-node-wazuh.manager-1 cat /var/ossec/logs/ossec.log | tail -20
Look for lines mentioning rule loading errors or XML parse failures.
help me troubleshoot why my custom Wazuh rule 100001 is not appearing on the dashboard after restarting the manager
✔️ Awesome, I've got everything!
Great. Double check you saved local_rules.xml inside the container and that the manager restarted without errors.
ⓧ I'd like to double check the full code
Here is the exact content of /var/ossec/etc/rules/local_rules.xml inside the Wazuh manager container:
<group name="local,syslog,sshd,">
<rule id="100001" level="10" frequency="5" timeframe="120">
<if_matched_sid>5760</if_matched_sid>
<description>SSH brute-force attack detected: 5+ failed logins in 2 minutes</description>
<mitre>
<id>T1110</id>
</mitre>
<group>authentication_failures,</group>
</rule>
</group>
Your custom detection rule is live and mapped to MITRE ATT&CK. Next up, you will document this entire attack and investigation as a professional incident report ready for your portfolio.
Write Your Professional Incident Report
Your custom detection rule caught the attack and your dashboard is full of alerts. That's exactly what a SOC analyst sees when an incident fires.
The difference between a junior analyst and a strong hire is what happens next. You need to turn raw alerts into a clear, structured investigation document. In this step, you'll write a professional incident report using the same format real SOC teams use to document security events.
In this step, get ready to:
- Document the incident using the SOC analyst format: Alert, Investigation, Evidence, Verdict, Actions.
- Map your findings to MITRE ATT&CK technique T1110 with a full timeline reconstruction.
- Format the report as a GitHub-ready Markdown file for your portfolio.
Document the incident using the SOC analyst format
Hiring managers look for one specific skill in junior SOC analyst candidates: can you investigate an alert and communicate what happened clearly? The standard format is Alert, Investigation, Evidence, Verdict, Actions.
- Before writing the report, gather the details you'll need from your Wazuh dashboard.
- Switch back to the Wazuh dashboard in your browser.
- Click Threat Hunting in the left sidebar.
- Look at the alerts from your Hydra attack and note the source IP address shown in the alert details.
Where do I find the attacker IP?
Click on any alert row to expand its details. Look for the data.srcip field. This is the IP address that launched the attack.
Since you attacked from WSL 2 into a Docker container, this will typically be a Docker bridge IP like 172.18.0.1 or similar. Your exact IP may differ depending on your Docker network configuration.
- Create your incident report file by running this command in your WSL 2 terminal:
cat > ~/incident-report.md << 'EOF'
# Incident Report: SSH Brute-Force Attack Detection
## Alert Summary
| Field | Details |
|-------|--------|
| **Date** | [[INCIDENT_DATE="today's date in YYYY-MM-DD format"]] |
| **Rule Triggered** | ID 100001 - SSH brute-force attack detected |
| **Severity** | Level 10 (High) |
| **MITRE ATT&CK** | T1110 - Brute Force |
| **Source IP** | [[ATTACKER_IP="attacker IP from your Wazuh alerts e.g. 172.18.0.1"]] |
| **Target System** | Wazuh Manager (Docker container) |
| **Target Service** | SSH (Port 22) |
## Investigation
### Initial Triage
Custom rule ID 100001 fired on the Wazuh dashboard, indicating 5 or more
failed SSH login attempts within a 2-minute window. The rule is mapped to
MITRE ATT&CK technique T1110 (Brute Force), warranting immediate
investigation.
### Log Analysis
Review of authentication logs in the Wazuh Threat Hunting module revealed
repeated failed SSH login attempts from a single source IP. The targeted
username was "badguy" which does not exist on the system, indicating an
external enumeration attempt rather than a legitimate user lockout.
Key observations:
- All attempts originated from the same source IP
- The username targeted does not exist on the system
- Attempts occurred in rapid succession (automated tool behavior)
- No successful authentication was achieved
### Timeline Reconstruction
| Time | Event |
|------|-------|
| [[START_TIME="time of first failed login e.g. 14:32:15"]] | First failed SSH login attempt detected (user: badguy) |
| +0-30s | Rapid succession of failed login attempts from same source |
| [[RULE_TIME="time rule 100001 fired e.g. 14:32:45"]] | Custom rule 100001 triggered (threshold: 5 failures in 120s) |
| [[END_TIME="time of last failed login e.g. 14:33:02"]] | Attack concluded - all password attempts exhausted |
## Evidence
### Alert Details (from Wazuh Dashboard)
- **Rule ID**: 100001
- **Rule Description**: SSH brute-force attack detected: 5+ failed logins in 2 minutes
- **Parent Rule**: 5760 (SSH authentication failure)
- **Alert Level**: 10
- **MITRE ATT&CK Technique**: T1110 (Brute Force)
- **MITRE ATT&CK Tactic**: Credential Access
### Sample Log Entry
```
Sample sshd log: Failed password for invalid user badguy from [[ATTACKER_IP="same attacker IP as above"]] port XXXXX ssh2
```
### Attack Characteristics
- **Tool signature**: Rapid automated attempts consistent with Hydra or similar brute-force tool
- **Attempt count**: Multiple password attempts against a single username
- **Success rate**: 0% (no valid credentials found)
## Verdict
**CONFIRMED: Brute-Force Attack (Unsuccessful)**
This incident is a confirmed SSH brute-force attack. The attacker used an
automated tool to attempt multiple password combinations against the SSH
service. The attack was unsuccessful as no valid credentials were discovered.
Risk assessment:
- **Immediate risk**: Low (attack failed, no unauthorized access achieved)
- **Ongoing risk**: Medium (attacker may retry with different wordlists or techniques)
- **Data exposure**: None
## Actions Taken
1. **Detection**: Custom rule 100001 successfully detected the attack in real-time
2. **Investigation**: Reviewed logs via Wazuh Threat Hunting module, confirmed automated brute-force pattern
3. **Containment**: No immediate containment required (attack was unsuccessful)
4. **Documentation**: This incident report created for SOC records
## Recommendations
1. Implement IP-based rate limiting or automatic blocking after N failed attempts
2. Consider deploying Wazuh Active Response to auto-block offending IPs
3. Monitor for follow-up attacks from the same source IP or subnet
4. Review SSH configuration to ensure password authentication is disabled where possible
5. Add the source IP to a watchlist for enhanced monitoring
---
*Report generated as part of SOC Home Lab - Wazuh SIEM Detection Pipeline*
*Analyst: SOC Home Lab Exercise*
EOF
What does this report structure do?
This follows the standard SOC incident documentation format that real security teams use. Each section serves a specific purpose in the investigation workflow.
- Alert Summary gives anyone reading the report the key facts in 5 seconds.
- Investigation shows your analytical process and proves you can think like a SOC analyst.
- Evidence backs up your conclusions with specific log data and rule details.
- Verdict is your professional judgment call on what happened.
- Actions Taken documents what was done and what should happen next.
- Verify the file was created by running:
head -20 ~/incident-report.md
You should see the first 20 lines of your incident report, starting with the heading and Alert Summary table.
Seeing "No such file or directory"?
Make sure you pasted the entire heredoc command including the closing EOF on its own line. If the terminal is still waiting for input, type EOF and press Enter.
If the file was partially created, delete it with rm ~/incident-report.md and run the full command again.
help me troubleshoot my incident report file creation
Verify the MITRE ATT&CK mapping on your dashboard
Your report references MITRE ATT&CK technique T1110 (Brute Force). This mapping is powerful because it connects your local detection to an industry-standard framework that every SOC team uses worldwide.
- Switch back to the Wazuh dashboard in your browser.
- In the left sidebar, expand the Security module section.
- Click MITRE ATT&CK to open the framework view.
- Click the Events tab.
- Look for events tagged with T1110 (Brute Force) from your custom rule.
What is MITRE ATT&CK?
MITRE ATT&CK is a globally recognized knowledge base of adversary tactics and techniques. SOC teams use it as a common language to describe attacks.
T1110 (Brute Force) falls under the Credential Access tactic. When you map a detection rule to a MITRE technique, anyone reading your alert or report instantly understands the type of threat without reading the full log analysis.
You should see T1110 events corresponding to your custom rule 100001 alerts. This confirms your rule's MITRE mapping is working correctly and validates the technique reference in your incident report.
Customize your timeline
Open your incident report and replace the timestamp placeholders with the actual times from your alerts. You can find exact timestamps by expanding individual alerts in the Threat Hunting module.
- Update the timeline placeholders in your report by opening the file with nano:
nano ~/incident-report.md
- Scroll down to the Timeline Reconstruction table.
- Replace the placeholder timestamps with the actual times from your Wazuh alerts.
- Replace the attacker IP placeholders with the IP you noted from your dashboard.
- Press Ctrl+O then Enter to save.
- Press Ctrl+X to exit nano.
Can't find the timestamps?
In the Wazuh Threat Hunting module, each alert row shows a timestamp column on the left. Click on an alert to expand it and look for the timestamp field in the full alert JSON.
help me find alert timestamps in the Wazuh dashboard
Format and preview your GitHub-ready report
Your incident report is written in Markdown, the same format GitHub uses to render documentation. This means when you push this file to a repository, GitHub will automatically render it with proper headings, tables, and formatting.
- Preview the full report to confirm it looks complete by running:
cat ~/incident-report.md
You should see the entire report with all five sections: Alert Summary, Investigation, Evidence, Verdict, and Actions Taken.
- Verify the report has no remaining placeholder text by running:
grep -n "\[\[" ~/incident-report.md
If you replaced all the placeholders, this command should return no output. If it shows any lines, those still have placeholder values you need to fill in.
Why Markdown for your portfolio?
Hiring managers and recruiters browse GitHub profiles to evaluate candidates. A clean Markdown incident report in a repository demonstrates two things at once: your security investigation skills AND your ability to document technical work clearly.
This report format matches how real SOC teams write tickets in tools like Jira, ServiceNow, and PagerDuty. Showing you already know this workflow puts you ahead of candidates who only list certifications.
Push to GitHub when you're ready
To add this to your GitHub portfolio, create a new repository called soc-home-lab and push this file along with any screenshots of your Wazuh dashboard alerts. A README explaining the project plus this incident report makes a strong portfolio piece.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file and that all placeholder values have been replaced with your actual data.
ⓧ I'd like to double check the full report
Here's what your completed incident report should look like (with your specific values filled in):
# Incident Report: SSH Brute-Force Attack Detection
## Alert Summary
| Field | Details |
|-------|--------|
| **Date** | 2026-06-06 |
| **Rule Triggered** | ID 100001 - SSH brute-force attack detected |
| **Severity** | Level 10 (High) |
| **MITRE ATT&CK** | T1110 - Brute Force |
| **Source IP** | 172.18.0.1 |
| **Target System** | Wazuh Manager (Docker container) |
| **Target Service** | SSH (Port 22) |
## Investigation
### Initial Triage
Custom rule ID 100001 fired on the Wazuh dashboard, indicating 5 or more
failed SSH login attempts within a 2-minute window. The rule is mapped to
MITRE ATT&CK technique T1110 (Brute Force), warranting immediate
investigation.
### Log Analysis
Review of authentication logs in the Wazuh Threat Hunting module revealed
repeated failed SSH login attempts from a single source IP. The targeted
username was "badguy" which does not exist on the system, indicating an
external enumeration attempt rather than a legitimate user lockout.
Key observations:
- All attempts originated from the same source IP
- The username targeted does not exist on the system
- Attempts occurred in rapid succession (automated tool behavior)
- No successful authentication was achieved
### Timeline Reconstruction
| Time | Event |
|------|-------|
| 14:32:15 | First failed SSH login attempt detected (user: badguy) |
| +0-30s | Rapid succession of failed login attempts from same source |
| 14:32:45 | Custom rule 100001 triggered (threshold: 5 failures in 120s) |
| 14:33:02 | Attack concluded - all password attempts exhausted |
## Evidence
### Alert Details (from Wazuh Dashboard)
- **Rule ID**: 100001
- **Rule Description**: SSH brute-force attack detected: 5+ failed logins in 2 minutes
- **Parent Rule**: 5760 (SSH authentication failure)
- **Alert Level**: 10
- **MITRE ATT&CK Technique**: T1110 (Brute Force)
- **MITRE ATT&CK Tactic**: Credential Access
### Sample Log Entry
```
Sample sshd log: Failed password for invalid user badguy from 172.18.0.1 port XXXXX ssh2
```
### Attack Characteristics
- **Tool signature**: Rapid automated attempts consistent with Hydra or similar brute-force tool
- **Attempt count**: Multiple password attempts against a single username
- **Success rate**: 0% (no valid credentials found)
## Verdict
**CONFIRMED: Brute-Force Attack (Unsuccessful)**
This incident is a confirmed SSH brute-force attack. The attacker used an
automated tool to attempt multiple password combinations against the SSH
service. The attack was unsuccessful as no valid credentials were discovered.
Risk assessment:
- **Immediate risk**: Low (attack failed, no unauthorized access achieved)
- **Ongoing risk**: Medium (attacker may retry with different wordlists or techniques)
- **Data exposure**: None
## Actions Taken
1. **Detection**: Custom rule 100001 successfully detected the attack in real-time
2. **Investigation**: Reviewed logs via Wazuh Threat Hunting module, confirmed automated brute-force pattern
3. **Containment**: No immediate containment required (attack was unsuccessful)
4. **Documentation**: This incident report created for SOC records
## Recommendations
1. Implement IP-based rate limiting or automatic blocking after N failed attempts
2. Consider deploying Wazuh Active Response to auto-block offending IPs
3. Monitor for follow-up attacks from the same source IP or subnet
4. Review SSH configuration to ensure password authentication is disabled where possible
5. Add the source IP to a watchlist for enhanced monitoring
---
*Report generated as part of SOC Home Lab - Wazuh SIEM Detection Pipeline*
*Analyst: SOC Home Lab Exercise*
Your incident report is complete and ready for your portfolio. Next up, take on the Secret Mission to configure automatic threat response so Wazuh blocks attackers without any manual intervention.
Secret mission
Configure Active Response to Auto-Block Attackers
Your custom rule detects the attack, but a real SOC goes further. What if Wazuh could automatically block the attacker's IP the moment your brute-force rule fires? In this secret mission, you'll configure Wazuh's Active Response module to do exactly that.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally using open-source tools, so there are no ongoing costs. However, the Wazuh containers use 4-6GB of RAM while running. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Wazuh Docker containers (manager, indexer, dashboard) running locally.
- Local project files (~/wazuh-docker, ~/passwords.txt, ~/incident-report.md).
- Hydra attack tool installed in WSL 2 Ubuntu.
- Docker Desktop for Windows.
- WSL 2 Ubuntu distribution.
Keep everything running
No action needed. Choose this if you're still actively experimenting with Wazuh, writing more detection rules, or planning to build on this lab.
- Your Wazuh containers will continue running and using ~4-6GB RAM.
- Access the dashboard anytime at https://localhost.
- Hydra, Docker Desktop, and WSL 2 remain installed on your machine.
Pause - I'll come back to this later
Stop the running containers to free up RAM. Your data and configuration are preserved so you can start them again later.
- Open your WSL 2 Ubuntu terminal.
- Navigate to the single-node directory and stop the containers by running:
cd ~/wazuh-docker/single-node/
docker compose stop
- When you want to resume, run docker compose start from the same directory.
- Docker Desktop can remain installed but you can close the application window to free additional RAM.
Delete - I don't want to use this again
Remove all project resources completely. Make sure you've saved your incident report to GitHub or another location first if you want to keep it for your portfolio.
- Open your WSL 2 Ubuntu terminal.
- Remove all Wazuh containers and their data volumes by running:
cd ~/wazuh-docker/single-node/
docker compose down -v
- Remove the cloned repository and project files by running:
rm -rf ~/wazuh-docker
rm ~/passwords.txt
rm ~/incident-report.md
- Uninstall Hydra by running:
sudo apt remove -y hydra
- To uninstall Docker Desktop, open Windows Settings, then select Apps, then Apps & features.
- Find Docker Desktop in the list, select it, and click Uninstall.
- To remove your WSL 2 Ubuntu distribution entirely, open PowerShell or Command Prompt and run:
wsl --unregister Ubuntu
- Restart your computer to complete the cleanup.
Nice Work!
Nice Work!
You just built a real SOC detection pipeline from scratch! You deployed an enterprise-grade SIEM, caught a brute-force attack with a custom detection rule, and documented the entire investigation as a professional incident report.
You've learned how to:
- Deploy Wazuh SIEM using Docker on WSL 2, giving you hands-on experience with the same tool used in production SOCs worldwide.
- Simulate a real brute-force attack using Hydra and write a custom detection rule mapped to MITRE ATT&CK technique T1110 (Brute Force).
- Investigate security alerts and produce a professional incident report following the SOC analyst format: Alert, Investigation, Evidence, Verdict, and Actions.
- Configure Active Response to automatically block attacker IP addresses when your custom detection rule fires (Secret Mission).
Ready to quiz yourself?