The majority of organizations are operating in a hybrid state, which means that a lot of organizations still have to deal with their On-Premises Active Directory environment.
Active Directory exists for more than a decade, but it hasn’t always been secured properly. Multiple changes are configured everyday, and it’s hard to find out, which setting has been configured insecurely for instance.
To mitigate this problem. We can use a Cloud native SIEM, like Azure Sentinel. Azure Sentinel runs on top of Log Analytics, which helps you to collect and analyze data that is generated in your Cloud and On-Premises environment.
Before we can start collecting logs from AD. We first have to install the Microsoft Monitoring Agent (MMA) on our Domain Controllers.
This is due to the fact that, Domain Controllers are servers that runs AD, so all the logs related to AD, can be found on a DC.
This agent can be downloaded if you scroll to Agents management under your Log Analytic Workspace.
After you have installed and configured your MMA Agents on your DC’s. It is time to configure the data connectors in Azure Sentinel, but before you go further. Make sure that the agent is able to communicate with Log Analytics.
Below you can find the proxy & firewall configuration that is required to make the MMA Agent being able to function properly.
Now you need to go to your Azure Sentinel workspace and click on Data connectors. These connectors allow us to collect data from various sources. Since all the AD logs belong to the ”Security” events on a Windows machine. Select Security Events, and then All Events. It is recommended to choose this option or otherwise you might miss some event ID’s.
Make sure that you check your audit policies first or otherwise you miss some valuable eventID’s.
Now we have received all the AD logs, which we can use to query and write custom detection rules.
- Here are some sample queries:
This KQL query can be found here: AdminSDHolderModification.yaml
let timeframe = 7d; SecurityEvent | where TimeGenerated >= ago(timeframe) | where EventID == 5136 | parse EventData with * 'ObjectDN">'ObjectDN'</Data>' * | parse EventData with * 'ObjectClass">'ObjectClass'</Data>' * | parse EventData with * 'AttributeLDAPDisplayName">'AttributeLDAPDisplayName'</Data>' * | where ObjectDN has "AdminSDHolder" | where AttributeLDAPDisplayName has "ntSecurityDescriptor" | summarize arg_max (TimeGenerated, Account, Computer, EventID, ObjectDN, ObjectClass, AttributeLDAPDisplayName) | sort by TimeGenerated desc
The second query looks, when the userAccountControl attribute of a user object has been modified and changed into the value 544. This means that the modified user can set an empty password.
This KQL query can be found here: EmptyPassword.yaml
let timeframe = 7d; SecurityEvent | where TimeGenerated >= ago(timeframe) | where EventID == 4738 | where NewUacValue has "0x14" | project TimeGenerated, Account, TargetUserName, Computer, EventID, OldUacValue, NewUacValue | sort by TimeGenerated desc
Last example will be monitoring high privileged built-in groups in AD with the likes of Domain Admins, Enterprise Admins, and so on.
This KQL query can be found here: ProtectedGroups.yaml
let timeframe = 7d; let protected_groups = dynamic (["Domain Admins","Enterprise Admins","Schema Admins","Administrators","Account Operators","Backup Operators","Server Operators","Print Operators","DnsAdmins"]); SecurityEvent | where TimeGenerated >= ago(timeframe) | where EventID in ("4728", "4732") | where TargetUserName has_any (protected_groups) | project TimeGenerated, Account, MemberName, TargetGroup = TargetAccount, Activity | sort by TimeGenerated desc
Azure Sentinel makes it relatively easy to track changes in AD. This makes it useful to write custom detection rules to alert on configurations that might be suspicious.
Why wait till an IT Admin is making a poor configuration, when you can always be ahead of it?