Running Federated Search from Splunk

Query's Splunk App displays real–time and historical data in your Splunk console by directly querying from the data sources' APIs when you run your federated search.

Getting Started with Search

For example, run a federated search to fetch events, associated devices, and user information for an IP you are investigating. This will run parallel queries into the platforms connected via Query and bring back results in real-time using the platforms' APIs.

| queryai search="ip = 172.16.16.10"

Note that you have to start with a pipe '|' in front of the app's queryai command, i.e. | queryai

Command Syntax and Examples

Command Syntax

| queryai search=”field = value” platforms="platformA, platformB, platformC" timeout=60

Parameter Description

  • search mandatory parameter that has the federated search condition payload. See the What can you search for understanding searchable entities, objects, and events, and the search syntax.
  • platforms optional parameter that lets you pass the platform alias names you want to query from. Without this parameter, all platforms will be queried. You can review/configure alias names from the 'Connections' page in Query's Console at https://go.query.ai/.`
  • timeout optional numeric parameter specified in seconds. It let's you pass the maximum time you are willing to wait for results. Note that setting this timeout may lead to incomplete results as only the results obtained within that timeframe will be displayed.

Examples

| queryai search="ip = 172.16.16.10"
| queryai search="email = [email protected]" timeout=60
| queryai search="ip = 172.16.16.10" platforms="S3, elastic, sentinel"

What can you search

The search parameter let's you specify what types of data you want to search by, and the conditions you want to put on that search. Start with familiarizing yourself with QDM (Query Data Model) Guide which is based on OCSF. Next, see the full QDM schema at:

📘

OCSF based Query Data Model (QDM)

  • View and browse the QDM at https://schema.query.ai/
  • Browse the events and object at above URL. See details of any event or object, to get a list of attributes you can search on.
  • In your search syntax, use the type's name instead of the display name. So, for example, use domain_info instead of Domain Information.

Regarding the types of data to search by, there are three:

  • Search by QDM Entity
  • Search by QDM Event
  • Search by QDM Object

Search by Entity

The QDM Entities are the common data types of interest seen across QDM Objects and Events, such as an IP Address or a File Hash. You can search by these more basic types to get a result set containing the QDM Events and Objects where these entities were observed. See the guide for QDM Entities. These are the supported QDM entities you can search by:

📘

Entities to Search

email
file_hash
file_name
hostname
ip
mac_address
process_name
resource_id
url
user_agent
username

You can put conditions on the searchable entities to get matched events and objects.

Examples:

| queryai search="ip = 8.8.8.8"
| queryai search="file_hash = b5045d802394f4560280a7404af69263"
| queryai search="email = [email protected]

Search by Event

The QDM Events are the cybersecurity events of interest, such as Authentication Event. See this guide to understand QDM Events.

📘

Events to search

account_change
api_activity
application_lifecycle
authentication
authorize_session
compliance_finding
config_state
data_security_finding
datastore_activity
detection_finding
dns_activity
email_activity
email_delivery_activity
file_activity
file_hosting
http_activity
incident_finding
module_activity
network_activity
patch_state
process_activity
security_finding
user_inventory
vulnerability_finding
web_resources_activity

You can put conditions on the searchable attributes of any class of events to get matched results. Use dots for hierarchically accessing attributes:

| queryai search="security_finding.severity_id = CRITICAL"

📘

Attributes of an event

To know the attributes of any event, lookup that event here and click to see its schema detail: https://schema.query.ai/events.html

You can also do a wildcard search to get a list of events of that class:

| queryai search="security_finding = *"

Search by Object

The QDM Objects are the cybersecurity objects of interest, such as User Object. See the guide for QDM Objects.

📘

Objects to search

actor
agent
data_security
device
domain_info
domain_intelligence
file
file_intelligence
ip_intelligence
threat_intelligence
url_intelligence
user

You can put conditions on the searchable attributes of any class of objects to get matched results. Use dots for hierarchically accessing attributes:

| queryai search="user.email_addr = [email protected]"

📘

Attributes of an object

To know the attributes of any object, lookup that object here and click to see its schema detail: https://schema.query.ai/objects.html

You can also do a wildcard search to get a list of objects of that type:

| queryai search="user = *"

Search Conditions and Operators

Here are some common federated search operators you can use:

📘

Operators

  • = (Equals operator)
  • != (NotEquals operator)
  • *value* (Contains operator)
  • value* (StartsWith operator)
  • *value (EndsWith operator)
  • NOT (Boolean NOT operator)
  • AND/OR (Logical AND and OR operator)
  • IN (IN operator for list of csv values)
  • * (Search all)

Operator Examples

Equality:

| queryai search="ip = 1.1.1.1"  
| queryai search="hostname = My-MacBookPro"

Not Equals:

| queryai search="security_finding.severity_id != LOW"

Starts with: (note the trailing '*')

| queryai search="hostname = mac*"  
| queryai search="user.name = sam*"

Ends with: (note the '*' at the beginning of the value)

| queryai search="hostname = *mac"  
| queryai search="user.name = *anand"

Contains:

| queryai search="hostname = *mac*"  
| queryai search="user.name = *ana*"

Showing all (using * wildcard):: Search for all events of that QDM event class by using the wildcard '*'. Or use '*' in an attribute to get the objects/events that have a value for that attribute.

| queryai search="authentication = *"
| queryai search="authentication.logon_type_id = *"
| queryai search="user.email_addr = *"

ANDing multiple conditions:

| queryai search="user.name=ana AND [email protected]"

Implicit ANDing multiple conditions:

| queryai search="user.name=ana [email protected]"

ORing multiple conditions:

| queryai search="user.name=ana OR [email protected]"

IN :

| queryai search="user.name IN (ana, ava, 'abc xyz', 'abc pqr')"

Negating condition(s) using NOT:

| queryai search="NOT security_finding.severity_id = LOW"
| queryai search="NOT (user.name=ana OR [email protected])"
| queryai search="NOT user.name IN (ana, ava, 'abc xyz', 'abc pqr')"

Left associativity:

In absense of parentheses, the default order of evaluation is left to right.

| queryai search="user.type=System OR [email protected] AND user.name=ava"

So above would be executed as:

| queryai search="(user.type=System OR [email protected]) AND user.name=ava"

Using parentheses to prioritize associativity:

| queryai search="user.type=System OR ([email protected] AND user.name=ava)"

Note that while you can use multiple parentheses to associate separate condition sections, nesting of parentheses is not supported.

Noteworthy Scenarios

About case sensitivity

  • Values are case in-sensitive. (One exception is enum attribute values covered in a later section below.)
  • Entities, events, objects, and their attribute names are case-sensitive

Checking for presence and absence (null or empty) of values

Here is an example of how you search for an attribute to have a non-empty value, for example, searching for users who have a valid value for email_addr:

| queryai search="user.email_addr = *"

Here is how you search for an attribute that does not have a value, i.e. checking for nulls. For example, searching for users whose email_addr is not set:

| queryai search="NOT user.email_addr = *"

Handling spaces, special characters, or reserved keywords in values

Value containing any reserved keywords (like AND, OR, NOT, IN), whitespaces, or special characters (like dots) should be enclosed inside single or double quotes. For example:

| queryai search="security_finding.severity_id = 'INFORMATIONAL'"
| queryai search="user.email_addr='[email protected]'"

Note that quoted values are not supported with StartsWith, EndsWith and Contains operators.

Using dot(.) notation to access attribute hierarchy

As we covered earlier, you can use dot(.) notation to put conditions on a desired attribute in any event or object. For example:

| queryai search="user.devices.domain=xyzdomain"

Note that you access attributes at a depth of max two dots as per the example above, i.e. a.b.c.

Conditions on enum attributes

Enum attributes hold a value from a constant set. For example security_finding.severity_id can only have one of these values: UNKNOWN, INFORMATIONAL, LOW, MEDIUM, HIGH. Refer to the QDM documentation for knowing all the enum attributes and their allowed values. Here are scenarios to be aware of with enum attributes:

  • You can only use equality or inequality conditions, i.e. you cannot put starts with, contains, or ends with style conditions.
  • Use the uppercase equivalent. So instead of Informational, use INFORMATIONAL.
  • While the QDM documentation also lists the internal integral code of enum values, you should only use above uppercase style values vs. the internal codes.

Conditions on certain attribute types

Operators like StartsWith, EndsWith, and Contains are only supported with attributes that hold strings. So, for example, these entities don't support those operations:

  • ip
  • mac_address
  • file_hash

Connection-specific condition limitations

Depending upon the connection, certain conditions may not be supported. For example, threat intelligence platforms like Virus Total don't support StartsWith, EndsWith, and Contains operators on url.

Connection-specific error handling with partial results

Query platform does distributed parallel querying. Any user issued search results in multiple queries run via relevant connectors into your data sources. There can be connection-specific errors or warnings that may cause only a subset of connections to provide partial results. In that scenario, the app will still show you the available results and will also show you specific warnings/errors from the connections that didn't provide results.

Validity of conditions on more than one entities, objects, and events

Only one single entity search

You can only put at most one QDM Entity condition. So no AND / OR / IN / * wildcard operations if your condition is on a QDM Entity. So you cannot do ip=\* . Also, you cannot doip=1.1.1.1 OR ip=1.2.3.4. Instead put the condition on an event or object, so for example, these are valid:

  • device.ip=1.1.1.1 OR device.ip=1.2.3.4
  • network_activity.src_endpoint.ip IN (1.1.1.1, 1.2.3.4)

No ANDing across multiple event/object types

When ANDing multiple conditions, you must use the same object/event types between the conditions. For example user.name = abc AND user.type!=System is valid (conditions are on same object) but user.name = abc AND device.ip=1.1.1.1is not valid (conditions are on different objects). You perhaps meant to use a relationship oriented condition, so you can alternatively do this:user.name = abc AND user.devices.ip=1.1.1.1 (valid because conditions are on same object).

Note that it is valid to do ORing across multiple event/object types. Souser.name = abc OR device.ip=1.1.1.1 is valid if you want to see those two unrelated objects together.

Parsing sub-fields from another value (or from _raw)

In the search results, you will see the top-level OCSF schema objects, events, and attributes. For more details on OCSF, please see Normalization and the OCSF Data Model

In scenarios where you have a value containing further fields, you can use SPL spath command to extract them. For example, the _raw field contains the native platform data mapped from OCSF's raw_data. For any content-specific use-cases, you can extract further fields from that native data by adding the spath pipe operation as ... | spath input=_raw(or simply ... | spath since splunk uses _raw as the default for the input parameter).