Labeling Rules¶
On this page you can learn about the various labeling rules available with Cyber Range Kyoushi Dataset.
DSL Query Rule (elasticsearch.query
)¶
Applies labels based on a simple Elasticsearch DSL query.
Examples:
- type: elasticsearch.query
id: attacker.foothold.vpn.ip
labels:
- attacker_vpn
- foothold
description: >-
This rule applies the labels to all openvpn log rows that have
the attacker server as source ip and are within the foothold phase.
index:
- openvpn-vpn
filter:
range:
"@timestamp":
# foothold phase start
gte: "2021-03-23 20:31:00+00:00"
# foothold phase stop
lte: "2021-03-23 21:13:52+00:00"
query:
- match:
source.ip: '192.42.0.255'
description: str
pydantic-field
¶
An optional description for the rule
exclude: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
¶
Similar to filters, but used to exclude results
filter_: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
¶
The filter/s to limit queried to documents to only those that match the filters
id_: str
pydantic-field
required
¶
The unique rule id
index: Union[List[str], str]
pydantic-field
¶
The indices to query (by default prefixed with the dataset name)
indices_prefix_dataset: bool
pydantic-field
¶
If set to true the <DATASET.name>-
is automatically prefixed to each pattern. This is a convenience setting as per default all dataset indices start with this prefix.
labels: str
pydantic-field
required
¶
The list of labels to apply to log lines matching this rule
query: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
required
¶
The query/s to use for identifying log lines to apply the tags to.
type_field: str
pydantic-field
required
¶
The rule type as passed in from the config
EQL Sequence Rule (elasticsearch.sequence
)¶
Applies labels to a sequence of log events defined by an EQL query.
This labeling rule is defined as an EQL query. Using this syntax it is possible to define a sequence of related events and retrieve them. All events part of retrieved sequences are then labeled.
Examples:
- type: elasticsearch.sequence
id: attacker.webshell.upload.seq
labels: [webshell_upload]
description: >-
This rule labels the web shell upload step by matching the 3 step sequence
within the foothold phase.
index:
- apache_access-intranet_server
# since we do these requests very fast
# we need the line number as tie breaker
tiebreaker_field: log.file.line
by: source.address
max_span: 2m
filter:
range:
"@timestamp":
# foothold phase start
gte: "2021-03-23 20:31:00+00:00"
# foothold phase stop
lte: "2021-03-23 21:13:52+00:00"
sequences:
- '[ apache where event.action == "access" and url.original == "/" ]'
- '[ apache where event.action == "access" and url.original == "/?p=5" ]'
- '[ apache where event.action == "access" and http.request.method == "POST" and url.original == "/wp-admin/admin-ajax.php" ]'
batch_size: int
pydantic-field
¶
The amount of sequences to update with each batch. Cannot be bigger than max_result_window
by: Union[List[str], str]
pydantic-field
¶
Optional global sequence by fields
description: str
pydantic-field
¶
An optional description for the rule
event_category_field: str
pydantic-field
¶
The field used to categories events
filter_: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
¶
The filter/s to limit queried to documents to only those that match the filters
id_: str
pydantic-field
required
¶
The unique rule id
index: Union[List[str], str]
pydantic-field
¶
The indices to query (by default prefixed with the dataset name)
indices_prefix_dataset: bool
pydantic-field
¶
If set to true the <DATASET.name>-
is automatically prefixed to each pattern. This is a convenience setting as per default all dataset indices start with this prefix.
labels: str
pydantic-field
required
¶
The list of labels to apply to log lines matching this rule
max_result_window: int
pydantic-field
¶
The max result window allowed on the elasticsearch instance
max_span: str
pydantic-field
¶
Optional max time span in which a sequence must occur to be considered a match
sequences: str
pydantic-field
required
¶
Event sequences to search. Must contain at least two events.
tiebreaker_field: str
pydantic-field
¶
(Optional, string) Field used to sort hits with the same timestamp in ascending order.
timestamp_field: str
pydantic-field
¶
The field containing the event timestamp
type_field: str
pydantic-field
required
¶
The rule type as passed in from the config
until: str
pydantic-field
¶
Optional until event marking the end of valid sequences. The until event will not be labeled.
DSL Sub Query Rule (elasticsearch.sub_query
)¶
Labeling rule that labels the results of multiple sub queries.
This labeling rule first executes a base query to retrieve information. It then renders and executes a templated sub query for each row retrieved from the base query. The result rows of these dynamically generated sub queries are then labled.
Note
The sub query uses Jinja2 syntax for templating. The information retrieved
by the base query can be accessed through the HIT
variable.
Examples:
- type: elasticsearch.sub_query
id: attacker.foothold.apache.access_dropped
labels:
- attacker_http
- foothold
description: >-
This rule tries to match attacker requests that we where unable to
match to a labeled response with access log entries. Such cases can
happen if the corresponding response gets lost in the network or
otherwise is not sent.
index:
- pcap-attacker_0
# obligatory match all
query:
- term:
destination.ip: "172.16.0.217"
filter:
- term:
event.category: http
- term:
event.action: request
# we are looking for requests that have not been marked as attacker http yet
# most likely they did not have a matching response due to some network error
# or timeout
- bool:
must_not:
- script:
script:
id: test_dataset_kyoushi_label_filter
params:
labels: [attacker_http]
sub_query:
index:
- apache_access-intranet_server
query:
- term:
url.full: "{{ HIT.url.full }}"
- term:
source.address: "172.16.100.151"
filter:
- range:
"@timestamp":
# the access log entry should be after the request, but since the access log
# does not have microseconds we drop them here as well
gte: "{{ (HIT['@timestamp'] | as_datetime).replace(microsecond=0) }}"
# the type of error we are looking for should create an access log entry almost immediately
# se we keep the time frame short
lte: "{{ ( HIT['@timestamp'] | as_datetime).replace(microsecond=0) + timedelta(seconds=1) }}"
description: str
pydantic-field
¶
An optional description for the rule
exclude: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
¶
Similar to filters, but used to exclude results
filter_: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
¶
The filter/s to limit queried to documents to only those that match the filters
id_: str
pydantic-field
required
¶
The unique rule id
index: Union[List[str], str]
pydantic-field
¶
The indices to query (by default prefixed with the dataset name)
indices_prefix_dataset: bool
pydantic-field
¶
If set to true the <DATASET.name>-
is automatically prefixed to each pattern. This is a convenience setting as per default all dataset indices start with this prefix.
labels: str
pydantic-field
required
¶
The list of labels to apply to log lines matching this rule
query: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
required
¶
The query/s to use for identifying log lines to apply the tags to.
sub_query: QueryBase
pydantic-field
required
¶
The templated sub query to use to apply the labels. Executed for each hit of the parent query.
type_field: str
pydantic-field
required
¶
The rule type as passed in from the config
DSL Parent Query Rule (elasticsearch.parent_query
)¶
Applies the labels to all rows of a base query for which a parent query returns results.
This labeling rule first executes a base query to retrieve rows we might want to apply labels to. It then renders and executes a templated parent query for each retrieved row. The parent queries are then used to indicate if the initial result row should be labeled or not. By default result rows of the base query are labeled if the corresponding parent query returns at leas one row. It is possible to configure this minimum number e.g., to require at least two results.
Note
The sub query uses Jinja2 syntax for templating. The information retrieved
by the base query can be accessed through the HIT
variable.
Examples:
- type: elasticsearch.parent_query
id: attacker.foothold.apache.error_access
labels:
- attacker_http
- foothold
description: >-
This rule looks for unlabeled error messages resulting from VPN server
traffic within the attack time and tries to match it to an already labeled
access log row.
index:
- apache_error-intranet_server
query:
match:
source.address: "172.16.100.151"
filter:
# use script query to match only entries that
# are not already tagged for as attacker http in the foothold phase
- bool:
must_not:
- script:
script:
id: test_dataset_kyoushi_label_filter
params:
labels: [attacker_http]
parent_query:
index:
- apache_access-intranet_server
query:
- term:
url.full: "{{ HIT.url.full }}"
- term:
source.address: "{{ HIT.source.address }}"
# we are looking for parents that are labeled as attacker http
- bool:
must:
- script:
script:
id: test_dataset_kyoushi_label_filter
params:
labels: [attacker_http]
filter:
- range:
# parent must be within +-1s of potential child
"@timestamp":
gte: "{{ (HIT['@timestamp'] | as_datetime) - timedelta(seconds=1) }}"
lte: "{{ ( HIT['@timestamp'] | as_datetime) + timedelta(seconds=1) }}"
description: str
pydantic-field
¶
An optional description for the rule
exclude: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
¶
Similar to filters, but used to exclude results
filter_: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
¶
The filter/s to limit queried to documents to only those that match the filters
id_: str
pydantic-field
required
¶
The unique rule id
index: Union[List[str], str]
pydantic-field
¶
The indices to query (by default prefixed with the dataset name)
indices_prefix_dataset: bool
pydantic-field
¶
If set to true the <DATASET.name>-
is automatically prefixed to each pattern. This is a convenience setting as per default all dataset indices start with this prefix.
labels: str
pydantic-field
required
¶
The list of labels to apply to log lines matching this rule
max_result_window: int
pydantic-field
¶
The max result window allowed on the elasticsearch instance
min_match: int
pydantic-field
¶
The minimum number of parent matches needed for the main query to be labeled.
parent_query: QueryBase
pydantic-field
required
¶
The templated parent query to check if the labels should be applied to a query hit.
query: Union[List[Dict[str, Any]], Dict[str, Any]]
pydantic-field
required
¶
The query/s to use for identifying log lines to apply the tags to.
type_field: str
pydantic-field
required
¶
The rule type as passed in from the config
check_parent(self, parent_query, min_match, dataset_config, es)
¶
Executes a parent query and returns if there were enough result rows.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
parent_query |
QueryBase |
The parent query to execute |
required |
min_match |
int |
The minimum number of result rows required |
required |
dataset_config |
DatasetConfig |
The dataset configuration |
required |
es |
Elasticsearch |
The elasticsearch client object |
required |
Returns:
Type | Description |
---|---|
bool |
|