Lock & Load III: Arming Yourself with Custom Sigma Rules

Lock & Load - Arming Yourself with Custom Sigma Rules

Welcome back to this series on making threat intelligence actionable!

In my last blog instalment of this series, we looked at extracting IOCs and TTPs from threat intelligence articles and using them to perform IOC-based and TTP-based threat hunts.

Hunting IOCs was simple, however for TTPs we had to correlate MITRE ATT&CK techniques mentioned in these articles to corresponding Sigma rules that could detect these techniques. We discussed the short coming of this approach to performing TTP-based threat hunting, in that TTPs listed in the MITRE ATT&CK framework may differ from the ones a specific threat is using.

Often a threat intelligence article will list a whole bunch of MITRE ATT&CK techniques right at the end of the article to summarise what the threat did. We can hunt for these TTPs by finding a Sigma rule with a matching technique ID, but this may not detect what the threat actually did (the specific procedure/behaviour). A senior threat intelligence analyst will go beyond generic TTPs and zero in on specifics by creating their own Sigma rules that are specifically designed to detect the threat being detailed.

In this instalment, we will explore how to create our own custom Sigma rules to combat specific threats and then translate this Sigma rule to our hunting platform of choice. Let’s dig in!

Sigma Rules

As a quick refresher, Sigma rules are a set of rules that are used to define and describe log events in a standardised way.

Sigma Logo

Sigma rules are used primarily in the field of cybersecurity to help security analysts quickly identify security threats in their organisation’s log data. These threats can include malware, phishing, brute-force attacks, lateral movement, and more.

Sigma rules are written in simple and flexible YAML syntax, which is easy to write and understand, and do not relate to any specific security solution. They are designed to be universal and can be translated to a wide range of security solutions from EDRs to SIEMs using a set of standardised fields and modifiers. There is a large open-source repository of Sigma rules on GitHub which you can freely use and contribute to, which I highly encourage you to do.

A threat intelligence analyst will use Sigma rules to hunt for a threat actor’s TTPs or behaviour. The majority of these rules are mapped to the MITRE ATT&CK framework and threat intelligence articles will detail the TTPs exhibited by a certain threat. If you can match up the MITRE ATT&CK technique with a Sigma rule, in theory, you can then hunt for this TTP.

Of course, we have discussed that Sigma rules may not detect a specific way a threat actor performed a TTP and, as such, just finding corresponding Sigma rules is a flawed approach when it comes to TTP-based threat hunting. Instead, we should know how to create our own Sigma rules so we can better detect the threats we face.

With this in mind let’s look at the basic anatomy of a Sigma Rule.

Anatomy of a Sigma Rule

Sigma rules consist of several components. Some of these provide metadata about the rule, while others define the logic used to detect specific log events.

YAML
title: a short capitalised title with less than 50 characters
id: generate one here <https://www.uuidgenerator.net/version4>
status: experimental # can be experiemtanl | test | stable | deprecated
description: A description of what your rule is meant to detect 
references:
    - A list of all references that can help a reader or analyst understand the meaning of a triggered rule
tags:
    - attack.execution  # example MITRE ATT&CK category
    - attack.t1059      # example MITRE ATT&CK technique id
    - car.2014-04-003   # example CAR id
author: Michael Haag, Florian Roth, Markus Neis  # example, a list of authors
date: 2018/04/06  # Rule date
logsource:                      # important for the field mapping in predefined or your additional config files
    category: process_creation  # In this example we choose the category 'process_creation'
    product: windows            # the respective product
detection:
    selection:
        FieldName: 'StringValue'
        FieldName: IntegerValue
        FieldName|modifier: 'Value'
    condition: selection
fields:
    - fields in the log source that are important to investigate further
falsepositives:
    - describe possible false positive conditions to help the analysts in their investigation
level: one of five levels (informational, low, medium, high, critical)

The components of a Sigma rule include:

  1. title — A descriptive title that summarizes the purpose of the rule.
  2. id — This is a unique identifier that represents the specific rule.
  3. status — This shows the stability of the rule and indicates to the user how much refactoring (filtering out of false positives) may be required when they use it.
  4. description — A more detailed description of the behaviour or activity that the rule is designed to detect.
  5. references — Threat intelligence article(s) the rule was created from.
  6. author — The person who is accredited to writing the rule.
  7. date — When the Sigma rule was created. There may also be a modified date if the rule has been updated.
  8. tags — MITRE ATT&CK mappings or other framework mappings.
  9. logsource — The type of log data that the rule is designed to analyse, such as Windows event logs, syslog data (Linux), Sysmon data, etc.
  10. detection — The actual detection logic used to identify log events that match the behaviour or activity described in the rule. This query is written in a specific syntax using fieldnames and modifiers (more on this later).
  11. condition — An optional component that specifies additional conditions (through Boolean operators) that must be met for the rule to trigger an alert or notification. This uses the detection logic previously defined and is often used to exclude false positives.
  12. falsepositives — A description of any known scenarios that might trigger the rule but do not indicate an actual security threat. This helps to prevent unnecessary alerts and reduce the number of false positives.
  13. level — The severity of an incident if this detection triggers. This helps users triage alerts.

These components allows a Sigma rule to provide a clear and standardised way to define detection rules that can be shared across different security tools and platforms.

With a firm understanding of what makes up a Sigma rule, we can jump into the heart of all Sigma rules… the detection logic.

Sigma Detection Logic

Let’s take a look at the following rule titled HackTool — Hydra Password Bruteforce Execution to get an understanding of Sigma detection logic. This rule is very simple and detects command line parameters used by the Hydra login cracker (a hacking tool). This tool is used to brute force logins to online services.

YAML
title: HackTool - Hydra Password Bruteforce Execution
id: aaafa146-074c-11eb-adc1-0242ac120002
status: test
description: Detects command line parameters used by Hydra password guessing hack tool
references:
    - https://github.com/vanhauser-thc/thc-hydra
author: Vasiliy Burov
date: 2020/10/05
modified: 2023/02/04
tags:
    - attack.credential_access
    - attack.t1110
    - attack.t1110.001
logsource:
    category: process_creation
    product: windows
detection:
    selection:
        CommandLine|contains|all:
            - '-u '
            - '-p '
        CommandLine|contains:
            - '^USER^'
            - '^PASS^'
    condition: selection
falsepositives:
    - Software that uses the caret encased keywords PASS and USER in its command line
level: high

This rule focuses on process creation logs on the Windows platform (as specified under logsource) and it detects when certain command line parameters are present (-u and -p used in conjunction with ^USER^ or ^PASS^).

The -u and -p are command line options specific to Hydra which represent username and password, respectively. The ^USER^ and ^PASS^ command line parameters are placeholders that are used when a list of usernames or passwords are fed into the tool.

The condition: selection defined in the Sigma rule dictates when these command line parameters should trigger a detection. In this case, it’s when -u and -p are both used on the command line (as defined by CommandLine|contains|all) and the command line also contains either ^USER^ or ^PASS^ (defined by CommandLine|contains).

For example, the following command line would be detected.

PowerShell
<hydra>.exe -u <username> -p ^PASS^ ...
<hydra>.exe -u ^USER^ -p <password> ...
<hydra>.exe -u ^USER^ -p ^PASS^ ...

The detection logic is the heart of all Sigma rules and will trigger a rule when observed in the defined log source. The example above demonstrated simple detection logic whereby the rule would trigger if certain command line parameters were seen in a log source. This detection logic can be broken down into two parts the selection part and the condition part.

The Selection Part

The selection part contains specific fields which the rule looks for in log sources. These fields can be log source specific (e.g. for Windows event logs a field could be EventID) or more generic and correspond to multiple log sources (e.g. CommandLine). For example, the following rule uses the Windows security event logs and detects on the Event ID 1102 which indicates the security event log was cleared.

YAML
title: Security Event Log Cleared
id: a122ac13-daf8-4175-83a2-72c387be339d
status: test
description: Checks for event id 1102 which indicates the security event log was cleared.
references:
    - https://github.com/Azure/Azure-Sentinel/blob/f99542b94afe0ad2f19a82cc08262e7ac8e1428e/Detections/SecurityEvent/SecurityEventLogCleared.yaml
author: Saw Winn Naung
date: 2021/08/15
modified: 2022/12/25
tags:
    - attack.t1070.001
logsource:
    service: security
    product: windows
detection:
    selection:
        EventID: 1102
        Provider_Name: Microsoft-Windows-Eventlog
    condition: selection
falsepositives:
    - Legitimate administrative activity
fields:
    - SubjectLogonId
    - SubjectUserName
    - SubjectUserSid
    - SubjectDomainName
level: medium
When writing a Sigma rule you can create multiple selection blocks.

The Condition Part

The condition part contains the logic of when the detection should trigger. This condition is made up of Boolean operators and wildcards. Here are some common examples:

  • the condition condition: all of selection_* will match all of the selections described that start with selection_.
  • the condition condition: any of selection_* will match any of the selections described that start with selection_.
  • the condition condition: selection1 and selection2will trigger only if selection1 and selection2 both match.
  • the condition condition: selection1 or selection2 will trigger if either selection1 or selection2 match.

These Boolean operators can also be grouped using parenthesises to create more complex conditions.

These conditions are vital when it comes to excluding false positives that may be triggered by a selection. By grouping known false positives into a selection block you can exclude the known good and reduce overhead.

For example, the following rule is designed to detect when Python initiates a network connection while ignoring when either Anaconda updates, Juptyer Notebooks are run, or connections to localhost are made.

YAML
title: Python Initiated Connection
id: bef0bc5a-b9ae-425d-85c6-7b2d705980c6
status: experimental
description: Adversaries may attempt to get a listing of services running on remote hosts, including those that may be vulnerable to remote software exploitation
references:
    - https://github.com/redcanaryco/atomic-red-team/blob/f339e7da7d05f6057fdfcdd3742bfcf365fee2a9/atomics/T1046/T1046.md#atomic-test-4---port-scan-using-python
    - https://pypi.org/project/scapy/
author: frack113
date: 2021/12/10
modified: 2022/09/20
tags:
    - attack.discovery
    - attack.t1046
logsource:
    category: network_connection
    product: windows
detection:
    selection:
        Initiated: 'true'
        Image|contains: python
    filter_conda:
        # Related to anaconda updates. Command example: "conda update conda"
        # This filter will only work with aurora agent enriched data as Sysmon EID 3 doesn't contain CommandLine nor ParentImage
        ParentImage: C:\ProgramData\Anaconda3\Scripts\conda.exe
        CommandLine|contains|all:
            - 'C:\ProgramData\Anaconda3\Scripts\conda-script.py'
            - 'update'
    filter_conda_jupyter_notebook:
        # Related to anaconda opening an instance of Jupyter Notebook
        # This filter will only work with aurora agent enriched data as Sysmon EID 3 doesn't contain CommandLine nor ParentImage
        ParentImage: C:\ProgramData\Anaconda3\python.exe
        CommandLine|contains: 'C:\ProgramData\Anaconda3\Scripts\jupyter-notebook-script.py'
    filter_local_communication:
        # This could be caused when launching an instance of Jupyter Notebook locally for example but can also be caused by other instances of python opening sockets locally etc. So comment this out if you want to monitor for those instances
        DestinationIp: 127.0.0.1
        SourceIp: 127.0.0.1
    condition: selection and not 1 of filter_*
falsepositives:
    - Legitimate python script
level: medium

These three exceptions are defined as selections starting with filter_ and are excluded in the condition block using the and not 1 of filter_* condition.

Writing our own Rule

Let’s take a crack at writing our own Sigma rule!

To start take a look at this threat intelligence article by Red Canary. It details how tax-themed phishing emails are being used to deliver GuLoader malware. Scrolling through the article we can see that Red Canary have written some pseudocode that can be used to detect the behaviour of this threat. In this case, the detection analytic should identify wscript.exe launching PowerShell to download and execute a payload.

YAML
parent_process == "wscript.exe"

&&

process == "powershell.exe"

&&

command_includes ("invoke-webrequest" || "iwr")

We can translate this detection logic into a formal Sigma rule.

I have filled out the metadata for this Sigma rule as follows.

YAML
title: GuLoader Phishing Email
id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee
status: test
description: Detects GuLoader executed from a phishing email
references:
    - https://redcanary.com/blog/tax-season-phishing/
author: Me
date: 2023/10/05
tags:
    - attack.initial_access
    - attack.T1566.001
logsource:
    category: process_creation
    product: windows
detection:
  selection: ...
  condition: ...
falsepositives:
    - None
level: high

Here we are looking at Windows process creation events (or log sources that would contain this data) and have mapped our rule to MITRE ATT&CK technique T1566.001 (initial access via spear-phishing attachment). Now we need to write the detection logic under the selection field!

Reading the detection analytic we can see that we need to identify the parent process, name of the process, and the command line the process runs with. For a Sigma rule we can use the following fields to do this:

  • ParentImage field with the endswith modifier and one option \wscript.exe
  • Image field with theendswith modifier and one option \powershell.exe
  • CommandLine field with the contains modifier and two options invoke-webrequest or iwr
YAML
title: GuLoader Phishing Email
id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee
status: test
description: Detects GuLoader executed from a phishing email
references:
  - https://redcanary.com/blog/tax-season-phishing/
author: Me
date: 2023/10/05
tags:
  - attack.initial_access
  - attack.T1566.001
logsource:
   category: process_creation
   product: windows
detection:
  selection:
    ParentImage|endswith: '\wscript.exe'
    Image|endswith: '\powershell.exe'
    CommandLine|contains:
      - 'iwr'
      - 'invoke-webrequest'
  condition: ... 
falsepositives:
    - None
level: high

Now we need to fill out the condition section to define when the detection should trigger. As we can see from the pseudo detection logic these conditions are all chained together by && (and) conditions. Hence, our Sigma rule condition can simply be selection as shown below. This requires all fields defined in our selection to be met.

YAML
title: GuLoader Phishing Email
id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee
status: test
description: Detects GuLoader executed from a phishing email
references:
 - https://redcanary.com/blog/tax-season-phishing/
author: Me
date: 2023/10/05
tags:
  - attack.initial_access
  - attack.T1566.001
logsource:
   category: process_creation
   product: windows
detection:
  selection:
    ParentImage|endswith: '\wscript.exe'
    Image|endswith: '\powershell.exe'
    CommandLine|contains:
      - 'iwr'
      - 'invoke-webrequest'
  condition: selection
falsepositives:
    - None
level: high

There are currently no false positives associated with our detection logic so we don’t need to add additional selection blocks or Boolean parameters to the conditions field. Our Sigma rule is complete, congrats!

For a complete guide on sigma rule creation (and a list of common pitfalls when creating them) check out the official Rule Creation Guide by Florian Roth.

The final step is translating this Sigma rule into a security solution specific language. We can do this using a tool like uncoder.io.

Now we can begin using this as a detection rule.

The beauty with Sigma rules is that if you have multiple security products (or change to a new one), you can translate this Sigma rule across with ease. So go ahead and get started making your own! Until then, happy hunting friends!

Discover more in the Load & Load: Actionable Threat Intelligence 101 series!

Back to top arrow

Interesting in Learning More?

Learn the dark arts of red teaming

If you want more of a challenge, take on one of their certification exams and land your next job in cyber:

Learn more cyber security skills

If you’re looking to level up your skills even more, have a go at one of their certifications: