Replies: 5 comments 4 replies
|
I would like to bump this topic and add a few things from myself. RationaleI believe we have a good reason to add array support to sigma. Many native log sources use arrays - including (but definitely not limited to):
It's worth to note that only Azure would not benefit from the Further Enhancement feature (proposed by @humpalum) since it does not appear to use JSON objects inside arrays. Additionally, note that sigma does already have rules for most of the log sources from the list above. Additional observationsI am not sure how sigma handles nested fields at the moment. We do have some rules that use Proposed solutionThe proposed solution roughly aligns with what @humpalum suggests, but I propose different syntax (for the sake of discussion). The format below is somewhat inspired by keywords search Let us consider the example by @humpalum once more: {
"message": "Some Message",
"process": "Some Process",
"connections": [
{"protocol":"TCP","ip":"123.1.1.1"},
{"protocol":"TCP","ip":"123.1.2.2"},
{"protocol":"UDP","ip":"123.3.3.3"}
]
}A rule that matches events with such schema if it contains any TCP connection with IP address "123.1.1.1" would look like this: selection:
matchNode:
connections[any].protocol: "TCP"
connections[any].ip: "123.1.1.1"which should be interpreted as a 'flattened' version of @humpalum's syntax. Consequently, the rule below selection:
matchNode:
connections[any].protocol: "TCP"
connections[all].ip: "123.1.1.1"would mean **match events where any connection is a TCP, but all of them have IP "123.1.1.1". This syntax can be nested easily. Let's consider another example: {
"configName": "Some Name",
"rules": [
{"type":"allow", "ip":["123.1.1.1", "123.1.1.2", "123.1.1.3"]},
{"type":"allow", "ip":["123.1.2.2"]},
{"type":"block","ip":["124.3.3.3"]}
]
}And a rule selection:
matchNode:
rules[any].type: "allow"
rules[any].ip[all]|startswith: "123.1.1"
rules[all].ip[all]|startswith: "123"This time, the rule matches any events where all rule ips start with "123". Additionally there must be at least one rule object
Pros and ConsI believe this syntax might be a bit more consistent with current sigma format. It would also not increase the depth of rules much. It also allows fine grained control over how nested logs should be matched. On the flip side it might be less straightforward and more verbose than @humpalum's solution. Regardless of the format, I would really embrace any official support for nested formats. |
|
Following up here (and on a side conversation with @thomaspatzke on Discord): I've written a full SEP that synthesizes the proposals in this thread, SEP: Array Matching in Sigma #212. The core idea is to treat "array matching" as two separate problems:
The proposal:
The deciding factor was convertibility: the block lowers to a single canonical primitive per backend (Elastic Open questions I'd value feedback on: empty/missing semantics for I'm building a reference implementation in rsigma (evaluator + converter) to validate the semantics across backends and feed findings back here. |
|
Just wanted to mention that we ran into the same problem at AlphaSOC and ended up introducing "recursive array matching": https://docs.alphasoc.com/detections_and_findings/sigma/supported_features/arrays/ One of our main concerns was preserving bindings between fields belonging to the same array element. It’s great to see that @mostafa's proposal explicitly addresses this. One aspect we found valuable in our approach is that array elements are evaluated by recursively applying the Sigma detection model to each element. In other words, array elements behave like "mini-events" and existing Sigma concepts can be reused inside arrays. This allows for the same rule complexity as the base object, including negations and more complex conditions on specific fields. Apart from introducing a single arrayAll modifier, we largely achieved this by reusing existing Sigma semantics rather than creating a separate array matching model. For example, assuming log entry with array of connections, “is there a non-TCP connection in 123.1.0.0/16?” can be expressed as: We could imagine adding syntax sugar on top of this in the future (potentially converging towards something similar to other proposals), but we wanted to establish a fully expressive foundation first. One thing we’re currently missing is support for matching specific indices. So far we haven’t seen detections where a particular array position has special meaning, but it’s certainly an interesting use case and worth considering. Sharing this as another approach to the problem that exists in the wild. I’m glad Sigma is getting closer to supporting arrays, as this is clearly something users need. |
|
Quick update on the array-matching SEP (#212) as suggested by @frack113: I added a Worked Examples section that pairs real-world log entries with rules that match them, drawn from AWS CloudTrail, Kubernetes audit, Okta system log, Elastic ECS, and network telemetry. Between these and the Problem Statement logs they cover every construct: implicit any-member, the basic and extended object-scope blocks, all four quantifiers, and positional indexing (including negative). To keep logs and rules traceable, each example log is labeled |
|
(The SEP is being constantly updated to reflect all perspectives and use-cases. Therefore, let's continue talking on the SEP issue itself, so that the history is preserved in a single place.) |
Uh oh!
There was an error while loading. Please reload this page.
Matching Arrays with sigma
Problem
Sigma currently lacks the capability to match values within arrays in log events. This limitation restricts its effectiveness in matching complex log data that includes arrays. For example:
{ "message": "Some Message", "process": "Some Process", "connections": [ "123.1.1.1", "123.1.2.2", "123.3.3.3" ] }It is not possible to match a value in that array for example with:
Proposed Solution
Enhance Sigma with key modifiers for array matching, such as |arrayAny, |arrayAll, |arrayOne, and |arrayNone. This would allow for more flexible and powerful matching scenarios.
This would return true if any element in the connections array matches "123.1.1.1".
This would return true if all elements in the array start with "123".
--> Inspired by https://expr-lang.org/docs/Language-Definition#array-functions
Further Enhancement
Even further we could allow matching of nested keys on arrays of objects:
{ "message": "Some Message", "process": "Some Process", "connections": [ {"protocol":"TCP","ip":"123.1.1.1"}, {"protocol":"TCP","ip":"123.1.2.2"}, {"protocol":"UDP","ip":"123.3.3.3"} ] }Allowing to "chain" multiple keys would allow to match on array of objects. Taking above example, we could write detections like this:
or
I can see how this is a big change of current sigma philosophy and I am not sure how implementable this is in backends but taking elasticsearch as an example, it would work on nested objects: Nested Fields
All reactions