Skip to content

Commit e506bfa

Browse files
committed
Add info to hasThreatMatch and threatlookup operators
1 parent 1fa7a5a commit e506bfa

File tree

9 files changed

+176
-115
lines changed

9 files changed

+176
-115
lines changed

docs/cse/rules/cse-rules-syntax.md

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -633,41 +633,55 @@ The `hasThreatMatch` Cloud SIEM rules function searches incoming records in Clou
633633
`hasThreatMatch([<fields>], <filters>, <indicators>)`
634634

635635
Parameters:
636-
* `<fields>` is a list of comma separated entity field names. At least one field name is required.
637-
* `<filters>` is a logical expression using indicator attributes. (Allowed are parentheses `()`; `OR` and `AND` boolean operators; and comparison operators `=`, `<`, `>`, `=<`, `=>`, `!=`.)
636+
* `<fields>` is a list of comma-separated [field names](https://github.com/SumoLogic/cloud-siem-content-catalog/blob/master/schema/full_schema.md). At least one field name is required.
637+
* `<filters>` is a logical expression using [indicator attributes](/docs/security/threat-intelligence/upload-formats/#normalized-json-format). Allowed in the filtering are parentheses `()`; `OR` and `AND` boolean operators; and comparison operators `=`, `<`, `>`, `=<`, `=>`, `!=`. <br/>You can filter on the following indicator attributes:
638+
* `actors`
639+
* `confidence`
640+
* `id`
641+
* `indicator`
642+
* `killChain`
643+
* `source`
644+
* `threatType`
645+
* `type`
646+
* `validFrom`
647+
* `validUntil`
638648
* `<indicators>` is an optional case insensitive option that describes how indicators should be matched with regard to their validity. Accepted values are:
639649
* `active_indicators`. Match active indicators only (default).
640650
* `expired_indicators`. Match expired indicators only.
641651
* `all_indicators`. Match all indicators.
642652

643653
**Examples**
644654

645-
* `hasThreatMatch([srcDevice_ip, dstDevice_ip], confidence > 50)`
646-
* `hasThreatMatch([srcDevice_ip], confidence > 50 AND source="FreeTAXII")`
647-
* `hasThreatMatch([srcDevice_ip], source="s1" OR (source="s2" AND confidence > 50))`
648-
* `hasThreatMatch([srcDevice_ip, dstDevice_ip], confidence > 50, expired_indicators)`
655+
* `hasThreatMatch([srcDevice_ip])`
656+
* `hasThreatMatch([srcDevice_ip, dstDevice_ip])`
657+
* `hasThreatMatch([srcDevice_ip], type="ipv4-addr")`
658+
* `hasThreatMatch([srcDevice_ip], confidence > 50)`
659+
* `hasThreatMatch([srcDevice_ip], confidence > 50 AND source="TAXII2Source")`
660+
* `hasThreatMatch([srcDevice_ip], source="s1" OR (source="s2" confidence > 50))`
661+
* `hasThreatMatch([srcDevice_ip], expired_indicators)`
662+
* `hasThreatMatch([srcDevice_ip], confidence > 50, all_indicators)`
649663

650664
#### Best practice
651665

652666
As a best practice, always include filtering to narrow your search to just the types desired (that is, `type=`). This will ensure that your search results are not overly broad.
653667

654668
For example:
655-
* `hasThreatMatch([dstDevice_ip], confidence > 1 AND (type ='ipv4-addr:value' OR type='ipv6-addr:value'))`
656-
* `hasThreatMatch([file_hash_imphash,file_hash_md5,file_hash_pehash,file_hash_ssdeep,file_hash_sha1,file_hash_sha256], confidence > 1 AND type = 'file:hashes')`
657-
* `hasThreatMatch([device_hostname, srcDevice_hostname, dstDevice_hostname, http_hostname, http_referrerHostname, bro_ssl_serverName, bro_ntlm_domainame, bro_ssl_serverName_rootDomain, dns_queryDomain, dns_replyDomain, fromUser_authDomain, http_referrerDomain, http_url_rootDomain, http_url_fqdn], confidence > 1 AND (type='domain-name:value' OR type='url'))`
658-
* `hasThreatMatch([http_url], confidence > 1 AND type='url')`
659-
* `hasThreatMatch([srcDevice_ip], confidence > 1 AND (type ='ipv4-addr:value' OR type='ipv6-addr:value'))`
669+
* `hasThreatMatch([dstDevice_ip], confidence > 1 AND (type="ipv4-addr" OR type="ipv6-addr"))`
670+
* `hasThreatMatch([file_hash_imphash, file_hash_md5, file_hash_pehash, file_hash_ssdeep, file_hash_sha1, file_hash_sha256], confidence > 1 AND type="file:hashes")`
671+
* `hasThreatMatch([device_hostname, srcDevice_hostname, dstDevice_hostname, http_hostname, http_referrerHostname, bro_ssl_serverName, bro_ntlm_domainame, bro_ssl_serverName_rootDomain, dns_queryDomain, dns_replyDomain, fromUser_authDomain, http_referrerDomain, http_url_rootDomain, http_url_fqdn], confidence > 1 AND (type="domain-name" OR type="url"))`
672+
* `hasThreatMatch([http_url], confidence > 1 AND type="url")`
673+
* `hasThreatMatch([srcDevice_ip], confidence > 1 AND (type="ipv4-addr" OR type="ipv6-addr"))`
660674

661675
Following are the standard indicator types you can filter on:
662-
* `domain-name:value`. Domain name.
663-
* `email-addr:value`. Email address.
676+
* `domain-name`. Domain name.
677+
* `email-addr`. Email address.
664678
* `file:hashes`. File hash.
665679
* `file:name`. File name.
666-
* `ipv4-addr:value`. IPv4 IP address.
667-
* `ipv6-addr:value`. IPv6 IP address.
668-
* `mac-addr:value`. Mac address name.
680+
* `ipv4-addr`. IPv4 IP address.
681+
* `ipv6-addr`. IPv6 IP address.
682+
* `mac-addr`. Mac address name.
669683
* `process:name`. Process name.
670-
* `url:value`. URL.
684+
* `url`. URL.
671685
* `user-account:user-id`. User ID.
672686
* `user-account:login`. Login name.
673687

docs/integrations/amazon-aws/waf.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ _sourceCategory=AWS/WAF {{client_ip}}
6565
_sourceCategory=AWS/WAF {{client_ip}}
6666
| parse "\"httpMethod\":\"*\"," as httpMethod,"\"httpVersion\":\"*\"," as httpVersion,"\"uri\":\"*\"," as uri, "{\"clientIp\":\"*\",\"country\":\"*\"" as clientIp,country, "\"action\":\"*\"" as action, "\"matchingNonTerminatingRules\":[*]" as matchingNonTerminatingRules, "\"rateBasedRuleList\":[*]" as rateBasedRuleList, "\"ruleGroupList\":[*]" as ruleGroupList, "\"httpSourceId\":\"*\"" as httpSourceId, "\"httpSourceName\":\"*\"" as httpSourceName, "\"terminatingRuleType\":\"*\"" as terminatingRuleType, "\"terminatingRuleId\":\"*\"" as terminatingRuleId, "\"webaclId\":\"*\"" as webaclId nodrop
6767
| threatlookup singleIndicator clientip
68-
| where (_threatlookup.type="ipv4-addr:value" or _threatlookup.type="ipv6-addr:value") and !isNull(_threatlookup.confidence)
68+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
6969
```
7070
-->
7171

docs/integrations/security-threat-detection/threat-intel-quick-analysis.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ Use [Field Extraction Rules (FER)](/docs/manage/field-extractions/create-field-e
111111
```
112112
| threatlookup singleIndicator src_ip
113113
| parse regex field=%"_threatlookup.fields" "labels.[^.]+.name\":\"(?<label_name>[^\"]+)\"" multi
114-
| where (_threatlookup.type="ipv4-addr:value" or _threatlookup.type="ipv6-addr:value") and !isNull(_threatlookup.confidence)
114+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
115115
| if (isEmpty(_threatlookup.actors), "Unassigned", _threatlookup.actors) as Actor
116116
| count as threat_count by src_ip, malicious_confidence, Actor, _source, label_name
117117
| sort by threat_count
@@ -138,7 +138,7 @@ Use scheduled views with the threat lookup operator to find threats. Scheduled v
138138
_sourceCategory=cylance
139139
| threatlookup singleIndicator src_ip
140140
| parse regex field=%"_threatlookup.fields" "labels.[^.]+.name\":\"(?<label_name>[^\"]+)\"" multi
141-
| where (_threatlookup.type="ipv4-addr:value" or _threatlookup.type="ipv6-addr:value") and !isNull(_threatlookup.confidence)
141+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
142142
| if (isEmpty(_threatlookup.actors), "Unassigned", _threatlookup.actors) as Actor
143143
| lookup latitude, longitude, country_code, country_name, region, city, postal_code, area_code, metro_code from geo://default on ip = src_ip
144144
| count as threat_count by src_ip, malicious_confidence, Actor, _source, label_name, city, country_name, raw
@@ -183,7 +183,7 @@ Yes, you can customize the query in the app. For example:
183183
_sourceCategory= */*/FIREWALL or _sourceCategory=*/*/LB or _sourceCategory=*/*/ROUTER or _sourceCategory=*/*/WINDOWS or _sourceCategory=*/*/SERVER
184184
| where Your_IP != "0.0.0.0" and Your_IP != "127.0.0.1"
185185
| threatlookup singleIndicator Your_IP
186-
| where (_threatlookup.type="ipv4-addr:value" or _threatlookup.type="ipv6-addr:value") and !isNull(_threatlookup.confidence)
186+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
187187
| if (isEmpty(_threatlookup.actors), "Unassigned", _threatlookup.actors) as Actor
188188
| count by Actor
189189
```
@@ -207,7 +207,7 @@ _sourceCategory= */*/FIREWALL or _sourceCategory=*/*/LB or _sourceCategory=*/*/R
207207
| where ip_address != "0.0.0.0" and ip_address != "127.0.0.1"
208208
| threatlookup singleIndicator ip_address
209209
| parse regex field=%"_threatlookup.fields" "labels.[^.]+.name\":\"(?<label_name>[^\"]+)\"" multi
210-
| where (_threatlookup.type="ipv4-addr:value" or _threatlookup.type="ipv6-addr:value") and !isNull(_threatlookup.confidence)
210+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
211211
| where !(label_name matches "*TorProxy*")
212212
| if (isEmpty(_threatlookup.actors), "Unassigned", _threatlookup.actors) as Actor
213213
| if (_threatlookup.confidence >= 85, "high", if (_threatlookup.confidence >= 50, "medium", if (_threatlookup.confidence >= 15, "low", if (_threatlookup.confidence >= 0, "unverified", "Unknown")))) as malicious_confidence

docs/observability/aws/integrations/aws-dynamodb.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ _sourceCategory=Labs/AWS/DynamoDB account=* namespace=* "\"eventSource\":\"dynam
7777
| where ip_address != "0.0.0.0" and ip_address != "127.0.0.1"
7878
| count as ip_count by ip_address
7979
| threatlookup singleIndicator ip_address
80-
| where (_threatlookup.type="ipv4-addr:value" or _threatlookup.type="ipv6-addr:value") and !isNull(_threatlookup.confidence)
80+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
8181
| if (isEmpty(_threatlookup.actors), "Unassigned", _threatlookup.actors) as Actor
8282
| sum (ip_count) as threat_count
8383
```

docs/search/search-query-language/search-operators/threatlookup.md

Lines changed: 120 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ title: threatlookup Search Operator
44
sidebar_label: threatlookup
55
---
66

7-
The `threatlookup` search operator allows you to search logs for matches in [threat intelligence indicators](/docs/security/threat-intelligence/threat-intelligence-indicators/), providing security analytics to help you to detect threats in your environment.
7+
The `threatlookup` search operator allows you to search logs for matches in [threat intelligence indicators](/docs/security/threat-intelligence/threat-intelligence-indicators/), providing security analytics to help you to detect threats in your environment.
88

99
:::note
1010
You can also use the [`threatip`](/docs/search/search-query-language/search-operators/threatip/) search operator to search CrowdStrike's threat intelligence data based on IP addresses.
1111
:::
1212

13-
### Syntax
13+
## Syntax
1414

1515
```
16-
threatlookup [singleIndicator] [source="<source_value>"] [include="<all|active|expired>"] <indicator_value_field> [,<optional_indicator_value_field_2>, …]
16+
threatlookup [singleIndicator] [source="<source_value>"] [include="<all|active|expired>"] <indicator> [,<optional_indicator>, …]
1717
```
1818

1919
Where:
@@ -29,24 +29,37 @@ Where:
2929

3030
* `source` is the source to search for the threat intelligence indicator. If `source` is not specified, all sources are searched.
3131
* `include` includes either all, only active, or only expired threat intelligence indicators. If `include` is not specified, only active matching indicators are returned.
32-
* `<indicator_value_field>` is the indicator to look up.
33-
* `<optional_indicator_value_field>` is used to add more indicators to look up.
34-
35-
#### Response fields
36-
* confidence
37-
* fields
38-
* imported
39-
* indicator
40-
* valid_from
41-
* valid_until
42-
* source
43-
* threat_type
44-
* type
45-
* updated
46-
* num_match (if `singleIndicator` is used)
47-
48-
### Examples
49-
32+
* `<indicator>` is the [indicator](/docs/security/threat-intelligence/upload-formats/#normalized-json-format) to look up for a [field name](https://github.com/SumoLogic/cloud-siem-content-catalog/blob/master/schema/full_schema.md). At least one field name is required. `<optional_indicator>` is used to add more indicators to look up. Allowed in the filtering are parentheses `()`; `OR` and `AND` boolean operators; and comparison operators `=`, `<`, `>`, `=<`, `=>`, `!=`. <br/>You can filter on the following indicator attributes:
33+
* `actors`
34+
* `confidence`
35+
* `id`
36+
* `indicator`
37+
* `killChain`
38+
* `source`
39+
* `threatType`
40+
* `type`
41+
* `validFrom`
42+
* `validUntil`
43+
44+
### Response fields
45+
46+
Query responses return the following fields:
47+
* `confidence`
48+
* `fields`
49+
* `imported`
50+
* `indicator`
51+
* `valid_from`
52+
* `valid_until`
53+
* `source`
54+
* `threat_type`
55+
* `type`
56+
* `updated`
57+
* `num_match` (if `singleIndicator` is used)
58+
59+
## Examples
60+
61+
### Simple examples
62+
5063
```
5164
_index=sec_record*
5265
| threatlookup srcDevice_ip
@@ -63,7 +76,7 @@ _index=sec_record*
6376
```
6477
```
6578
_index=sec_record*
66-
| threatlookup source="s_CrowdStrike" srcDevice_ip
79+
| threatlookup source="mysource" srcDevice_ip
6780
| where _threatlookup.confidence > 50
6881
| timeslice 1h
6982
| count by _timeslice
@@ -77,19 +90,99 @@ _index=sec_record*
7790
```
7891
```
7992
_index=sec_record*
80-
| threatlookup source="s_CrowdStrike" dstDevice_ip, srcDevice_ip
93+
| threatlookup source="mysource" dstDevice_ip, srcDevice_ip
8194
| where _threatlookup.confidence > 50
8295
| timeslice 1h
8396
| count by _timeslice
8497
```
8598
```
8699
_index=sec_record*
87-
| threatlookup source="s_CrowdStrike" include="active" dstDevice_ip, srcDevice_ip
100+
| threatlookup source="mysource" include="active" dstDevice_ip, srcDevice_ip
88101
| where _threatlookup.confidence > 50
89102
| timeslice 1h
90103
| count by _timeslice
91104
```
92-
### Format timestamp results
105+
106+
### Complex examples
107+
108+
```sql title="Client IP threat info"
109+
_sourceCategory=AWS/WAF {{client_ip}}
110+
| parse "\"httpMethod\":\"*\"," as httpMethod,"\"httpVersion\":\"*\"," as httpVersion,"\"uri\":\"*\"," as uri, "{\"clientIp\":\"*\",\"country\":\"*\"" as clientIp,country, "\"action\":\"*\"" as action, "\"matchingNonTerminatingRules\":[*]" as matchingNonTerminatingRules, "\"rateBasedRuleList\":[*]" as rateBasedRuleList, "\"ruleGroupList\":[*]" as ruleGroupList, "\"httpSourceId\":\"*\"" as httpSourceId, "\"httpSourceName\":\"*\"" as httpSourceName, "\"terminatingRuleType\":\"*\"" as terminatingRuleType, "\"terminatingRuleId\":\"*\"" as terminatingRuleId, "\"webaclId\":\"*\"" as webaclId nodrop
111+
| threatlookup singleIndicator clientip
112+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
113+
```
114+
115+
```sql title="All IP threat count"
116+
_sourceCategory=Labs/AWS/DynamoDB account=* namespace=* "\"eventSource\":\"dynamodb.amazonaws.com\""
117+
| json "eventName", "awsRegion", "requestParameters.tableName", "sourceIPAddress", "userIdentity.userName" as event_name, Region, entity, ip_address, user
118+
| where Region matches "*" and tolowercase(entity) matches "*"
119+
| where ip_address != "0.0.0.0" and ip_address != "127.0.0.1"
120+
| count as ip_count by ip_address
121+
| threatlookup singleIndicator ip_address
122+
| where (_threatlookup.type="ipv4-addr" or _threatlookup.type="ipv6-addr") and !isNull(_threatlookup.confidence)
123+
| if (isEmpty(_threatlookup.actors), "Unassigned", _threatlookup.actors) as Actor
124+
| sum (ip_count) as threat_count
125+
```
126+
127+
```sql title="Use threatlookup in a subquery"
128+
_sourceCategory=weblogs
129+
[subquery:_sourceCategory="Labs/SecDemo/guardduty" "EC2 Instance" "communicating on an unusual server port 22"
130+
| json field=_raw "service.action.networkConnectionAction.remoteIpDetails" as remoteIpDetails
131+
| json field=_raw "service.action.networkConnectionAction.connectionDirection" as connectionDirection
132+
| where connectionDirection = "OUTBOUND"
133+
| json field=remoteipdetails "ipAddressV4" as src_ip
134+
| threatlookup singleIndicator threat| if (_threatlookup.confidence >= 85, "high", if (_threatlookup.confidence >= 50, "medium", if (_threatlookup.confidence >= 15, "low", if (_threatlookup.confidence >= 0, "unverified", "Unknown")))) as malicious_confidence
135+
| where malicious_confidence = "high"
136+
| compose src_ip]
137+
```
138+
139+
<!-- Add this after sumo://threat/cs is replaced by threatlookup":
140+
141+
### Threatlookup queries in dashboards
142+
143+
The `threatlookup` search operator is used for queries in some dashboards, including dashboards in the [Threat Intel Quick Analysis app](/docs/integrations/security-threat-detection/threat-intel-quick-analysis/). These queries provide great examples of how to use the operator.
144+
145+
To see `threatlookup` used in a query:
146+
1. Open the Threat Intel Quick Analysis app.
147+
1. Navigate to a dashboard, such as **Overview**.
148+
1. Click the three-dot kebab in the upper-right corner of the dashboard panel.
149+
1. Select **Open in Log Search**.
150+
1. Look for `threatlookup` used in the query.
151+
152+
For example, here is the query used for the **Threat Count** panel in the **Threat Intel Quick Analysis - IP** dashboard:
153+
154+
```
155+
_sourceCategory=<source-category-name>
156+
| parse regex "(?<ip_address>\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
157+
| where ip_address != "0.0.0.0" and ip_address != "127.0.0.1"
158+
| count as ip_count by ip_address
159+
160+
| threatlookup singleIndicator ip_address
161+
162+
// normalize confidence level to a string
163+
| if (_threatlookup.confidence >= 85, "high", if (_threatlookup.confidence >= 50, "medium", if (_threatlookup.confidence >= 15, "low", if (_threatlookup.confidence >= 0, "unverified", "unknown")))) as threat_confidence
164+
165+
// filter for threat confidence
166+
| where  threat_confidence matches "*"
167+
168+
//rename to match threat_<foo> convention
169+
| %"_threatlookup.actors" as threat_actors
170+
| %"_threatlookup.type" as type
171+
| %"_threatlookup.threat_type" as threat_type
172+
173+
//convert threat valid from to human readable time
174+
| toLong(%"_threatlookup.valid_from" * 1000) as %"_threatlookup.valid_from"
175+
| formatDate(%"_threatlookup.valid_from", "MM-dd-yyyy") as threat_valid_from
176+
177+
| where type matches "ipv4-addr*" and !isNull(threat_confidence)
178+
179+
| if (isEmpty(threat_actors), "Unassigned", threat_actors) as threat_actors
180+
181+
|sum (ip_count) as threat_count
182+
```
183+
-->
184+
185+
## Format timestamp results
93186

94187
Timestamps for the following response fields return results as an integer because they use Unix time (also known as *epoch time*):
95188
* `_threatlookup.imported`
@@ -107,7 +200,7 @@ _index=sec_record*
107200

108201
<!-- For threat intel. Add this back once we have support for the cat search operator:
109202
110-
#### Run threatlookup with the cat search operator
203+
## Run threatlookup with the cat search operator
111204
112205
You can run the `threatlookup` search operator with the [`cat` search operator](/docs/search/search-query-language/search-operators/cat/) by using the `sumo://threat-intel` path. This lets you search the entire store of threat intelligence indicators, or just a portion. For example:
113206
```
@@ -124,6 +217,6 @@ cat sumo://threat-intel | formatDate(toLong(_threatlookup.valid_until), "yyyy-MM
124217
```
125218
126219
:::note
127-
You cannot use the cat search operator with the `s_CrowdStrike` source.
220+
You cannot use the cat search operator with the `_sumo_global_feed_cs` source.
128221
:::
129222
-->

docs/search/subqueries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ _sourceCategory=search "error while retrying to deploy index"
376376

377377
### Check Malicious Activity with Subquery
378378

379-
The following search allows a security analyst how to track logs related to a malicious IP address that was flagged by Amazon GuardDuty and also by a CrowdStrike Threat feed. The subquery is returning the field `src_ip` with the IP addresses deemed as threats to the parent query, note that the keywords option was not used so the parent query will expect a field src_ip to exist. The results will include logs from the weblogs sourceCategory that have a `src_ip` value that was deemed a threat from the subquery.
379+
The following search allows a security analyst to track logs related to a malicious IP address that was flagged by Amazon GuardDuty and also by a CrowdStrike Threat feed. The subquery is returning the field `src_ip` with the IP addresses deemed as threats to the parent query, note that the keywords option was not used so the parent query will expect a field src_ip to exist. The results will include logs from the weblogs sourceCategory that have a `src_ip` value that was deemed a threat from the subquery.
380380

381381
```sql
382382
_sourceCategory=weblogs

0 commit comments

Comments
 (0)