# Reflex Query Language (RQL)

**Reflex Query Language (RQL)** is a query language designed to query events within Case-Hub. RQL is used while creating Event Rules to query the Event data and match certain criteria.

## Event Fields

* `observables|observables.*`
* `value`
* `tlp`
* `tags`
* `spotted`
* `safe`
* `source_field`
* `data_type`
* `ioc`
* `original_source_field`
* `title`
* `description`
* `tlp`
* `severity`
* `status`,
* `reference`
* `source`
* `signature`
* `tags`
* `raw_log|raw_log.*`

## Supported Expressions

The following Expressions are used to compare target field data to intended data:

<table><thead><tr><th width="184.33333333333331">Expression</th><th width="333">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>RegExp</code></td><td>The item has a value that matches a regular expression</td><td><code>title RegExp "^Event.*"</code></td></tr><tr><td><code>In</code></td><td>The item has a value in a list of values</td><td><code>observables.tags.name in ["malware"]</code></td></tr><tr><td><code>Contains</code></td><td>The target value contains a specific string</td><td><code>description Contains "malware"</code></td></tr><tr><td><code>ContainsCIS</code></td><td>Same as <code>Contains</code> but will make the target value and checked value the same case</td><td></td></tr><tr><td><code>=|eq|Eq</code></td><td>Equal to (strings or numbers)</td><td></td></tr><tr><td><code>!=|ne|Ne|NE</code></td><td>Not equal to (strings or numbers)</td><td></td></tr><tr><td><code>>|gt</code></td><td>Greater than (> or gt)</td><td></td></tr><tr><td><code>>=|gte</code></td><td>Greater than or equal to (>= or gte)</td><td></td></tr><tr><td><code>&#x3C;|lt</code></td><td>Less than (&#x3C; or lt)</td><td></td></tr><tr><td><code>&#x3C;=|lte</code></td><td>Less than or equal to (&#x3C;= or lte)</td><td></td></tr><tr><td><code>InCIDR</code></td><td>The IP address is in a specific CIDR network</td><td><code>192.168.1.1 InCIDR 192.168.0.0/16</code></td></tr><tr><td><code>Is</code></td><td>Use for boolean operations like "Is True"</td><td><code>ioc Is True</code></td></tr><tr><td><code>Exists</code></td><td>The field exists at all, useful if you don't care what the target value</td><td></td></tr><tr><td><code>Between</code> </td><td>The item has a value between a given range</td><td><code>tlp Between "1,3"</code></td></tr><tr><td><code>StartsWith</code></td><td>The item has a value that starts with a certain string</td><td><code>url StartsWith "https"</code></td></tr><tr><td><code>EndsWith</code></td><td>The item has a value that ends with a certain string</td><td><code>domain EndsWith ".tk"</code></td></tr><tr><td><code>Expand</code></td><td>When you want two conditions on a nested object to be true use each statement. </td><td>For example, The observable <code>127.0.0.1</code> should have a value of <code>127.0.0.1</code> and <code>safe</code> is True, the query would look like <code>Expand observables (value = "127.0.0.1" and safe Is True)</code></td></tr><tr><td><code>Intel|Threat</code></td><td>Allows RQL to check the value of a field against a Case-Hub Intel List (threat lists)</td><td></td></tr><tr><td><code>Not</code></td><td>The expression within this block should not match. <br><br>Note: Can only be used on <code>eq</code>, <code>in</code>, <code>InCIDR</code>, <code>contains</code>, <code>between</code> AND <code>regexp.</code></td><td><code>title Not Eq "Suspicious DNS Query"</code></td></tr></tbody></table>

Note that the Items that don't have a specified field may match a `Not` expression e.g. `ip NOT InCIDR "192.168.0.0/16"` may match on an event not having an `ip` field, pair this with `ip exists AND ip NOT InCIDR "192.168.0.0/16"`

## Mutators <a href="#mutators" id="mutators"></a>

Mutators take a field and perform an extra operation on it to make it digestible by the downstream comparison. Assume you want to find any Event with a domain observable where the length of the domain is longer than 20 characters

* `|length` - How long a string is e.g. `url.domain|length > 20`
* `|count` - The number of items in an array value `observables|count > 2`
* `|lowercase` - Lowercase a string (redundant for `ContainsCIS` but can be used for other fields)
* `|refang` - If for some reason the target value has been defanged, think `hXXps[:]//` instead of `https://` this will refang the value to perform a proper comparison e.g. `url.full|refang eq "https://www.google.com"`
* `|b64decode` - If the target value is base64 encoded and you want to write rules using the terms within it, first base64 decode it, e.g. `command|b64decode Contains "Invoke-Mimikatz"`
* `|b64extract` - Will attempt to find base64 encoded data in a string and extract it for comparison later in the query e.g. an event contains a command `powershell -encodedCommand SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AaQBwAGkAbgBmAG8ALgBpAG8ALwBpAHAA` would extract and decode `SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AaQBwAGkAbgBmAG8ALgBpAG8ALwBpAHAA` to `Invoke-WebRequest https://www.ipinfo.io/ip`. An analyst could then use a query like `command|b64extract Contains "ipinfo.io"`
* `|urldecode` - Unescapes an escaped URL so that direct comparisons can be made
* `|any` - Force the following condition to match any item in the array (Can only be used on `Contains` and `In` expressions)
* `|all` - Force the condition to match all items in the array (Can only be used on `Contains` and `In` expressions)
* `|avg` - Calculates the average value given a list of values e.g. `observables.risk_score|avg > 7`
* `|max` - Finds the max value given a list of values e.g. `vulnerablities.cvss_score|max > 7`
* `|min` - Finds the minimum value given a list of values
* `|sum` - Add up all the values in a list of integer or float values
* `|split` - Splits a string that contains spaces into an array
* `|geo_country` - Returns the ISO Code for the country an IP resides in
* `|geo_continent` - Returns the ISO Code for the content an IP resides in
* `|geo_timezone` - Returns the timezone an IP resides in
* `|reverse_lookup` - Takes an IP and attempts to return the associated hostname
* `|nslookup_a` - Fetches the A record for a domain name
* `|nslookup_aaaa` - Fetches the AAAA record for a domain name
* `|nslookup_mx` - Fetches the MX records for a domain name
* `|nslookup_ns` - Fetches the NS records for a domain name
* `|nslookup_ptr`- Fetches the PTR records for a domain
* `|is_private` - Returns True if an IP is RFC1918
* `|is_global` - Returns True if an IP is routable on the internet
* `|is_multicast` - Returns True if an IP is multicast
* `|is_ipv6` - Returns True if an IP is IPv6

## Query Examples <a href="#example-queries" id="example-queries"></a>

```
# Match any Suspicious DNS query only if it came from the Administrator on a domain joined machine and the target observable is evil.com
title = "Suspicious DNS Query" and user Contains "Administrator" and hostname EndsWith "ad.blusapphire.com" and (observables.data_type = "domain" and observables.value = "evil.com")
```

```
# Match any cases referencing malware or with a severity higher than 3
description Contains "malware" or severity > 3
```

```
# Match any event that has a domain with evil.com or an IP with 127.0.0.1
(observables.data_type = "domain" and observables.value = "evil.com") or (observables.data_type = "ip" and observables.value = "127.0.0.1")
```

```
# Match any Event that has all of the below observables
observables.values|all in ["evil.com","blusapphire.com"]
```

```
# Match any event that contains a base64 encoded command that once decoded contains the following phrases
command exists and command|b64decode|lowercase Contains ["invoke-mimikatz","invoke-bloodhound","invoke-powerdump","invoke-kerberoast"]
```

```
# Match any suspicious DNS query for a specific domain that originates from a specific user and source process 
# Should always be this event title
title = "Suspicious DNS Query"

# Observables should always exist
and observables exists

# Brian must be the source user of the event
and expand observables (value Contains "Brian" and source_field|lowercase = "winlog.event_data.user")

# And the DNS resolution should always be for netwars-support.slack.com
and expand observables (value = "netwars-support.slack.com" and source_field|lowercase = "dns.question.name")

# And should originate from Slack
and raw_log.process.executable EndsWith "slack.exe"
```

```
# Check to see if the user in the event is in the Allowed Users intel list
expand observables ( data_type = "user" and intel(value|uppercase, 'Allowed Users'))
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.blusapphire.io/older-releases/09_casehub/reflex-query-language-rql.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
