Mahesh Harripaul
Home Experience Blog Services Contact
← Back to blog
WazuhCorrelation rulesMITRE T1110Detection engineering

Writing the First Correlation Rules: Brute Force Detection

June 3–5, 2026 · Mahesh Harripaul

4
Rules written
5
Frequency threshold
120s
Timeframe

Custom rules 100002–100005 · MITRE T1110 · T1484

With the pipeline understood, it was time to write the first custom rules. The process for every rule is the same: generate a real event, confirm the field names from actual data, write the rule, test it. Never assume a field name. Always verify from a real alert.

The rule writing workflow

  1. Identify the gap in default coverage
  2. Generate a real event to inspect
  3. Confirm exact field names from the actual alert in the dashboard
  4. Write the rule targeting those confirmed fields
  5. Deploy, test, and validate

Parent and child rule structure

<group name="local,windows,authentication,">

  <rule id="100002" level="5">
    <if_sid>60122</if_sid>
    <description>Windows: Failed logon attempt</description>
    <group>windows_failed_logon,authentication_failed,</group>
    <mitre><id>T1110</id></mitre>
  </rule>

  <rule id="100003" level="10" frequency="5" timeframe="120">
    <if_matched_sid>100002</if_matched_sid>
    <same_field>win.eventdata.targetUserName</same_field>
    <description>Windows: Brute force attack detected</description>
    <group>windows_brute_force,</group>
    <mitre><id>T1110</id></mitre>
  </rule>

</group>

Rule 100002 is a parent that chains from Wazuh's built-in rule 60122. By owning an intermediate rule, the correlation logic is controlled without depending on built-in rules that might change on updates. Custom rule IDs must be 100000 or above.

How the correlation rule works

Rule 100003 uses three attributes together:

Five failed logins against the same account in two minutes is a brute force attack. One failed login is a typo.

Critical: field names in rules vs dashboard

The dashboard shows field names with a data. prefix. Inside rule XML that prefix does not exist:

# Dashboard search
data.win.eventdata.targetUserName

# Rule XML — drop the data. prefix
<same_field>win.eventdata.targetUserName</same_field>

The data. prefix is added by the indexer when storing alerts. It does not exist in the rules engine. This is the single most common early mistake.

same_field vs same_srcuser

Wazuh has shortcut tags like <same_srcuser /> that are supposed to handle username correlation. For Windows eventchannel logs these silently fail — they map to internal fields that the Windows decoder does not populate. Always use <same_field>win.eventdata.fieldname</same_field> for Windows events.

Deploying and testing

# Deploy
sudo systemctl reload wazuh-manager

# Watch alerts in real time
sudo tail -f /var/ossec/logs/alerts/alerts.log

Simulate the attack — five failed logins quickly against the same account. The brute force rule fired at level 10. Alert appeared in the dashboard within seconds and was automatically mapped to MITRE ATT&CK T1110 in the framework view.

Rules written this session

Rule IDDescriptionLevel
100002Failed logon parent — fires on every Event ID 46255
100003Brute force — same account fails 5× in 120 seconds10
100004Privilege escalation parent — Event ID 46727
100005Repeated privilege escalation — same user 3× in 300 seconds10
Previous: Understanding the Log PipelineNext: Building a Multi-Stage Attack Chain All posts →