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.
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.
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 as
Containsbut 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 value
Between- 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 on
- Items that don't have a specified field may match a
ip NOT InCIDR "192.168.0.0/16"may match on an event not having an
ipfield, pair this with
ip 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 observable
127.0.0.1should have a value of
safeis True, query would look like
Expand 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 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 value
observables|count > 2
|lowercase- Lowercase a string (redundant for
ContainsCISbut can be used for other fields)
|refang- If for some reason the target value has been defanged, think
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 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 command
powershell -encodedCommand SW52b2tlLVdlYlJlcXVlc3QgaHR0cHM6Ly93d3cucmVmbGV4c29hci5jb20=would extract and decode
Invoke-WebRequest https://www.reflexsoar.com. An analyst could then use a query like
command|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 on
|all- Force the condition to match on all items in the array (Can only be used on
|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
ip between "192.168.0.1-10"
|semver- Semantic Versioning, will convert a string to a tuple so it can be compared
process.version|semver < 3.1.0so you can exclude Events from a process with a known bug in it
Comparisons for dates (
whois.last_updated before "2021-11-08 00:00:00"or
whois.last_updated after "7d"or
whois.registration_date after "14d
Nowterm to calculate the current date for previous date comparisons
event.created_at before Now