Writing your first rule

Use a Message Data Model to write a rule.

Now that we understand what the Message Data Model is, it's time to learn about the next core building block of Sublime, Message Query Language (MQL), and write our first rule.

MQL is the query language that powers Sublime rules. It's very versatile and lets us define any pattern of behavior in our email environment.

Let's take a look at the phishing attack from our previous tutorial more closely:

The sender's display name is Joshua Kamdjou, but this isn't his real email address. Let's write a simple rule to detect this attack.

Step 1: Determine what attributes of the message you'll use for your rule

Let's make a list of everything that's suspicious about this message:

  • the sender's display name impersonates a known contact, "Joshua Kamdjou", but is not from his work email ([email protected])
  • suspicious phrases like "Urgent" and "W2" in the subject
  • suspicious phrases like "need your help" and "send me the w2s" in the body
  • email signature with Josh's name and title, but not from his known email address

For the purposes of this tutorial we'll keep things simple and start with the impersonation of Josh's display name.

Step 2: Write a query to build the syntax of your rule

Sublime queries are used to extract or summarize information from a message. We start with queries because they'll return more verbose output, and then we'll turn it into a rule when we're done.

By looking at the Message Data Model (MDM) reference, we can see the display name is located in the sender object. Let's confirm this by running a simple query.

๐Ÿ“˜

CLI hint

The Sublime CLI's analyze command can run queries and rules on any of the following types of files: .eml, .msg, .mdm, and .mbox. Below we're using the MDM we generated from the first tutorial, but you could also use the EML. Both can be downloaded directly here.

sublime analyze -i impersonation.mdm -q 'sender.display_name'

Output:

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘          Results          โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

File Name: impersonation.mdm

Total Rules: 0
Total Queries: 1

QUERIES

  - Query 1
    Result: Joshua Kamdjou

We've successfully extracted the sender's display name using a Sublime query.

Now, let's modify our query to look for Josh's full name. We'll start with MQL's case-insensitive comparison operator: =~:

sublime analyze -i impersonation.mdm -q 'sender.display_name =~ "Joshua Kamdjou"'

Output:

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘          Results          โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

File Name: impersonation.mdm

Total Rules: 0
Total Queries: 1

QUERIES

  - Query 1
    Result: True

Great!

The query above will look for an exact match, so we'll make this a little more robust by using MQL's ilike function for case-insensitive string search:

sublime analyze -i impersonation.mdm -q 'ilike(sender.display_name, "*Josh* Kamdjou*")'

Now, this query will return true for all emails that we receive from Josh, so we'll want to make sure we exclude those:

sublime analyze -i impersonation.mdm -q 'ilike(sender.display_name, "*Josh* Kamdjou*") and sender.email.email != "[email protected]"'

Output:

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘          Results          โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

File Name: impersonation.mdm

Total Rules: 0
Total Queries: 1

QUERIES

  - Query 1
    Result: True

Awesome! This is looking pretty good. Now we're ready to turn this into a rule and save it for future use.

Step 3: Save and run your rule

Sublime rules and queries are stored in YAML files. Open up a new file called ceo_impersonation.yml with your text editor of choice and paste in the following:

name: "CEO impersonation"
source: |
  ilike(sender.display_name, "*Josh* Kamdjou*") 
  and sender.email.email != "[email protected]"
type: "rule"

Let's run our new rule to make sure it works as expected:

sublime analyze -i impersonation.mdm -r ceo_impersonation.yml

:tada: You've done it! Congratulations on writing your first detection rule. Josh is now protected from display name impersonations.