Hunting TTPs with Azure Sentinel

Introduction:

Azure Sentinel is a cloud native SIEM solution that leverages, the power of Artificial Intelligence to analyze large data volumes at scale.

It provides a lot of capabilities and it’s a solution that I highly can recommend to both SOC Analysts and Threat Hunters.

Today in my blog post. I’m going to describe a use-case, and how we could use Azure Sentinel to hunt for the described use-case that I will demonstrate.

NOTE: If you scroll down at the end of this blog post. You will see a PDF that contains different TTPs based on ATT&CK. It walks you through different steps on using Azure Sentinel to hunt for those TTPs on a practical way by using KQL queries. There are multiple examples in it.

T1208 – Kerberoasting

Kerberoasting is a technique that allows an attacker to request service tickets for any Service Principal Name from a Domain Controller. All the requested service tickets can be exported from memory, and later on. Cracked offline. Every authenticated user is able to do this, which makes the attack so scary.

There are tons of blog posts about Kerberoasting, so if you want to understand this technique in-depth. I highly recommend to check out others their blog, because I’m not going to cover it into the details.

Example:

An attacker managed to get a foothold in an environment and decided to request all the service tickets from any SPN to Kerberoast it. This is possible with tools, such as Invoke-Kerberoast.

If we look at it from a defender perspective. It is a OpSec failure for the attacker, because at the event logs. We would see an account making numerous request at a short period of time.

Unfortunately it is very hard to monitor every Kerberos ticket, because it is a legitimate event that generates every minute or even seconds.

This means that it is very likely that we could miss this type of activity, but I’m going to demonstrate how we could use Azure Sentinel to hunt for this.

Hunting:

We will look for data from the past 30 days and this is the first KQL query that we will use.

// T1028 - Possible Kerberoasting
// Reference: https://attack.mitre.org/techniques/T1208/
let timeframe = 30d;
let requestCountThreshold = 3;
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4769
| parse EventData with * 'TargetUserName">' TargetUserName '</Data>' *
| parse EventData with * 'IpAddress">' IpAddress '</Data>' * 
| parse EventData with * 'ServiceName">' ServiceName '</Data>' *
| project TimeGenerated, Activity, TargetUserName, ServiceName, IpAddress

At the returned results, we can see around 1800 results.

Since we are interested in the average amount of request a user makes per day, we could use the summarize tabular operator and the count() scalar function to obtain the results that we’re looking for.

If we use the following KQL query:

// T1028 - Possible Kerberoasting
// Reference: https://attack.mitre.org/techniques/T1208/
let timeframe = 30d;
let requestCountThreshold = 3;
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4769
| parse EventData with * 'TargetUserName">' TargetUserName '</Data>' *
| parse EventData with * 'IpAddress">' IpAddress '</Data>' * 
| parse EventData with * 'ServiceName">' ServiceName '</Data>' * 
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), AttemptRequest = dcount(ServiceName) by TargetUserName, Activity, IpAddress 
| sort by StartTimeUtc desc

We can see a new column in the returned result that summarizes the average amount of request a user is making per day.

If we are going to baseline our environment. There is something suspicious in this time chart, because the average service ticket request of that a user is around 1-3. While we can see that Alice has made 11 request somewhere in the past 30 days. Keep in mind that this data is from a test lab, so it could be different in a production environment.

We can validate this result by filtering on the user Alice and see at which time she has requested a service ticket. Since machine accounts in AD have a password of 120 characters. It is not realistic that an attacker would try to crack that one, so we could exclude all the machine accounts that ends with the ”$” sign.

This will be our KQL query:

// T1028 - Possible Kerberoasting
// Reference: https://attack.mitre.org/techniques/T1208/
let timeframe = 30d;
let requestCountThreshold = 3;
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4769
| parse EventData with * 'TargetUserName">' TargetUserName '</Data>' *
| parse EventData with * 'IpAddress">' IpAddress '</Data>' * 
| parse EventData with * 'ServiceName">' ServiceName '</Data>' * 
| summarize AttemptRequest = dcount(ServiceName) by TargetUserName, ServiceName, TimeGenerated
| where TargetUserName == "Alice@IDENTITY.LOCAL"
| where ServiceName !endswith "$"
| sort by TimeGenerated desc

What we can see here is that Alice has requested multiple service tickets in just one minute.

Now we can create the following KQL query to look if a user has requested more than 3 service tickets on a day. We can use the following example:

// T1028 - Possible Kerberoasting
// Reference: https://attack.mitre.org/techniques/T1208/
let timeframe = 30d;
let requestCountThreshold = 3;
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4769
| parse EventData with * 'TargetUserName">' TargetUserName '</Data>' *
| parse EventData with * 'IpAddress">' IpAddress '</Data>' * 
| parse EventData with * 'ServiceName">' ServiceName '</Data>' * 
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), AttemptRequest = dcount(ServiceName) by TargetUserName, Activity, IpAddress
| project StartTimeUtc, EndTimeUtc, TargetUserName, AttemptRequest, IpAddress, Activity
| where AttemptRequest > requestCountThreshold
| sort by StartTimeUtc desc

Here it returns one result from the previous example.

Last, but not least. We can use this query as a Hunting query in Azure Sentinel. Here is an example, where I’ve created a hunting query and ran it. If you look closely. It shows one result, which is about the user, Alice.

If you liked this blog post. You might be interested in looking at the PDF down below, where it describes on a practical way, how you can use Azure Sentinel to hunt for TTPs based on ATT&CK.

Of course, nothing is perfect. If it can help you a bit. I’m glad to hear that. If you can do it even better? That’s super. Because we all can learn from each other, so I hope this could inspire you. The majority of queries are primary used for searching anomalies. Some can also be used as a detection rule, but most are really used for hunting.

Published by Huy

I have no idea what I'm doing.

2 thoughts on “Hunting TTPs with Azure Sentinel

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: