<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Devyani Nandanwar</title>
    <description>The latest articles on DEV Community by Devyani Nandanwar (@devyani_nandanwar_5).</description>
    <link>https://dev.to/devyani_nandanwar_5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4176045%2Fe03d3b34-7b0d-4e69-81db-5b400f7d7806.jpg</url>
      <title>DEV Community: Devyani Nandanwar</title>
      <link>https://dev.to/devyani_nandanwar_5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devyani_nandanwar_5"/>
    <language>en</language>
    <item>
      <title>Detection Engineering Lab: Building a Wazuh SIEM and Writing a Custom Rule for SSH Brute Force</title>
      <dc:creator>Devyani Nandanwar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 23:12:18 +0000</pubDate>
      <link>https://dev.to/devyani_nandanwar_5/detection-engineering-lab-building-a-wazuh-siem-and-writing-a-custom-rule-for-ssh-brute-force-12dd</link>
      <guid>https://dev.to/devyani_nandanwar_5/detection-engineering-lab-building-a-wazuh-siem-and-writing-a-custom-rule-for-ssh-brute-force-12dd</guid>
      <description>&lt;p&gt;This write-up documents a small SIEM detection lab I built to practice detection engineering from the defender's side: deploying a SIEM, generating adversary activity against a monitored host, validating that it is detected, and writing a custom correlation rule mapped to MITRE ATT&amp;amp;CK.&lt;/p&gt;

&lt;p&gt;Repository with the rule, configuration notes and all screenshots: &lt;a href="https://github.com/devyaninandanwar/wazuh-siem-detection-lab" rel="noopener noreferrer"&gt;https://github.com/devyaninandanwar/wazuh-siem-detection-lab&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objective&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To validate end to end that a SIEM can ingest endpoint logs, surface attacker activity, and support a custom detection, and to practice the triage thinking that goes with it, including recognizing a false positive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three virtual machines in VirtualBox on a bridged network:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Host&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;wazuh-manager&lt;/td&gt;
&lt;td&gt;Wazuh server, indexer and dashboard (the SIEM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;monitored-endpoint&lt;/td&gt;
&lt;td&gt;Ubuntu Server running OpenSSH and Apache, with the Wazuh agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kali Linux&lt;/td&gt;
&lt;td&gt;Adversary simulation host&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Wazuh agent on the endpoint collects local logs (journald for SSH authentication events, and the Apache access log) and forwards them to the manager. The manager decodes the events, evaluates them against its ruleset, and indexes alerts for the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi87zbf6dzr3p29ajanss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi87zbf6dzr3p29ajanss.png" alt="Dashboard showing one active agent" width="799" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment issues
&lt;/h2&gt;

&lt;p&gt;Two infrastructure problems are worth recording, since they affect anyone running this on a laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage&lt;/strong&gt; &lt;br&gt;
The first manager VM had a 25 GB disk, and the all-in-one installer failed with "No space left on device". After rebuilding with 60 GB, the Ubuntu installer's LVM layout still allocated only about 29 GB to the root logical volume. The fix was &lt;code&gt;lvextend -l +100%FREE&lt;/code&gt; on the logical volume followed by &lt;code&gt;resize2fs&lt;/code&gt;, verified with &lt;code&gt;df -h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory&lt;/strong&gt; &lt;br&gt;
With 4 GB of RAM, the Wazuh indexer, manager and dashboard compete for memory, and after a reboot some services failed to start. Starting the indexer first and the dependent services afterwards resolved it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Detection scenario 1: SSH brute force (MITRE ATT&amp;amp;CK T1110)
&lt;/h2&gt;

&lt;p&gt;Simulated from the Kali host with Hydra against the endpoint's SSH service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hydra &lt;span class="nt"&gt;-l&lt;/span&gt; ubuntu &lt;span class="nt"&gt;-P&lt;/span&gt; passwords.txt ssh://192.168.1.194
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fep8gk722yq92pjxeda0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fep8gk722yq92pjxeda0m.png" alt="Hydra attack from Kali (password redacted)" width="800" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent's authentication logs triggered Wazuh's built-in rule 5760 (sshd: authentication failed) repeatedly. The event detail includes the targeted account, the source IP and port, and the raw log line. Together, these give an analyst the data needed to start an investigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvor1d93rwhu18xukkjka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvor1d93rwhu18xukkjka.png" alt="Wazuh dashboard after the attack" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc50v6zooah5v37wkas70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc50v6zooah5v37wkas70.png" alt="Event detail for rule 5760 showing the source IP" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection scenario 2: Network reconnaissance (MITRE ATT&amp;amp;CK T1595)
&lt;/h2&gt;

&lt;p&gt;A service-version scan from the Kali host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmap &lt;span class="nt"&gt;-sV&lt;/span&gt; 192.168.1.194
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was detected through the Apache access log. Nmap's scripting engine requests non-existent URLs, producing 404 responses that Wazuh flagged under its web rules (31101). The raw log line includes the Nmap Scripting Engine user agent, which makes attribution of the tooling straightforward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffb5g83987j8dt4z08b02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffb5g83987j8dt4z08b02.png" alt="Nmap detected through the Apache access log" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection engineering: a custom correlation rule
&lt;/h2&gt;

&lt;p&gt;The built-in rule 5760 alerts on every failed login. A single failure is normal operational noise, so alerting on it alone produces low-value alerts. The detection of interest is a burst of failures. I wrote a frequency-based correlation rule that fires when rule 5760 triggers five times within 120 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;rule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"100002"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="na"&gt;frequency=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt; &lt;span class="na"&gt;timeframe=&lt;/span&gt;&lt;span class="s"&gt;"120"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;if_matched_sid&amp;gt;&lt;/span&gt;5760&lt;span class="nt"&gt;&amp;lt;/if_matched_sid&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;SSH brute-force attack detected&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mitre&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;T1110&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/mitre&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;group&amp;gt;&lt;/span&gt;authentication_failures,pci_dss_11.4,mitre,&lt;span class="nt"&gt;&amp;lt;/group&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-running the Hydra attack triggered rule 100002 at level 10, confirming the detection works against the simulated activity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn9i2bpkwi94o797dy5n9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn9i2bpkwi94o797dy5n9.png" alt="Custom rule 100002 firing" width="799" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Alert triage: a rootcheck false positive
&lt;/h2&gt;

&lt;p&gt;After deployment the SIEM raised 84 alerts for rule 510 (rootcheck), "Trojaned version of file detected", on system binaries such as &lt;code&gt;/usr/bin/md5sum&lt;/code&gt;. On a freshly built host this warrants investigation before dismissal. Reviewing the event showed the rootcheck signature is a generic string pattern that matches any file containing certain references (for example &lt;code&gt;/bin/sh&lt;/code&gt;), and no other indicators of compromise were present. My assessment was that this is a known false positive from generic rootcheck signatures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdntapl69sxv65dpkalrp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdntapl69sxv65dpkalrp.png" alt="84 rootcheck alerts for rule 510" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqojb9vqeap44zzeimtcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqojb9vqeap44zzeimtcf.png" alt="Rule 510 event detail on /usr/bin/md5sum" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The appropriate response in an operational environment is a documented, scoped tuning exception for those files, not disabling the rule. I documented this approach but did not implement the exception in this lab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;p&gt;The lab is built to be extended. Planned next iterations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same-source correlation.&lt;/strong&gt; Tighten rule 100002 with &lt;code&gt;same_source_ip&lt;/code&gt; so it alerts only when the failures come from a single address, then retest against the same Hydra run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated response.&lt;/strong&gt; Use Wazuh active response to block the offending IP once the rule fires, taking the lab from detection to containment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broader coverage.&lt;/strong&gt; Add further ATT&amp;amp;CK techniques and log sources, such as file integrity monitoring and privilege escalation scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tuning.&lt;/strong&gt; Implement the scoped exception for the rootcheck false positive and document the before and after alert volume.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;Standing up a SIEM and observing its alerts against traffic you generated yourself makes the detection engineering workflow concrete: telemetry in, a rule that expresses a hypothesis about attacker behavior, validation against simulated activity, and triage of whatever noise comes with it. &lt;/p&gt;

&lt;p&gt;Which attack techniques would you simulate next in a lab like this? Share your ideas in the comments!&lt;/p&gt;

</description>
      <category>security</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
