Difference between revisions of "Wazuh Custom Rule Creation"

From Notes_Wiki
Line 3: Line 3:
= Wazuh Custom Rule Creation =
= Wazuh Custom Rule Creation =


In Wazuh, we have two types of rules:
In Wazuh, there are two types of rules:
 
# Default rules
# Default rules
# Custom rules
# Custom rules
Line 9: Line 10:
== Default Rules ==
== Default Rules ==


Wazuh’s default rules are pre-configured rules included with every Wazuh installation. These can be found on the Wazuh server at:
Wazuh’s default rules are pre-configured rules included with every Wazuh installation. These are located at:
 
<code>/var/ossec/ruleset/rules/</code>
 
These rules are designed to monitor a broad spectrum of security events and log sources, providing a solid foundation for detecting common security threats such as attacks, vulnerabilities, and suspicious activities.
 
'''Note:''' Modifying existing default rules is '''not recommended''' directly.


<code>/var/ossec/ruleset/rules/</code>
=== Changing Existing Rules ===


These rules are designed to monitor a broad spectrum of security events and log sources, providing a solid foundation for detecting common security threats. They help identify different types of attacks, vulnerabilities, and suspicious activities.
Wazuh allows us to modify its built-in rules by copying them to:


'''Note:''' Modifying existing rules is not recommended.
<code>/var/ossec/etc/rules/local_rules.xml</code>
 
To override a rule, add the attribute <code>overwrite="yes"</code>.
 
==== Sample Event Log ====
 
<pre>
Jun 06 08:46:21 thehive sshd[2556]: Invalid user test from 10.9.8.16 port 39496
</pre>
 
Let's use this example with Rule ID 5710: ''sshd: Attempt to login using a non-existent user''.
 
==== Default Rule Definition ====
 
<pre>
<group name="syslog,sshd,">
  <rule id="5710" level="5">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group>
  </rule>
</group>
</pre>
 
==== Example 1: Change Alert Level ====
 
Change level from 5 to 10:
 
<pre>
<group name="syslog,sshd,">
  <rule id="5710" level="10" overwrite="yes">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group>
  </rule>
</group>
</pre>
 
==== Example 2: Match by Hostname ====
 
<pre>
<group name="syslog,sshd,">
  <rule id="5710" level="10" overwrite="yes">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <hostname>t-t</hostname>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group>   
  </rule>
</group>
</pre>
 
==== Example 3: Match by Source IP ====
 
<pre>
<group name="syslog,sshd,">
  <rule id="5710" level="10" overwrite="yes">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <srcip>10.9.8.16</srcip>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group> 
  </rule>
</group>
</pre>


== Custom Rules ==
== Custom Rules ==


Custom rules are used in Wazuh to define specific conditions or patterns for how an alert will be triggered.
In Wazuh, custom rules are used to define specific conditions or patterns that determine when an alert should be triggered. These rules enable users to customize security monitoring based on the unique needs of their environment. Unlike default rules, which come pre-configured with Wazuh, custom rules are user-defined and maintained to address specialized security requirements or to refine detection logic. Custom rules are written in the file located at:
  <code>/var/ossec/rules/local_rules.xml</code>


They allow users to tailor security monitoring to meet specific needs. Unlike default rules, custom rules are created and managed by users and are defined in the file:
Use custom rule IDs (100000 to 120000) to avoid conflicts.


<code>/var/ossec/etc/rules/local_rules.xml</code>
=== Basic Custom Rule Structure ===
 
=== Basic Structure of a Custom Rule ===


<pre>
<pre>
Line 37: Line 125:
</pre>
</pre>


== How to Check If an Alert Is Triggering for a Log ==
=== Testing Rules ===
 
Use the following binary to test log matches:
 
<code>/var/ossec/bin/wazuh-logtest</code>
 
==== Example Log ====


Use the <code>wazuh-logtest</code> binary utility provided by the Wazuh Manager.
<pre>
Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2
</pre>


=== Example Event Log ===
Run:


<code>Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2</code>
<code>/var/ossec/bin/wazuh-logtest</code>


Run <code>/var/ossec/bin/wazuh-logtest</code> and paste the above log.
Paste the log and observe the output.


=== Example Output ===
==== Sample Output ====


<pre>
<pre>
**Phase 1: Completed pre-decoding.
**Phase 1: Completed pre-decoding.
    full event: 'Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2'
full event: 'Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2'
    timestamp: 'Jun 05 09:48:16'
timestamp: 'Jun 05 09:48:16'
    hostname: 'shuffle'
hostname: 'shuffle'
    program_name: 'sshd'
program_name: 'sshd'


**Phase 2: Completed decoding.
**Phase 2: Completed decoding.
    name: 'sshd'
name: 'sshd'
    parent: 'sshd'
parent: 'sshd'
    dstuser: 'shuffle'
dstuser: 'shuffle'
    srcip: '10.9.8.16'
srcip: '10.9.8.16'
    srcport: '57868'
srcport: '57868'


**Phase 3: Completed filtering (rules).
**Phase 3: Completed filtering (rules).
    id: '5760'
id: '5760'
    level: '5'
level: '5'
    description: 'sshd: authentication failed.'
description: 'sshd: authentication failed.'
    groups: '['syslog', 'sshd', 'authentication_failed']'
groups: '['syslog', 'sshd', 'authentication_failed']'
    firedtimes: '1'
firedtimes: '1'
    gdpr: '['IV_35.7.d', 'IV_32.2']'
gdpr: '['IV_35.7.d', 'IV_32.2']'
    gpg13: '['7.1']'
gpg13: '['7.1']'
    hipaa: '['164.312.b']'
hipaa: '['164.312.b']'
    mail: 'False'
mail: 'False'
    mitre.id: '['T1110.001', 'T1021.004']'
mitre.id: '['T1110.001', 'T1021.004']'
    mitre.tactic: '['Credential Access', 'Lateral Movement']'
mitre.tactic: '['Credential Access', 'Lateral Movement']'
    mitre.technique: '['Password Guessing', 'SSH']'
mitre.technique: '['Password Guessing', 'SSH']'
    nist_800_53: '['AU.14', 'AC.7']'
nist_800_53: '['AU.14', 'AC.7']'
    pci_dss: '['10.2.4', '10.2.5']'
pci_dss: '['10.2.4', '10.2.5']'
    tsc: '['CC6.1', 'CC6.8', 'CC7.2', 'CC7.3']'
tsc: '['CC6.1', 'CC6.8', 'CC7.2', 'CC7.3']'
**Alert to be generated.
**Alert to be generated.
</pre>
</pre>


This confirms that the event log triggers an alert with:
==== Triggered Rule ====
* rule.id: 5760
* rule.level: 5
* description: sshd: authentication failed
* groups: syslog, sshd, authentication_failed
 
=== Rule Definition That Triggered the Above Log ===


<pre>
<pre>
Line 105: Line 195:
</pre>
</pre>


== Creating Custom Rules ==
=== Creating Custom Rules ===


=== Example 1: Basic Custom Rule ===
=== Example 1: Basic Custom Rule ===
Modify the default alert rule by creating a custom rule in <code>/var/ossec/etc/rules/local_rules.xml</code>:


<pre>
<pre>
Line 121: Line 209:
</pre>
</pre>


==== Breakdown ====
'''Explanation:'''
* <code>&lt;group&gt;</code>: Assigns group name to rule
* <code>&lt;group&gt;</code> Assigns a group name
* <code>&lt;rule&gt;</code>: Defines custom rule ID and level
* <code>&lt;rule&gt;</code> — Custom ID and severity
* <code>&lt;if_sid&gt;</code>: Applies this rule only if rule ID 5760 is triggered
* <code>&lt;if_sid&gt;</code> — Triggers only if rule 5760 matches
* <code>&lt;match&gt;</code>: Matches strings in the event log
* <code>&lt;match&gt;</code> — String match
* <code>&lt;description&gt;</code>: Explains the rule’s purpose
* <code>&lt;description&gt;</code> — Rule purpose
 
==== wazuh-logtest Output ====
 
<pre>
**Phase 1: Completed pre-decoding.
full event: 'Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2'
timestamp: 'Jun 05 09:48:16'
hostname: 'shuffle'
program_name: 'sshd'
 
**Phase 2: Completed decoding.
name: 'sshd'
parent: 'sshd'
dstuser: 'shuffle'
srcip: '10.9.8.16'
srcport: '57868'
 
**Phase 3: Completed filtering (rules).
  id: '100002'
  level: '3'
  description: 'custom rule for sshd authentication failed.'
  groups: '['custom_rule']'
  firedtimes: '1'
  mail: 'False'
**Alert to be generated.
</pre>


This rule is general and doesn't specify tags like IP or hostname, so it will trigger alerts regardless of source or destination.
=== Example 2: Match srcip ===
The below rule will only trigger an alert if both specified conditions the hostname and the source IP address are simultaneously met in the incoming log data. This means that even if the log contains the correct source IP but the hostname doesn't match (or vice versa), the rule will not activate. Both criteria must align exactly with the values defined in the rule for it to be evaluated as a match and generate an alert.


=== Example 2: Rule Based on Source IP ===


<pre>
<pre>
Line 137: Line 251:
     <if_sid>5760</if_sid>
     <if_sid>5760</if_sid>
     <match>Failed password|Failed keyboard|authentication error</match>
     <match>Failed password|Failed keyboard|authentication error</match>
    <srcip>10.9.8.16</srcip>
     <description>Custom rule for SSHD authentication failures.</description>
     <description>Custom rule for SSHD authentication failures.</description>
    <srcip>10.9.8.16</srcip>
     <group>authentication_failed,sshd</group>
     <group>authentication_failed,sshd</group>
     <mitre>
     <mitre>
Line 148: Line 262:
</pre>
</pre>


==== Additional Tags ====
=== Example 3: Match srcip and hostname ===
* <code>&lt;group&gt;</code>: Classifies alert
The '''<srcip>''' tag ensures that the rule is triggered only when the source IP address in the log exactly matches the value specified in log (e.g., a known attacker IP). If the source IP in the incoming log differs from the value provided, the rule will not be applied. This allows for more precise alerting by narrowing down rule activation to specific IP addresses associated with potential threats.
* <code>&lt;mitre&gt;</code>: Maps TTPs for threat intelligence
* <code>&lt;srcip&gt;</code>: Only triggers if source IP matches
 
=== Example 3: Rule Based on Source IP and Hostname ===


<pre>
<pre>
Line 160: Line 270:
     <if_sid>5760</if_sid>
     <if_sid>5760</if_sid>
     <match>Failed password|Failed keyboard|authentication error</match>
     <match>Failed password|Failed keyboard|authentication error</match>
    <description>Custom rule for SSHD authentication failures.</description>
     <srcip>10.9.8.16</srcip>
     <srcip>10.9.8.16</srcip>
     <hostname>t-t</hostname>
     <hostname>t-t</hostname>
    <description>Custom rule for SSHD authentication failures.</description>
     <group>authentication_failed,sshd</group>
     <group>authentication_failed,sshd</group>
     <mitre>
     <mitre>
Line 171: Line 281:
</group>
</group>
</pre>
</pre>
==== Additional Tags ====
* <code>&lt;srcip&gt;</code>: Triggers only if source IP matches
* <code>&lt;hostname&gt;</code>: Triggers only if hostname matches

Revision as of 09:33, 6 June 2025

Home > Wazuh > Wazuh Custom Rule Creation

Wazuh Custom Rule Creation

In Wazuh, there are two types of rules:

  1. Default rules
  2. Custom rules

Default Rules

Wazuh’s default rules are pre-configured rules included with every Wazuh installation. These are located at:

/var/ossec/ruleset/rules/

These rules are designed to monitor a broad spectrum of security events and log sources, providing a solid foundation for detecting common security threats such as attacks, vulnerabilities, and suspicious activities.

Note: Modifying existing default rules is not recommended directly.

Changing Existing Rules

Wazuh allows us to modify its built-in rules by copying them to:

/var/ossec/etc/rules/local_rules.xml

To override a rule, add the attribute overwrite="yes".

Sample Event Log

Jun 06 08:46:21 thehive sshd[2556]: Invalid user test from 10.9.8.16 port 39496

Let's use this example with Rule ID 5710: sshd: Attempt to login using a non-existent user.

Default Rule Definition

<group name="syslog,sshd,">
  <rule id="5710" level="5">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group>
  </rule>
</group>

Example 1: Change Alert Level

Change level from 5 to 10:

<group name="syslog,sshd,">
  <rule id="5710" level="10" overwrite="yes">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group>
  </rule>
</group>

Example 2: Match by Hostname

<group name="syslog,sshd,">
  <rule id="5710" level="10" overwrite="yes">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <hostname>t-t</hostname>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group>    
  </rule>
</group>

Example 3: Match by Source IP

<group name="syslog,sshd,">
  <rule id="5710" level="10" overwrite="yes">
    <if_sid>5700</if_sid>
    <match>illegal user|invalid user</match>
    <srcip>10.9.8.16</srcip>
    <description>sshd: Attempt to login using a non-existent user</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,...</group>   
  </rule>
</group>

Custom Rules

In Wazuh, custom rules are used to define specific conditions or patterns that determine when an alert should be triggered. These rules enable users to customize security monitoring based on the unique needs of their environment. Unlike default rules, which come pre-configured with Wazuh, custom rules are user-defined and maintained to address specialized security requirements or to refine detection logic. Custom rules are written in the file located at:

 /var/ossec/rules/local_rules.xml

Use custom rule IDs (100000 to 120000) to avoid conflicts.

Basic Custom Rule Structure

<group name="custom_name,">
  <rule id="100010" level="5">
    <if_sid>...</if_sid>
    <match>...</match>
    <description>...</description>
  </rule>
</group>

Testing Rules

Use the following binary to test log matches:

/var/ossec/bin/wazuh-logtest

Example Log

Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2

Run:

/var/ossec/bin/wazuh-logtest

Paste the log and observe the output.

Sample Output

**Phase 1: Completed pre-decoding.
	full event: 'Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2'
	timestamp: 'Jun 05 09:48:16'
	hostname: 'shuffle'
	program_name: 'sshd'

**Phase 2: Completed decoding.
	name: 'sshd'
	parent: 'sshd'
	dstuser: 'shuffle'
	srcip: '10.9.8.16'
	srcport: '57868'

**Phase 3: Completed filtering (rules).
	id: '5760'
	level: '5'
	description: 'sshd: authentication failed.'
	groups: '['syslog', 'sshd', 'authentication_failed']'
	firedtimes: '1'
	gdpr: '['IV_35.7.d', 'IV_32.2']'
	gpg13: '['7.1']'
	hipaa: '['164.312.b']'
	mail: 'False'
	mitre.id: '['T1110.001', 'T1021.004']'
	mitre.tactic: '['Credential Access', 'Lateral Movement']'
	mitre.technique: '['Password Guessing', 'SSH']'
	nist_800_53: '['AU.14', 'AC.7']'
	pci_dss: '['10.2.4', '10.2.5']'
	tsc: '['CC6.1', 'CC6.8', 'CC7.2', 'CC7.3']'
**Alert to be generated.

Triggered Rule

<group name="syslog,sshd,">
  <rule id="5760" level="5">
    <if_sid>5700,5716</if_sid>
    <match>Failed password|Failed keyboard|authentication error</match>
    <description>sshd: authentication failed.</description>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
    <group>authentication_failed,gdpr_IV_35.7.d,gdpr_IV_32.2,gpg13_7.1,hipaa_164.312.b,nist_800_53_AU.14,nist_800_53_AC.7,pci_dss_10.2.4,pci_dss_10.2.5,tsc_CC6.1,tsc_CC6.8,tsc_CC7.2,tsc_CC7.3,</group>
  </rule>
</group>

Creating Custom Rules

Example 1: Basic Custom Rule

<group name="custom_rule,">
  <rule id="100002" level="3">
    <if_sid>5760</if_sid>
    <match>Failed password|Failed keyboard|authentication error</match>
    <description>custom rule for sshd authentication failed.</description>
  </rule>
</group>

Explanation:

  • <group> — Assigns a group name
  • <rule> — Custom ID and severity
  • <if_sid> — Triggers only if rule 5760 matches
  • <match> — String match
  • <description> — Rule purpose

wazuh-logtest Output

**Phase 1: Completed pre-decoding.
	full event: 'Jun 05 09:48:16 shuffle sshd[6670]: Failed password for shuffle from 10.9.8.16 port 57868 ssh2'
	timestamp: 'Jun 05 09:48:16'
	hostname: 'shuffle'
	program_name: 'sshd'

**Phase 2: Completed decoding.
	name: 'sshd'
	parent: 'sshd'
	dstuser: 'shuffle'
	srcip: '10.9.8.16'
	srcport: '57868'

**Phase 3: Completed filtering (rules).
  id: '100002'
  level: '3'
  description: 'custom rule for sshd authentication failed.'
  groups: '['custom_rule']'
  firedtimes: '1'
  mail: 'False'
**Alert to be generated.

Example 2: Match srcip

The below rule will only trigger an alert if both specified conditions the hostname and the source IP address are simultaneously met in the incoming log data. This means that even if the log contains the correct source IP but the hostname doesn't match (or vice versa), the rule will not activate. Both criteria must align exactly with the values defined in the rule for it to be evaluated as a match and generate an alert.


<group name="custom_rule">
  <rule id="100002" level="3">
    <if_sid>5760</if_sid>
    <match>Failed password|Failed keyboard|authentication error</match>
    <srcip>10.9.8.16</srcip>
    <description>Custom rule for SSHD authentication failures.</description>
    <group>authentication_failed,sshd</group>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
  </rule>
</group>

Example 3: Match srcip and hostname

The <srcip> tag ensures that the rule is triggered only when the source IP address in the log exactly matches the value specified in log (e.g., a known attacker IP). If the source IP in the incoming log differs from the value provided, the rule will not be applied. This allows for more precise alerting by narrowing down rule activation to specific IP addresses associated with potential threats.

<group name="custom_rule">
  <rule id="100002" level="3">
    <if_sid>5760</if_sid>
    <match>Failed password|Failed keyboard|authentication error</match>
    <srcip>10.9.8.16</srcip>
    <hostname>t-t</hostname>
    <description>Custom rule for SSHD authentication failures.</description>
    <group>authentication_failed,sshd</group>
    <mitre>
      <id>T1110.001</id>
      <id>T1021.004</id>
    </mitre>
  </rule>
</group>