Microsoft Secure Tech Accelerator
Apr 03 2024, 07:00 AM - 11:00 AM (PDT)
Microsoft Tech Community

Monitoring specific list of users, belonging to an AD group

Brass Contributor

Hello everyone!

 

I have list of users that I would like to use for additional monitoring. We could say these are "high risk" users. These users belong to specific AD groups (more than one). We are currently getting logs from our on prem domain controllers. These logs are within the "SecurityEvent" table. I'm trying to create multiple alerts specific to these users, such as these users being added to new security groups. I'm trying to come up with a query to do this but so far no luck. I have tried using the "join" or "union" operators to combine SecurityEvents and IdentityInfo tables so once an group addition event (4728 for example)  is found in SecurityEvent table, it would look into IdentityInfo table to see if this user is part of the said groups (AD risk groups), if it is then alert is triggered. 

 

This was my idea but I am unable to get my query working. Am I on the right track? or would you have done it in a different way? I have come up with many different queries (that do not work) but see below for what I'm trying to achieve 

 

 

 

let HIGHRISKGROUPS= dynamic(["TEAM1", "TEAM2", "TEAM3", "TEAM4", "TEAM_5"]);
SecurityEvent
| union IdentityInfo
| where EventID == 4728
| where GroupMembership in (HIGHRISKGROUPS) \\ this is from the IdentityInfo table but obviously I'm not sure how to correlate the user with group  

 

 

 

I'm guessing the query does not make sense but that is my struggle at the moment.  Also, any ideas of how else would you monitor these users?

 

applicable log sources:

AzureActivity

SecurityEvent

IdentityInfo

AzureActiveDirectory (

  • SigninLogs
    AuditLogs
    AADNonInteractiveUserSignInLogs
    AADServicePrincipalSignInLogs
    AADManagedIdentitySignInLogs
    AADProvisioningLogs

 

5 Replies

@Ciyaresh I would suggest using a Watchlist (perhaps based off of the VIP watchlist Template) to store your users or groups.  It will be much easier to update this than trying to update all the rules you created with the list of them in it.

 

Then the rest of your code should work better.  The dynamic will create an array rather than a table while if you use a Watchlist it will be returned as a table with the added bonus of being able to add columns to hold additional information.

@Ciyaresh 

I had a somewhat similar problem where i wanted to create a query for alerting on brute-force attempts against users in specific "high risk groups". A user then came up with this solution:
https://learnsentinel.blog/2021/07/04/enrich-hunting-with-data-from-ms-graph-and-azure-ad/ 

This way you can have a updated table of the high risk users from our AD, then you can join other tables to cross reference activity regarding changes to group membership. 

@stianhoydal 

 

Thank you so much, I was able to push the high risk users to sentinel logs with a playbook following your method. However... excuse my ignorance but the last query you are running..

 

let Alert=
SigninLogs
| where UserPrincipalName contains "username"
| where ResultType == "50158"
| take 1;
let HighRiskUser=
HighRiskUsers_CL
| where TimeGenerated > ago(24h)
| extend UserPrincipalName = UserPrincipalName_s
| project TimeGenerated, UserPrincipalName, AADObjectID_g
;
Alert
| join kind=inner HighRiskUser on UserPrincipalName
| project TimeGenerated, ResultType, UserPrincipalName

 

this query works only if we replace "username" with an actual username. But wasnt the whole point of this to not enter usernames manually? what am I missing here. FYI I am just a beginner at KQL and still not familiar with most operators, including join/union. 

 

@Ciyaresh  Ah, well that is because the query you found in the link was made by the original creator, it is more of a test to see that it works. 

I would probably do something like this; 

let HighriskUsers = HighRiskUsers_CL
| distinct UserPrincipalName_s;
SecurityEvent
| where TargetAccount in (HighriskUsers)
| where EventID == "4624"

 Just make sure the custom log table usernames match with the SecurityEvent TargetAccount regarding upper/lower case. You can use the toupper/tolower function to make sure they match if they are not by default. I use the distinct operation to make sure i dont get duplicate values from the custom table. 

@stianhoydal Thank you, now I get it fully. works as you described!