KQL Cafe - June 2024
Recording and Presentation
Hosts
Guests
News
- Analyze data using Log Analytics Simple mode (Preview)
- Microsoft Defender for Endpoint Advanced Hunting and Application Control for Business – WDACConfig
- Detect suspicious processes running on hidden desktops
You will find queries for the following use cases:
- Monitoring Cosmos DB's request unit consumption.
- Identifying top N queries by consumption in Cosmos DB.
- Checking for requests that are throttled in Cosmos DB.
- Checking for antivirus exclusions.
- Identifying applications using auto proxy (WPAD).
- Detecting changes to evade detection.
- Analyzing Microsoft Graph API usage patterns.
- Analyzing traffic patterns to Microsoft Graph APIs.
- Monitoring ID Governance in Microsoft Entra for usage patterns.
- Visualizing authentication method use over time.
- Understanding administrative activities.
- Monitoring short-lived connections in PostgreSQL.
- Monitoring failed login attempts in PostgreSQL.
- Resource utilization monitoring in PostgreSQL.
- Summarizing sign-ins via iOS and macOS SSO Extensions.
- Searching for MFA phone number changes using regex.
- Tracking dynamic group membership changes.
- Session breakdown by legacy vs modern TLS.
- Understanding email authentication patterns for security.
- Monitoring token protection impact and managing conditional access.
- Analyzing Intune device management events and enrollments.
- Monitoring failed operations and sign-in events.
- Network traffic monitoring.
- Identity governance operations.
- Detecting suspicious activities and anomalies.
- Identifying vulnerabilities and attack surfaces via IP range and CVE ID tracking.
- Detecting administrative actions and user re-enabling.
- High-risk sign-in patterns detection.
- Reporting on antimalware versions.
- Detecting email anomalies.
- Performance troubleshooting for SQL servers.
- Monitoring conditional access policy applications and failures
Our Guest Michalis Michalos
Our guest Michalis Michalos spoke about Defender for Endpoint and WSL.
Keeping an eye on WSL through Microsoft Defender for Endpoint
Identify endpoints that run WSL and/or MDE plug-in First things first, let’s identify endpoints that users run WSL with the following KQL:
DeviceProcessEvents
| where ActionType has "ProcessCreated"
| where ProcessVersionInfoOriginalFileName has "wsl.exe"
| where ProcessVersionInfoFileDescription has "Windows Subsystem for Linux"
| summarize by DeviceName
You can also identify which of your endpoints already have the MDE plug-in:
DeviceTvmSoftwareInventory
| where SoftwareName has "microsoft_defender_for_endpoint_plug-in_for_wsl"
| summarize by DeviceName
Joining forces from the queries above, you can identify endpoints running WSL but don’t have the plug-in installed:
let WSLDevices = DeviceProcessEvents
| where ActionType has "ProcessCreated"
| where ProcessVersionInfoOriginalFileName has "wsl.exe"
| where ProcessVersionInfoFileDescription has "Windows Subsystem for Linux"
| project DeviceName;
WSLDevices
| join kind=leftanti (DeviceTvmSoftwareInventory
| where SoftwareName has "microsoft_defender_for_endpoint_plug-in_for_wsl"
| project DeviceName
) on DeviceName
A simple hunt to begin with could be the following, looking for reconnaissance activity:
let WSLSuspicousList = dynamic(["whoami", "uname", "find", "grep", "cron -l", "/etc/shadow", "/etc/passwd", "/etc/sudoers", "w"]);
let TimeFrame = 30d; // Choose the best timeframe for your investigation
DeviceInfo
| where RegistryDeviceTag has "WSL2"
| project DeviceId
| join ( DeviceProcessEvents
| where Timestamp > ago(TimeFrame)
| where ActionType == "ProcessCreated"
| where ProcessCommandLine has_any (WSLSuspicousList)
| project TimeGenerated, WSLDeviceID = DeviceId, DeviceName, FileName, FolderPath, ProcessId, ProcessCommandLine, AccountDomain, AccountName
)
on $left.DeviceId == $right.WSLDeviceID
| sort by TimeGenerated desc
Check out the above referenced blog post for more KQL for WSL.
Learn KQL
MicrosoftGraphActivityLogs
| where ResponseStatusCode == "200"
| join kind=inner AADNonInteractiveUserSignInLogs on $left.SignInActivityId == $right.UniqueTokenIdentifier
| project-away *1
SigninLogs
| summarize arg_max(TimeGenerated,*) by ResultType
| project-keep TimeGenerated, OperationName, AppDisplayName, Risk*
What did you do with KQL this month
Monitor Azure Automation Account Runbooks
AzureDiagnostics
| where Category == 'JobLogs'
| extend RunbookName = RunbookName_s
| project TimeGenerated,RunbookName,ResultType,CorrelationId,JobId_g
| summarize StartTime = minif(TimeGenerated,ResultType == 'Started'),EndTime = minif(TimeGenerated,ResultType in ('Completed','Failed','Failed')),
Status = tostring(parse_json(make_list_if(ResultType,ResultType in ('Completed','Failed','Stopped')))[0]) by JobId_g,RunbookName
| extend DurationSec = datetime_diff('second', EndTime,StartTime)
| join kind=leftouter (AzureDiagnostics
| where Category == "JobStreams"
| where StreamType_s == "Error"
| summarize TotalErrors = dcount(StreamType_s) by JobId_g, StreamType_s)
on $left. JobId_g == $right. JobId_g
| extend HasErrors = iff(StreamType_s == 'Error',true,false)
| project StartTime, EndTime, DurationSec,RunbookName,Status,HasErrors,TotalErrors,JobId_g
Defender for Endpoint - internet-facing devices
JA3
show all SSL connections
show all SSL connections and additional details (unpacked)
DeviceNetworkEvents
| where ActionType == "SslConnectionInspected"
| extend AF = parse_json(AdditionalFields)
| evaluate bag_unpack(AF)
show all SSL connections and join on successfull device network events to iidentify the executable JA3 (Client)
DeviceNetworkEvents
| where ActionType == "SslConnectionInspected"
| extend Array = parse_json(AdditionalFields)
| join kind=inner (
DeviceNetworkEvents
| where ActionType == "ConnectionSuccess"
) on DeviceId, LocalIP, LocalPort, RemoteIP, RemotePort
| extend JA3 = tostring(Array.ja3), JA3S = tostring(Array.ja3s)
| summarize count() by Client = JA3,
//Server = JA3S,
InitiatingProcessFileName1, InitiatingProcessVersionInfoProductVersion1
show all SSL connections and count the successfull connections to a JA3S (Server)
```kql
DeviceNetworkEvents
| where ActionType == "SslConnectionInspected"
| extend Array = parse_json(AdditionalFields)
| join kind=inner (
DeviceNetworkEvents
| where ActionType == "ConnectionSuccess"
) on DeviceId, LocalIP, LocalPort, RemoteIP, RemotePort
| extend JA3 = tostring(Array.ja3), JA3S = tostring(Array.ja3s)
| summarize count() by Server = JA3S,
InitiatingProcessFileName1, InitiatingProcessVersionInfoProductVersion1, RemoteIP