Gartner coined the term User and Entity Behavior Analytics (UEBA) in 2015, sparking a flood of 'silver bullet' products. A decade later, effective UEBA implementation remains a challenge for most organizations. Personally, I’ve always seen UEBA as a technology to prioritize and refine security alerts, not a standalone solution.
I’d like to discuss how to implement UEBA with the objective of reducing the volume of security alerts that could otherwise overwhelm a security team.
If you'd like to dive deeper into the foundational concepts for what is discussed here, I recommend checking out these three previous articles: New to Google SecOps: Using Metrics in YARA-L Rules (Part 1), (Part 2) and (Part 3)
The below starting point YL2 rule (Azure command interpreter login after multiple failures) for our scenario identifies the combination of two main events to generate an alert:
This approach, while providing valuable information, inherently lacks the desired fidelity by including events where an account owner may have simply forgotten their password and performs a login that matches their normal activity after failing a few times. To increase our confidence that malicious behavior is occurring with such a rule, we can integrate User and Entity Behavior Analytics (UEBA). UEBA can transform a high-risk action into a truly actionable alert.
events:
$blocked_login.metadata.vendor_name = "Microsoft"
$blocked_login.metadata.log_type = "AZURE_AD"
$blocked_login.metadata.event_type = "USER_LOGIN"
$blocked_login.security_result.action = "BLOCK"
$blocked_login.security_result.summary = "Failed login occurred"
//Error 50140 - This error occurrs due to "Keep me signed in" interrupt when the user was signing-in.This can occur conjunction with succesful logins
$blocked_login.security_result.rule_id != "50140"
$allowed_login.metadata.vendor_name = "Microsoft"
$allowed_login.metadata.log_type = "AZURE_AD"
$allowed_login.metadata.event_type = "USER_LOGIN"
$allowed_login.security_result.action = "ALLOW"
(
$allowed_login.target.application = "Microsoft Azure PowerShell" or
$allowed_login.target.application = "Microsoft Azure CLI" or
$allowed_login.target.application = "Azure Active Directory PowerShell"
)
$targetAccountId = $blocked_login.target.user.userid
$targetAccountId = $allowed_login.target.user.userid
$blocked_login.metadata.event_timestamp.seconds < $allowed_login.metadata.event_timestamp.seconds
match:
$targetAccountId over 4h
outcome:
$failed_logins_count = count_distinct($blocked_login.metadata.id)
$victim_name = array_distinct($blocked_login.target.user.userid)
$failed_logins_count_threshold = 9
condition:
$blocked_login and $allowed_login and $failed_logins_count >= 9
To improve the efficiency of the original rule with the goal of identifying suspicious or malicious account behavior, we will insert two separate UEBA analytics.
$historical_login_count - Have we seen this user login before? If so, how many times in the last month? We look back over the last 30 days, and event_count_sum tells us how many times such logins were observed, each day, over that window. We then apply the sum aggregation, to get a total count of the number of times this has been observed in the past month.
$historical_threshold_country_success - We might also want to consider if this is the first time that this particular user has logged in from this country. Again, looking back over the past 30 days, we look at the first_seen metric from each day. If any of those values is greater than 0, that means we’ve seen that activity before (we do this by checking if the max aggregation is greater than 0). This is performed on each event where the principal.ip_geo_artifact.location.country_or_region and target.user.userid fields match.
By implementing these two analytics we are able to reduce false positives by ensuring the account has a pattern of being used at least 10 times and the login source country for the account has not been seen in successful logins over a 30 day period. Certain events will require more or less comprehensive historical baselines based on the activity being performed. By using 10 events within a 30 day period we will have a well established pattern of activity to compare against.
This is defined in the outcome section by ensuring the analytic outcomes are:
$historical_login_count >=10 and
$historical_threshold_country_success = 0
events:
$blocked_login.metadata.vendor_name = "Microsoft"
$blocked_login.metadata.log_type = "AZURE_AD"
$blocked_login.metadata.event_type = "USER_LOGIN"
$blocked_login.security_result.action = "BLOCK"
$blocked_login.security_result.summary = "Failed login occurred"
//Error 50140 - This error occurrs due to "Keep me signed in" interrupt when the user was signing-in. This can occur conjunction with succesful logins.
$blocked_login.security_result.rule_id != "50140"
$allowed_login.metadata.vendor_name = "Microsoft"
$allowed_login.metadata.log_type = "AZURE_AD"
$allowed_login.metadata.event_type = "USER_LOGIN"
$allowed_login.security_result.action = "ALLOW"
(
$allowed_login.target.application = "Microsoft Azure PowerShell" or
$allowed_login.target.application = "Microsoft Azure CLI" or
$allowed_login.target.application = "Azure Active Directory PowerShell"
)
$targetAccountId = $blocked_login.target.user.userid
$targetAccountId = $allowed_login.target.user.userid
$blocked_login.metadata.event_timestamp.seconds < $allowed_login.metadata.event_timestamp.seconds
match:
$targetAccountId over 4h
outcome:
$failed_logins_count = count_distinct($blocked_login.metadata.id)
$victim_name = array_distinct($blocked_login.target.user.userid)
$failed_logins_count_threshold = 9
// Counts the number of successful logins for this account over the past 30 days,this is helped to establish a baseline of activity
$historical_login_count = max(metrics.auth_attempts_success(
period:1d, window:30d,
metric:event_count_sum, agg:sum,
target.user.userid:$user_id))
// Analyzes historical login activity to determine the amount of times the source country for the IP address has been seen in successful logins.
$historical_threshold_country_success = max(metrics.auth_attempts_success(
period:1d, window:30d,
metric:first_seen, agg:max,
principal.ip_geo_artifact.location.country_or_region:$ip_country, target.user.userid:$user_id))
condition:
$blocked_login and $allowed_login and $failed_logins_count >= 9 and $historical_login_count >=10 and $historical_threshold_country_success = 0
The same approach used in this blog can be implemented across a wide range of detections to create high fidelity alerting out of your existing rule sets.
Some other examples of this are:
These are just a few examples of ways to implement UEBA analytics and you should always keep in mind that multiple UEBA analytics can be placed within a single rule to further increase the accuracy of the detection.