Reflex Query Language (RQL)
Reflex Query Language (RQL) is a query language designed to ask Reflex questions about Events. RQL is used when creating certain items in Reflex, such as 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.*
raw_log allows accessing any field from a raw log. Click for more details.
The use of **raw_log** allows accessing anything in fields within the raw log to use with RQL. Consider the below event JSON.Supported Expressions
The following Expressions are used to compare target field data to intended data:
RegExp
- The item has a value that matches a regular expression e.g.title RegExp "^Event.*"
In
- The item has a value in a list of values e.g.observables.tags.name in ["malware"]
Contains
- The target value contains a specific string e.g.description Contains "malware"
ContainsCIS
- Same asContains
but will make the target value and checked value the same case=|eq|Eq
- Equal to (strings or numbers)!=|ne|Ne|NE
- Not equal to (strings or numbers)>|gt
- Greater than (> or gt)>=|gte
- Greater than or equal to (>= or gte)<|lt
- Less than (< or lt)<=|lte
- Less than or equal to (<= or lte)InCIDR
- The IP address is in a specific CIDR network e.g.192.168.1.1 InCIDR 192.168.0.0/16
Is
- Use for boolean operations like "Is True" e.g.ioc Is True
Exists
- The field exists at all, useful if you don't care what the target valueBetween
- The item has a value between a given range e.g.tlp Between "1,3"
StartsWith
- The item has a value that starts with a certain string e.g.url StartsWith "https"
EndsWith
- The item has a value that ends with a certain string e.g.domain EndsWith ".tk"
Not
- The expression within this block should not match e.g.title Not Eq "Suspicious DNS Query"
(Can only be used oneq
,in
,InCIDR
,contains
,between
ANDregexp
)- 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 anip
field, pair this withip exists AND ip NOT InCIDR "192.168.0.0/16"
Expand
- When you want two conditions on a nested object to be true use an each statement. Example, the observable127.0.0.1
should have a value of127.0.0.1
andsafe
is True, query would look likeExpand observables (value = "127.0.0.1" and safe Is True)
.Intel|Threat
- Allows RQL to check the value of a field against a Reflex Intel List (threat lists)
Mutators
Mutators take a field and perform an extra operation on it to make it digestible by the down stream 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 valueobservables|count > 2
|lowercase
- Lowercase a string (redundant forContainsCIS
but can be used for other fields)|refang
- If for some reason the target value has been defanged, thinkhXXps[:]//
instead ofhttps://
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 with in 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. and event contains a commandpowershell -encodedCommand SW52b2tlLVdlYlJlcXVlc3QgaHR0cHM6Ly93d3cucmVmbGV4c29hci5jb20=
would extract and decodeSW52b2tlLVdlYlJlcXVlc3QgaHR0cHM6Ly93d3cucmVmbGV4c29hci5jb20=
toInvoke-WebRequest https://www.reflexsoar.com
. An analyst could then use a query likecommand|b64extract Contains "reflexsoar.com"
|urldecode
- Unescapes an escaped URL so that direct comparisons can be made|any
- Force the following condition to match on any item in the array (Can only be used onContains
andIn
expressions)|all
- Force the condition to match on all items in the array (Can only be used onContains
andIn
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 in to an array|geo_country
- Returns the ISO Code for the country an IP resides in|geo_continent
- Returns the ISO Code for the contient an IP resides in|geo_timezone
- Returns the timezone an IP resides in|reverse_lookup
- Takes an IP and attempts to return the associated host name|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
Features in Development
Below are features that are currently in development for Reflex and will be pushed to production sometime in the near future.
- Support for IP ranges not using CIDR
-
Example:
ip between "192.168.0.1-10"
-
|semver
- Semantic Versioning, will convert a string to a tuple so it can be compared -
Example:
process.version|semver < 3.1.0
so you can exclude Events from a process with a known bug in it -
Comparisons for dates (
between
,=
,before (<)
,after (>)
) -
Example:
whois.last_updated before "2021-11-08 00:00:00"
orwhois.last_updated after "7d"
orwhois.registration_date after "14d
-
Now
term to calculate the current date for previous date comparisons - Example:
event.created_at before Now