Note: I have updated the kql queries below, but the screenshots itself still refer to the previous (old) schema names
If you’re among those administrators that use Microsoft Defender Advanced Threat Protection, here’s a handy tip how to find out who’s logging on with local administrators’ rights. But first when would you want to run this? Well here are some scenarios I can think of:
- You want to find users that have local administrator rights on their devices.
- You introduced LAPS and instructed your IT support to no longer use their own credentials but use the LAPS Administrator and password. (here’s a great article why you should do so. Remote Use of Local Accounts: LAPS Changes Everything
- You’re proactively looking for suspicious behaviour
Or if you want to get more details about the computer and how they logged on (Remote Interactive, Interactive or via the network such as with PowerShell) simply comment out the summarize line in the kusto query code.
Yes I know screenshots with code aren’t cool, so here again to copy paste:
Update: August 2020, i have updated the below query to work with the latest MDATP hunting schema
// Uses that logon with local admin rights summary DeviceLogonEvents
| where IsLocalAdmin == 1
| extend locallogon = extractjson(“$.IsLocalLogon”,AdditionalFields, typeof(string))
| project Timestamp , DeviceName, AccountDomain, AccountName , LogonType, ActionType, locallogon
| summarize count() by AccountName
|
// users that logon on with Local Admin rights – detailed
DeviceLogonEvents
| where IsLocalAdmin == 1
| extend locallogon = extractjson(“$.IsLocalLogon”,AdditionalFields, typeof(string))
| project Timestamp , DeviceName, AccountDomain, AccountName , LogonType, ActionType, locallogon
|
Thanks VERY much for this tip, however is it possible a couple of fields have changed since you wrote this?
This worked for me:
DeviceLogonEvents| where IsLocalAdmin == 1
| extend locallogon = extractjson(“$.IsLocalLogon”,AdditionalFields, typeof(string))
| project Timestamp , DeviceName, AccountDomain, AccountName , LogonType, ActionType, locallogon
// summarize by user
| summarize count() by AccountName
Thanks very much for your knowledge!
However is it possible a couple of the fields have changed since you wrote this?
This worked for me:
DeviceLogonEvents| where IsLocalAdmin == 1
| extend locallogon = extractjson(“$.IsLocalLogon”,AdditionalFields, typeof(string))
| project Timestamp , DeviceName, AccountDomain, AccountName , LogonType, ActionType, locallogon
// summarize by user
| summarize count() by AccountName
Yes that is correct, thanks for the hint, i have updated the blog post
Were you successfully able to create a detection rule from this query? I’m getting syntax errors and am still unsure what’s wrong as these aren’t very verbose
Hello Michael, i have updated the queries, they used the old MDATP schema , should work now
DeviceLogonEvents
| where IsLocalAdmin == 1
| extend locallogon = extractjson(“$.IsLocalLogon”,AdditionalFields, typeof(string))
| project Timestamp , DeviceName, AccountDomain, AccountName , LogonType, ActionType, locallogon
| summarize count() by AccountName
your extractjson breaks in Defender as well…
my bad, copy/paste messed up the double quotes. please ignore my comments.
If you’re looking for this in Azure Sentinel:
Replace:
| extend locallogon = extractjson(“$.IsLocalLogon”,AdditionalFields, typeof(string))
with this:
| where AdditionalFields.IsLocalLogon == true
i get this error: Error message
Path expression IsLocalLogon source must be scalar of type ‘dynamic’. Received a source of type string instead