Custom Alert Rules in Wazuh
Task 1 Introduction
Wazuh
is an open-source security detection tool that works on top of the ELK stack (Elasticsearch, Logstash, and Kibana) and is designed to identify threats using its alert rule system. This system uses rules to search for potential security threats or issues in logs from various sources, such as operating system logs, application logs, endpoint security logs, etc.
Out of the box, Wazuh has a comprehensive set of pre-configured rules. While these rules cover a wide range of potential security issues, there are still scenarios or risks unique to an organization that these rules may not cover. To compensate for this, organizations can create custom alert rules, which is the focus of this room.
Learning objectives:
- Learn how important data is extracted from logs using Decoders.
- Learn how alerts are triggered using Rules.
- Learn how to add new rules to extend detection capabilities.
- Learn how to simulate a real-world attack to test existing rules.
Room Prerequisites
- Knowledge and experience with Wazuh โ If you need an overview of its features, visit the Wazuh room.
- Familiarity with regular expressions โ Wazuh decoders and rules rely heavily on regular expressions, so brush up by checking out the Regular Expressions room.
- Knowledge of Sysmon โ Weโll use Sysmon logs as an example for this room.
Task 2 Decoders
- One of Wazuhโs many features is that it can ingest logs from different sources and generate alerts based on their contents
- But various logs can have varied data types and structures
- To manage this Wazuh uses Decoders that use regex to extract only the needed data for later use
Understanding Decoders โ
- Considering Sysmon ( System Monitor ) tool logs as an example
- There is a pre-existing decoder for this listed in the windows+decoders.xml file on, can also be downloaded from task files
<decoder name=”Sysmon-EventID#1_new”>
<parent>windows</parent>
<type>windows</type>
<prematch>INFORMATION\\(1\\)\\.+Hashes</prematch>
<regex>Microsoft-Windows-Sysmon/Operational: \\S+\\((\\d+)\\)</regex>
<order>id</order>
</decoder>
Breaking down the parts of the decoder block above:
- Decoder name- The name of this decoder. ( Note multiple decoder blocks can have the same name; this should be pictured as if they are being grouped together )
- Parent- The name of the parent decoder. The parent decoder is processed before the children decoders
- Prematch- Uses regular expressions to look for a match. If this succeeds, it will process the โregexโ option below
- Regex- Uses regular expressions to extract data. Any string in between a non-escaped open and closed parenthesis is extracted
- Order- Contains a list of names to which the extracted data will be stored
- The log entry above shows an example event a Wazuh agent installed in a windows machine sent
- It describes an event where the user ran a PowerShell script named test.ps1 from his system using poweshell.exe executable initiated by the Explorer process ( Cโ\Windows\explorer.exe )
- The above log entry has lots of data in it and it is the work of the decoder to extract them
- Once this log entry is ingested all appropriate decoder blocks will kick into action where they will check the prematch option
- The decoder block above will check if any strings match the regular expression โINFORMATION\(1\)\.+Hashesโ
- First, the regex will look for the
INFORMATION
string. - Followed by an escaped open parenthesis
\\(
- Followed by a number
1
- Followed by an escaped close parenthesis
\\)
- And then any number of characters
\\.+
- Until it reaches the
Hashes
string
Q 1. Looking at the Sysmon Log, what will the value of sysmon.commandLine be?
Answer: โC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exeโ โ-fileโ โC:\Users\Alberto\Desktop\test.ps1โ
Q 2. What would the extracted value be if the regex is set to โUser: (\.) \sโ?
Answer: WIN-P57C9KN929H\Alberto
Task 3 Rules
- Rules contain defined conditions to detect specific events or malicious activities using the extracted data from decoders
- An alert is generated when an event matches a rule
- The rules defined in the sysmon_rules.xml file will be discussed below
Understanding Rules
Here is an example of an alert rule that looks for the โsvchost.exeโ string in the โsysmon.imageโ field:
sysmon_rules.xml<rule id=”184666″ level=”12″><if_group>sysmon_event1</if_group><field name=”sysmon.image”>svchost.exe</field><description>Sysmon – Suspicious Process – svchost.exe</description><mitre><id>T1055</id></mitre><group>pci_dss_10.6.1,pci_dss_11.4,…</group></rule>
- A rule block has multiple options
- rule-id โ The unique identity of the rule
- rule level โ The classification of levels from 0โ15 indicating the level of severity as listed by Wazuh
- if_group โ Specifies the group name that triggers this rule when that group has matched
- field name โ The name of the field extracted from the decoder. The value in this field is matched using regex
- group โ Contains a list of groups or categories that the rule belongs to. It can be used for organizing and filtering rules
Testing the Rule
Go back to the โRuleset Testโ page. Paste the exact log entry we used in the previous task. The result should be the same, but this time, we will focus on Phase 3 of the output.
Ruleset Test Output**Phase 3: Completed filtering (rules).
id: 184665
level: –
description: Sysmon – Event 1
groups: [“sysmon”,”sysmon_event1″]
firedtimes: 1
gdpr: “-“
gpg13: “-“
hipaa: “-“
mail: “-“
mitre.id: “-“
mitre.technique: “-“
nist_800_53: “-“
pci_dss: “-“
tsc: “-“
Phase 3 shows what information an alert would contain when a rule is triggered, like โidโ, โlevelโ, โdescriptionโ, etc.
Right now, the output shows that the triggered rule ID is 184665
. This is not the rule block that we examined above, which has the ID of 184666
. The reason for this is that 184666
is looking for “svchost.exe” in the “sysmon.image” field option. For this rule to trigger, we need to change “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” to “C:\WINDOWS\system32\svchost.exe”, as shown below:
Sysmon LogMar 29 13:36:36 WinEvtLog: Microsoft-Windows-Sysmon/Operational: INFORMATION(1): Microsoft-Windows-Sysmon: SYSTEM: NT AUTHORITY: WIN-P57C9KN929H: Process Create: UtcTime: 2017-03-29 11:36:36.964 ProcessGuid: {DB577E3B-9C44-58DB-0000-0010B0983A00} ProcessId: 3784 Image: C:\\WINDOWS\\system32\\svchost.exe CommandLine: “C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe” “-file” “C:\\Users\\Alberto\\Desktop\\test.ps1” CurrentDirectory: C:\\Users\\Alberto\\Desktop\\ User: WIN-P57C9KN929H\\Alberto LogonGuid: {DB577E3B-89E5-58DB-0000-0020CB290500} LogonId: 0x529cb TerminalSessionId: 1 IntegrityLevel: Medium Hashes: MD5=92F44E405DB16AC55D97E3BFE3B132FA,SHA256=6C05E11399B7E3C8ED31BAE72014CF249C144A8F4A2C54A758EB2E6FAD47AEC7 ParentProcessGuid: {DB577E3B-89E6-58DB-0000-0010FA3B0500} ParentProcessId: 2308 ParentImage: C:\\Windows\\explorer.exe ParentCommandLine: C:\\Windows\\Explorer.EXE
When this is done, press the โTestโ button again to run the Ruleset Test. The output should now be different, especially in Phase 3:
Ruleset Test Output**Phase 3: Completed filtering (rules).
id: 184666
level: 12
description: Sysmon – Suspicious Process – svchost.exe
groups: [“sysmon”,”sysmon_process-anomalies”]
firedtimes: 1
gdpr: [“IV_35.7.d”]
gpg13: “-“
hipaa: [“164.312.b”]
mail: true
mitre.id: {“id”:[“T1055″],”tactic”:[“Defense Evasion”,”Privilege Escalation”],”technique”:[“Process Injection”]}
mitre.technique: {“id”:[“T1055″],”tactic”:[“Defense Evasion”,”Privilege Escalation”],”technique”:[“Process Injection”]}
nist_800_53: [“AU.6″,”SI.4”]
pci_dss: [“10.6.1″,”11.4”]
tsc: [“CC7.2″,”CC7.3″,”CC6.1″,”CC6.8”]
**Alert to be generated.
Because our rule now matches the log, the triggered Rule is now 184666
. There is now also more information on the output thanks to the mitre
and group
options in the rule block.
Q 3. From the Ruleset Test results, what is the <mitre> ID of rule id 184666?
Answer: T1055
Q 4. According to the Wazuh documentation, what is the description of the rule with a classification level of 12?
Answer: High Importance Level
Q 5. In the Ruleset Test page, change the value of โsysmon.imageโ to โtaskhost.exeโ, and press the โTestโ button again. What is the ID of the rule that will get triggered?
Answer: 184736
URL โ https://github.com/wazuh/wazuh/blob/master/ruleset/rules/0330-sysmon_rules.xml
Task 4 Rule Order
- In Wazuh rules are processed based on several factors determining rule order
- One factor that will be discussed that is relevant to making custom rules is the โifโ condition prerequisites
- if_group option in the previous task, but there other โifโ condition prerequisites like the if_side option shown below:
sysmon_rules.xml
<rule id=”184667″ level=”0″>
<if_sid>184666</if_sid>
<field name=”sysmon.parentImage”>\\\\services.exe</field>
<description>Sysmon – Legitimate Parent Image – svchost.exe</description>
</rule>
โข if_sid โ Specifies the ID of another rule that triggers this rule. In this example, the rule is triggered if an event with the ID of 184666
has been triggered.
These โifโ condition prerequisites are considered the โparentโ that must be evaluated first. Because of this parent-child relationship, it is essential to note that Wazuh Rules are triggered from a top-to-down manner. When rules are processed, the condition prerequisites are checked, and the rule order is updated.
Testing the Rule Order
Go back to the โRuleset Testโ page. Paste the exact log entry we used in the previous task. We want to trigger Rule ID 184667
, so our Sysmon log entry should have the value of “sysmon.parentImage” changed to C:\\\\Windows\\\\services.exe
.
The log entry should now look like the one below:
Sysmon LogMar 29 13:36:36 WinEvtLog: Microsoft-Windows-Sysmon/Operational: INFORMATION(1): Microsoft-Windows-Sysmon: SYSTEM: NT AUTHORITY: WIN-P57C9KN929H: Process Create: UtcTime: 2017-03-29 11:36:36.964 ProcessGuid: {DB577E3B-9C44-58DB-0000-0010B0983A00} ProcessId: 3784 Image: C:\\WINDOWS\\system32\\svchost.exe CommandLine: “C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe” “-file” “C:\\Users\\Alberto\\Desktop\\test.ps1” CurrentDirectory: C:\\Users\\Alberto\\Desktop\\ User: WIN-P57C9KN929H\\Alberto LogonGuid: {DB577E3B-89E5-58DB-0000-0020CB290500} LogonId: 0x529cb TerminalSessionId: 1 IntegrityLevel: Medium Hashes: MD5=92F44E405DB16AC55D97E3BFE3B132FA,SHA256=6C05E11399B7E3C8ED31BAE72014CF249C144A8F4A2C54A758EB2E6FAD47AEC7 ParentProcessGuid: {DB577E3B-89E6-58DB-0000-0010FA3B0500} ParentProcessId: 2308 ParentImage: C:\\Windows\\services.exe ParentCommandLine: C:\\Windows\\Explorer.EXE
Pressing the โTestโ button would then output the following:
Ruleset Test Output**Phase 3: Completed filtering (rules).
id: 184667
level: –
description: Sysmon – Legitimate Parent Image – svchost.exe
groups: [“sysmon”,”sysmon_process-anomalies”]
firedtimes: 1
gdpr: “-“
gpg13: “-“
hipaa: “-“
mail: “-“
mitre.id: “-“
mitre.technique: “-“
nist_800_53: “-“
pci_dss: “-“
tsc: “-“
We can see that the triggered rule is 184667
, which is what we expected. What is not shown in the output, however, is that before 184667
was triggered, Wazuh first checked if_sid
and found that Rule ID184666
was a prerequisite. Before rule ID 184666
, Wazuh then saw that it has if_group
set to sysmon_event1
, which is associated with Rule ID 184665
. This goes on and on until all the chains of prerequisites are satisfied.
Q 6. In the sysmon_rules.xml file, what is the Rule ID of the parent of 184717?
Answer: 184716
Task 5 Custom Rules
As mentioned before, the pre-existing rules are comprehensive. However, it cannot cover all use cases, especially for all organizations with unique needs and requirements.
There are several reasons why we want to have custom rules:
- You want to enhance the detection capabilities of Wazuh.
- You are integrating a not-so-well-known security solution.
- You use an old version of a security solution with an older log format.
- You recently learned of a new attack and want to create a specific detection rule.
- You want to fine-tune a rule.
In this task the auitd_rules.xml will be used, URL: https://github.com/wazuh/wazuh/blob/master/ruleset/rules/0365-auditd_rules.xml
Auditd Logtype=SYSCALL msg=audit(1479982525.380:50): arch=c000003e syscall=2 success=yes exit=3 a0=7ffedc40d83b a1=941 a2=1b6 a3=7ffedc40cce0 items=2 ppid=432 pid=3333 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm=”touch” exe=”/bin/touch” key=”audit-wazuh-w” type=CWD msg=audit(1479982525.380:50): cwd=”/var/log/audit” type=PATH msg=audit(1479982525.380:50): item=0 name=”/var/log/audit/tmp_directory1/” inode=399849 dev=ca:02 mode=040755 ouid=0 ogid=0 rdev=00:00 nametype=PARENT type=PATH msg=audit(1479982525.380:50): item=1 name=”/var/log/audit/tmp_directory1/malware.py” inode=399852 dev=ca:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=CREATE type=PROCTITLE msg=audit(1479982525.380:50): proctitle=746F756368002F7661722F6C6F672F61756469742F746D705F6469726563746F7279312F6D616C776172652E7079
The log describes an event wherein a touch
command (probably as root user) was used to create a new file called malware.py
in the /var/log/audit/tmp_directory1/
directory. The command was successful, and the log was generated based on an audit rule with the key “audit-wazuh-w”.
When Wazuh ingests the above log, the pre-existing rule below will get triggered because of the value of <match>
:
auditd_rules.xml<rule id=”80790″ level=”3″><if_group>audit_watch_write</if_group><match>type=CREATE</match><description>Audit: Created: $(audit.file.name)</description><group>audit_watch_write,audit_watch_create,gdpr_II_5.1.f,gdpr_IV_30.1.g,</group></rule>
Adding Local Rules
For this exercise, letโs create a custom rule that will override the above rule so we have more control over the information we display.
To do this, you need to do the following:
- Connect to the server using SSH at
10.10.177.121
and usethm
for the username andTryHackMe!
the password. The credentials and connection details are listed in Task 1 of this room. - Use the
sudo su
command to become the root user. - Open the file
/var/ossec/etc/rules/local_rules.xml
using your favourite editor. - Paste the following text at the end of the file:
local_rules.xml<group name=”audit,”><rule id=”100002″ level=”3″><if_sid>80790</if_sid><field name=”audit.cwd”>downloads|tmp|temp</field><description>Audit: $(audit.exe) created a file with filename $(audit.file.name) the folder $(audit.directory.name).</description><group>audit_watch_write,</group></rule></group>
The rule above will get triggered if a file is created in the downloads, tmp, or temp folders. Letโs break this down so we can better understand:
- group name=โaudit,โ We are setting this to the same value as the grouped rules in audit_rules.xml.
- rule id=โ100002″ โ Each custom rule needs to have a unique ID. Custom IDs start from
100001
onwards. Since there is already an existing example rule that uses100001
, we are going to use100002
. - level=โ3″ โ We are setting this to 3 (Successful/Authorized events) because a file created in these folders isnโt necessarily malicious.
- if_sid โ We set the parent to rule ID
80790
because we want that rule to be processed before this one. - field name=โaudit.directory.nameโ The string here is matched using regex. In this case, we are looking for tmp, temp, or downloads matches. This value is compared to the
audit.cwd
variable fetched by the auditd decoder. - description The description that will appear on the alert. Variables can be used here using the format
$(variable.name)
. - group โ Used for grouping this specific alert. We just took the same value from rule
80790
.
Save the file and run the code below to restart wazuh-manager so it can load the new custom rules:
Bashsystemctl restart wazuh-manager
Go back to the Wazuh dashboard, access the โRuleset Testโ page and paste the sample auditd log entry found above. If all goes well, you should see the following โPhase 3โ output:
Ruleset Test Output**Phase 3: Completed filtering (rules).
id: ‘100002’
level: ‘3’
description: ‘Audit: /bin/touch created a file with filename /var/log/audit/tmp_directory1/malware.py the folder /var/log/audit.’
groups: ‘[“audit”,”audit_watch_write”]’
firedtimes: ‘1’
mail: ‘false’
From the results above, we can see that the custom rules that we created triggered an alert successfully.
Q 7. What is the regex field name used in the local_rules.xml?
Answer: audit.cwd
Step 1: SSH into the machine with the given credentials and elevate privileges to root using the sudo su command
Editing the file in nano โ
Q 8. Looking at the log, what is the current working directory (CWD) from where the command was executed?
Answer: /var/log/audit
Running the sample log in the rule test against the newly added rule in the local_rules.xml file
Task 6 Fine-Tuning
You can fine-tune the custom rule by adding more child rules, each focusing on specific related data from the logs. For example, you can use the values decoded by auditd
decoder, as shown in the Phase 2 results of the previous test.
Ruleset Test Output**Phase 2: Completed decoding.
name: ‘auditd’
parent: ‘auditd’
audit.arch: ‘c000003e’
audit.auid: ‘0’
audit.command: ‘touch’
audit.cwd: ‘/var/log/audit’
audit.directory.inode: ‘399849’
audit.directory.mode: ‘040755’
audit.directory.name: ‘/var/temp/downloads/tmp_directory1/’
audit.egid: ‘0’
audit.euid: ‘0’
audit.exe: ‘/bin/touch’
audit.exit: ‘3’
audit.file.inode: ‘399852’
audit.file.mode: ‘0100644’
audit.file.name: ‘/var/log/audit/tmp_directory1/malware.py’
….
We can use the above data to make our detection rules as broad or as specific as needed. The following is an expanded version of local_rules.xml
that incorporates more of the log’s data.
local_rules.xml<group name=”audit,”><rule id=”100002″ level=”3″><if_sid>80790</if_sid><field name=”audit.directory.name”>downloads|tmp|temp</field><description>Audit: $(audit.exe) created a file with filename $(audit.file.name) in the folder $(audit.directory.name).</description><group>audit_watch_write,</group></rule><rule id=”100003″ level=”12″><if_sid>100002</if_sid><field name=”audit.file.name”>.py|.sh|.elf|.php</field><description>Audit: $(audit.exe) created a file with a suspicious file extension: $(audit.file.name) in the folder $(audit.directory.name).</description><group>audit_watch_write,</group></rule><rule id=”100004″ level=”6″><if_sid>100002</if_sid><field name=”audit.success”>no</field><description>>Audit: $(audit.exe) created a file with filename $(audit.file.name) but failed</description><group>audit_watch_write,</group></rule><rule id=”100005″ level=”12″><if_sid>100003</if_sid><field name=”audit.file.name”>>malware|shell|dropper|linpeas</field><description>Audit: $(audit.exe) created a file with suspicious file name: $(audit.file.name) in the folder $(audit.directory.name).</description><group>audit_watch_write,</group></rule><rule id=”100006″ level=”0″><if_sid>100005</if_sid><field name=”audit.file.name”>malware-checker.py</field><description>False positive. “malware-checker.py” is used by our red team for testing. This is just a temporary exception.</description><group>audit_watch_write,</group></rule></group>
You can test these rules by updating thelocal_rules.xml
file and checking the output on the Ruleset Test Page.
Q 9. If the filename in the logs is โtest.phpโ, what rule ID will be triggered?
Answer: 100003<rule id=”100003″ level=”12″>
<if_sid>100002</if_sid>
<field name=”audit.file.name”>.py|.sh|.elf|.php</field>
<description>Audit: $(audit.exe) created a file with a suspicious file extension: $(audit.file.name) in the folder $(audit.directory.name).</description>
<group>audit_watch_write,</group>
</rule>
Q 10. If the filename in the logs is โmalware-checker.shโ, what is the rule classification level in the generated alert?
Answer: 12
Leave a Reply