We’re back with additional methods that the Google Security Operations (SecOps) rules engine can leverage to build composite rules. So far in this mini-series we have been very focused on detections and creating alerts based on rolling multiple detections up, whether that is by descriptors, risk score, variables or rule labels.
Today we are going to branch out and move beyond detections. While composite rules will most often leverage detections only, there may be some use cases where having a mix of detections with a little frosting on top of UDM events may be just what the detection engineer ordered.
To do this, we are going to start by revisiting the first composite rule we built in this series. This rule uses specific rule IDs to identify detections and then aggregates them over a two hour window by a common hostname.
rule composite_lolbin_recon_by_hostname {
meta:
author = "Google Cloud Security"
description = "Detects multiple producer rules triggering based on a common tactic of discovery associated with Volt Typhoon"
reference = "https://media.defense.gov/2023/May/24/2003229517/-1/-1/0/CSA_Living_off_the_Land.PDF"
severity = "High"
priority = "High"
type = "composite"
events:
$detect_prod1.detection.detection.rule_id = "ru_9912f523-0633-49d4-b6f1-90a766d9919d" //producer_recon_environment_enumeration_active_directory_cisa_report
$detect_prod1.detection.detection.detection_fieldsd"hostname"] = $hostname
$detect_prod2.detection.detection.rule_id = "ru_91b9a754-ff55-4cd9-ab56-62a2102fdb6e" //producer_recon_environment_enumeration_network_cisa_report
$detect_prod2.detection.detection.detection_fieldsd"hostname"] = $hostname
$detect_prod3.detection.detection.rule_id = "ru_9dc70038-a0ae-4720-b45a-bb172cf8d078" //producer_recon_environment_enumeration_system_cisa_report
$detect_prod3.detection.detection.detection_fieldsd"hostname"] = $hostname
match:
$hostname over 2h
outcome:
$risk_score = 60
$rules_triggered = arrays.concat(arrays.concat(array_distinct($detect_prod1.detection.detection.rule_name), array_distinct($detect_prod2.detection.detection.rule_name)),array_distinct($detect_prod3.detection.detection.rule_name))
condition:
$detect_prod1 and $detect_prod2 and $detect_prod3
}
When we test our detection, we can see that each composite test detection has at least three detections in it. If we expand one of the detections, we can view the UDM events that help trigger the underlying detection and by clicking on the event, we can see a listing of all UDM fields on the right side of the page. To highlight specific fields, rather than adding them to the columnar view here, I went ahead and pinned them in the event viewer so they are at the top of the viewer.
Here we can see that tim.smith_admin is the user who launched the process DiskUtil-win-x64-installer.exe from the downloads folder on win-server. In one use case, the presence of these three detections in a small time window might be sufficient to generate an alert, and we could move on with our day to investigate this.
But let’s say that while this is interesting, it may not be compelling enough to generate an alert and additional suspicious activity may be needed on top of these detections. We could add additional detection rules to this, but we could also add UDM events to this rule that aren’t part of a detection as well. Let’s take a look.
Depending on your logging, file creation events themselves can be voluminous and many can be innocuous but just like anything else, there can be nuggets of goodness in there. The problem with the volume is that it may not be worth building detections for these file creation events unless there is a high fidelity detection that you’ve identified and always want to collect.
For the sake of this example, we are going to make the assumption that we don’t have that high fidelity detection in place, but we do know that when users are creating .exe files in the Windows\\Temp directory and they are doing this based on an .exe file executing in the user’s Downloads directory, this is something we want to look further into.
Let’s use that criteria and build a search and see what we find. We will use regular expressions and long time readers know that I don’t claim to be a regex expert so there are likely to be improvements in the quality of the regex but this is enough to get us started.
$file.metadata.event_type = "FILE_CREATION"
re.regex($file.principal.process.command_line, `\\\\Users\\\\.*\\\\Downloads\\\\.*\\.exe`) nocase
re.regex($file.target.file.full_path, `\\\\Windows\\\\Temp\\\\.*\\.exe`) nocase
Here we can see that we get a result based on this query. While we could convert this into a detection, let’s instead just augment our existing composite detection by looking for files that are created in this manner.
At the top of our detection funnel are the UDM events that are used for our initial detections, which we already looked at. The composite rule previously just used the rule IDs from those detections. This time we are going to include file creation events from our pool of UDM events and then aggregate by both the hostname and the user ID.
Because this rule builds on the previous one, I’ve bolded some of the key differences between the original rule and the updated rule that adds the UDM file creation event to it. The first difference is that in the original rule, we joined the detections by hostname, now we are joining on both hostname and user ID. This is a choice I made to tighten up my rule, it’s not mandatory and just like any other rule that you build, it’s important to review the detections and their match and outcome variables to ensure that the variables exist to be able to create the join.
The search criteria from above is brought into the rule and assigned an event variable of $file. Additionally, placeholder variables are created to join the file creation event to the detection events. To ensure that the file creation events happen before the detection events, we added a few inequality statements.
rule composite_detection_recon_activity_followed_by_file_creation_exe_temp_from_downloads {
meta:
author = "Google Cloud Security"
description = "Detects recon activity followed by file creation of exe in the Windows temp directory and the process is executed from a users download directory"
severity = "High"
priority = "High"
type = "composite"
events:
$detect_prod1.detection.detection.rule_id = "ru_9912f523-0633-49d4-b6f1-90a766d9919d" //producer_recon_environment_enumeration_active_directory_cisa_report
$detect_prod1.detection.detection.detection_fieldsd"hostname"] = $hostname
$detect_prod1.detection.detection.outcomest"principal_user_userid"] = $userid
$detect_prod2.detection.detection.rule_id = "ru_91b9a754-ff55-4cd9-ab56-62a2102fdb6e" //producer_recon_environment_enumeration_network_cisa_report
$detect_prod2.detection.detection.detection_fieldsd"hostname"] = $hostname
$detect_prod2.detection.detection.outcomest"principal_user_userid"] = $userid
$detect_prod3.detection.detection.rule_id = "ru_9dc70038-a0ae-4720-b45a-bb172cf8d078" //producer_recon_environment_enumeration_system_cisa_report
$detect_prod3.detection.detection.detection_fieldsd"hostname"] = $hostname
$detect_prod3.detection.detection.outcomest"principal_user_userid"] = $userid
$file.metadata.event_type = "FILE_CREATION"
re.regex($file.principal.process.command_line, `\\\\Users\\\\.*\\\\Downloads\\\\.*\\.exe`) nocase
re.regex($file.target.file.full_path, `\\\\Windows\\\\Temp\\\\.*\\.exe`) nocase
$file.principal.hostname = $hostname
$file.principal.user.userid = $userid
$file.metadata.event_timestamp.seconds < $detect_prod1.detection.created_time.seconds
$file.metadata.event_timestamp.seconds < $detect_prod2.detection.created_time.seconds
$file.metadata.event_timestamp.seconds < $detect_prod3.detection.created_time.seconds
match:
$hostname, $userid over 2h
outcome:
$risk_score = 100
$rules_triggered = arrays.concat(arrays.concat(array_distinct($detect_prod1.detection.detection.rule_name),array_distinct($detect_prod2.detection.detection.rule_name)),array_distinct($detect_prod3.detection.detection.rule_name))
$process_executed = array_distinct($file.principal.process.command_line)
$file_created_path = array_distinct($file.target.file.full_path)
condition:
$detect_prod1 and $detect_prod2 and $detect_prod3 and $file
}
We are taking our detections and events that meet the criteria in the event section and aggregating them by the hostname and user ID over a two hour window and then outputting information about the rules triggered like we did previously but also outputting the process and file path by defining those fields from the UDM event in the outcome section. Lastly, we need to specify the event variable of $file in the condition section, just like the other event variables.
When we test the rule, we have a single detection, where previously we had four detections for the same time range. This one is focused on the user account tim.smith_admin and the system win-server. Expanding the test detection, we can see the detections for the time window as well as a single UDM event. If we click on the event, we can see that same event viewer on the right side of the page and in addition to the three pinned fields from earlier, we have the target.file.full_path pinned as well. We can see that the same process that was associated with the earlier detections was also responsible for the creation of this file in the Windows/Temp folder.
Now we have something a bit more suspicious to investigate.
Adding the flexibility of UDM events to composite rules to augment detections without having to build a chatty rule can be very helpful. It’s not something that I would expect to deploy in every composite rule but another tool in the tool chest that can be used to refine and tighten your use case. I hope this provides additional insights into how the Google SecOps rules engine can handle detections in concert with standalone UDM events!