detect-anomalous-process-trees


Description

This query generates process trees of given processes and performs anomaly detection on the process trees. It generates process trees up to 7th level. The query can be used as a template to perform anomaly detection on specific processes like winword.exe, powerpnt.exe, w3wp.exe, etc. The query runs without any performance issues in large environments. Detailed explanation can be found here Reference - https://posts.bluraven.io/detecting-threats-with-process-tree-analysis-without-machine-learning-838d85f78b2c

Query · kql

let timeframe = 48h;
// Define of which processes you want to generate process tree
let _selected_processes = dynamic(["winword.exe","excel.exe","powerpnt.exe","acrord32.exe", "FoxitPhantomPDF.exe","MicrosoftPdfReader.exe","SumatraPDF.exe"]); 
// First, generate the process tree and store it in the cache.
// Renaming fields accordingly to generate a tree up to 7th level
// In each step, project only the required fields to optimize resource usage
let _process_tree_data= materialize 
( DeviceProcessEvents
    | where Timestamp > ago(timeframe)
    | where InitiatingProcessFileName in~ (_selected_processes )
    | project DeviceId,DeviceName, 
              InitiatingProcessG3ParentFileName=FileName,InitiatingProcessG3ParentSHA1=SHA1,InitiatingProcessG3ParentId=ProcessId, InitiatingProcessG3ParentCommandLine=ProcessCommandLine,InitiatingProcessG3ParentCreationTime=todatetime(ProcessCreationTime),
              InitiatingProcessG4ParentFileName=InitiatingProcessFileName,InitiatingProcessG4ParentSHA1=InitiatingProcessSHA1,InitiatingProcessG4ParentId=InitiatingProcessId,InitiatingProcessG4ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG4ParentCreationTime=todatetime(InitiatingProcessCreationTime)
    // Start iteration
    // 1st iteration of join. From now on, query all processes, rename fields, and join accordingly
    | join kind=leftouter (
                DeviceProcessEvents
                    | where Timestamp > ago(timeframe)
                    | project DeviceId, InitiatingProcessG2ParentFileName=FileName,InitiatingProcessG2ParentFolderPath=FolderPath,InitiatingProcessG2ParentSHA1=SHA1, InitiatingProcessG2ParentId=ProcessId,  InitiatingProcessG2ParentCommandLine=ProcessCommandLine, InitiatingProcessG2ParentCreationTime=todatetime(ProcessCreationTime), 
                       InitiatingProcessG3ParentFileName=InitiatingProcessFileName,InitiatingProcessG3ParentFolderPath=InitiatingProcessFolderPath,InitiatingProcessG3ParentSHA1=InitiatingProcessSHA1, InitiatingProcessG3ParentId=InitiatingProcessId,  InitiatingProcessG3ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG3ParentCreationTime=todatetime(InitiatingProcessCreationTime)
                     ) 
                     on DeviceId , InitiatingProcessG3ParentFileName, InitiatingProcessG3ParentId, InitiatingProcessG3ParentCreationTime
        // 2nd iteration of join.
        | join kind=leftouter (
                    DeviceProcessEvents
                        | where Timestamp > ago(timeframe)
                        | project DeviceId, InitiatingProcessG1ParentFileName=FileName,InitiatingProcessG1ParentFolderPath=FolderPath,InitiatingProcessG1ParentSHA1=SHA1, InitiatingProcessG1ParentId=ProcessId,  InitiatingProcessG1ParentCommandLine=ProcessCommandLine, InitiatingProcessG1ParentCreationTime=todatetime(ProcessCreationTime), 
                        InitiatingProcessG2ParentFileName=InitiatingProcessFileName,InitiatingProcessG2ParentFolderPath=InitiatingProcessFolderPath,InitiatingProcessG2ParentSHA1=InitiatingProcessSHA1, InitiatingProcessG2ParentId=InitiatingProcessId,  InitiatingProcessG2ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG2ParentCreationTime=todatetime(InitiatingProcessCreationTime)
                        ) 
                        on DeviceId , InitiatingProcessG2ParentFileName , InitiatingProcessG2ParentId, InitiatingProcessG2ParentCreationTime
            // 3rd iteration of join.
            | join kind=leftouter (
                        DeviceProcessEvents
                            | where Timestamp > ago(timeframe)
                            | project DeviceId, InitiatingProcessParentFileName=FileName,InitiatingProcessParentFolderPath=FolderPath,InitiatingProcessParentSHA1=SHA1, InitiatingProcessParentId=ProcessId,  InitiatingProcessParentCommandLine=ProcessCommandLine, InitiatingProcessParentCreationTime=ProcessCreationTime, 
                            InitiatingProcessG1ParentFileName=InitiatingProcessFileName,InitiatingProcessG1ParentFolderPath=InitiatingProcessFolderPath,InitiatingProcessG1ParentSHA1=InitiatingProcessSHA1, InitiatingProcessG1ParentId=InitiatingProcessId,  InitiatingProcessG1ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG1ParentCreationTime=todatetime(InitiatingProcessCreationTime)
                            ) 
                            on DeviceId , InitiatingProcessG1ParentFileName , InitiatingProcessG1ParentId, InitiatingProcessG1ParentCreationTime
                // 4th iteration of join
                | join kind=leftouter (
                            DeviceProcessEvents
                                | where Timestamp > ago(timeframe)
                                | project DeviceId, InitiatingProcessFileName=FileName,InitiatingProcessSHA1=SHA1, InitiatingProcessId=ProcessId,  InitiatingProcessCommandLine=ProcessCommandLine, InitiatingProcessCreationTime=ProcessCreationTime, 
                                InitiatingProcessParentFileName=InitiatingProcessFileName,InitiatingProcessParentSHA1=InitiatingProcessSHA1, InitiatingProcessParentId=InitiatingProcessId,  InitiatingProcessParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessParentCreationTime=InitiatingProcessCreationTime
                                ) 
                                on DeviceId , InitiatingProcessParentFileName , InitiatingProcessParentId, InitiatingProcessParentCreationTime
                    // 5th iteration of join
                    | join kind=leftouter (
                                DeviceProcessEvents
                                    | where Timestamp > ago(timeframe)
                                    | project Timestamp, DeviceId, FileName,SHA1, ProcessId, ProcessCommandLine, ProcessCreationTime, 
                                    InitiatingProcessFileName,InitiatingProcessSHA1, InitiatingProcessId, InitiatingProcessCommandLine, InitiatingProcessCreationTime
                                    ) 
                                    on DeviceId , InitiatingProcessFileName , InitiatingProcessId, InitiatingProcessCreationTime
);
// Use the cached results and find the rare patterns based on process names.
_process_tree_data
|summarize count() by FileName,InitiatingProcessFileName,InitiatingProcessParentFileName,InitiatingProcessG1ParentFileName,InitiatingProcessG2ParentFileName,InitiatingProcessG3ParentFileName,InitiatingProcessG4ParentFileName
| where count_ < 10 // If the count of a pattern is less than 10, it is anomalous. Threshold can be changed.
// Now, join the anomalous patterns with the original results to get the details. 
| join kind=inner _process_tree_data on FileName,InitiatingProcessFileName,InitiatingProcessParentFileName,InitiatingProcessG1ParentFileName,InitiatingProcessG2ParentFileName,InitiatingProcessG3ParentFileName,InitiatingProcessG4ParentFileName
// Now, join the anomalous patterns with the original results to get the details. 
|project Timestamp=case(isnotempty(Timestamp),Timestamp,isnotempty(InitiatingProcessParentCreationTime),InitiatingProcessParentCreationTime,isnotempty(InitiatingProcessG1ParentCreationTime),InitiatingProcessG1ParentCreationTime,
    isnotempty(InitiatingProcessG2ParentCreationTime),InitiatingProcessG2ParentCreationTime,isnotempty(InitiatingProcessG3ParentCreationTime),InitiatingProcessG3ParentCreationTime,InitiatingProcessG4ParentCreationTime),
    count_ , DeviceId, DeviceName, 
    InitiatingProcessG4ParentFileName,InitiatingProcessG3ParentFileName,InitiatingProcessG2ParentFileName,InitiatingProcessG1ParentFileName,InitiatingProcessParentFileName,InitiatingProcessFileName,FileName,
    InitiatingProcessG4ParentCommandLine, InitiatingProcessG3ParentCommandLine, InitiatingProcessG2ParentCommandLine, InitiatingProcessG1ParentCommandLine, InitiatingProcessCommandLine, ProcessCommandLine,
    InitiatingProcessG4ParentId,  InitiatingProcessG4ParentCreationTime,
    InitiatingProcessG3ParentId, InitiatingProcessG3ParentFolderPath ,InitiatingProcessG3ParentSHA1,  InitiatingProcessG3ParentCreationTime,
    InitiatingProcessG2ParentId,InitiatingProcessG2ParentFolderPath,InitiatingProcessG2ParentSHA1, InitiatingProcessG2ParentCreationTime,
    InitiatingProcessG1ParentId,InitiatingProcessG1ParentFolderPath,InitiatingProcessG1ParentSHA1,  InitiatingProcessG1ParentCreationTime,
    InitiatingProcessParentId, InitiatingProcessParentFolderPath,InitiatingProcessParentSHA1, InitiatingProcessParentCommandLine ,InitiatingProcessParentCreationTime,
    InitiatingProcessId, InitiatingProcessSHA1,  InitiatingProcessCreationTime,
    ProcessId, SHA1,  ProcessCreationTime
| order by Timestamp, DeviceName, InitiatingProcessG4ParentCreationTime , InitiatingProcessG3ParentCreationTime , InitiatingProcessG2ParentCreationTime , InitiatingProcessG1ParentCreationTime , InitiatingProcessCreationTime
Raw source detect-anomalous-process-trees · KQL
Esc
Published by Azure/Azure-Sentinel ↗, licensed under MIT ↗. Reproduced here unmodified.
id: a3bbacd9-7e8a-4dbc-a168-d08740f9904e
name: detect-anomalous-process-trees
description: |
  This query generates process trees of given processes and performs anomaly detection on the process trees. It generates process trees up to 7th level.
  The query can be used as a template to perform anomaly detection on specific processes like winword.exe, powerpnt.exe, w3wp.exe, etc. The query runs without any performance issues in large environments.
  Detailed explanation can be found here
  Reference - https://posts.bluraven.io/detecting-threats-with-process-tree-analysis-without-machine-learning-838d85f78b2c
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
  dataTypes:
  - DeviceProcessEvents
tactics:
- Initial access
- Execution
- Persistence
- Discovery
- Lateral movement
query: |
  let timeframe = 48h;
  // Define of which processes you want to generate process tree
  let _selected_processes = dynamic(["winword.exe","excel.exe","powerpnt.exe","acrord32.exe", "FoxitPhantomPDF.exe","MicrosoftPdfReader.exe","SumatraPDF.exe"]); 
  // First, generate the process tree and store it in the cache.
  // Renaming fields accordingly to generate a tree up to 7th level
  // In each step, project only the required fields to optimize resource usage
  let _process_tree_data= materialize 
  ( DeviceProcessEvents
      | where Timestamp > ago(timeframe)
      | where InitiatingProcessFileName in~ (_selected_processes )
      | project DeviceId,DeviceName, 
                InitiatingProcessG3ParentFileName=FileName,InitiatingProcessG3ParentSHA1=SHA1,InitiatingProcessG3ParentId=ProcessId, InitiatingProcessG3ParentCommandLine=ProcessCommandLine,InitiatingProcessG3ParentCreationTime=todatetime(ProcessCreationTime),
                InitiatingProcessG4ParentFileName=InitiatingProcessFileName,InitiatingProcessG4ParentSHA1=InitiatingProcessSHA1,InitiatingProcessG4ParentId=InitiatingProcessId,InitiatingProcessG4ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG4ParentCreationTime=todatetime(InitiatingProcessCreationTime)
      // Start iteration
      // 1st iteration of join. From now on, query all processes, rename fields, and join accordingly
      | join kind=leftouter (
                  DeviceProcessEvents
                      | where Timestamp > ago(timeframe)
                      | project DeviceId, InitiatingProcessG2ParentFileName=FileName,InitiatingProcessG2ParentFolderPath=FolderPath,InitiatingProcessG2ParentSHA1=SHA1, InitiatingProcessG2ParentId=ProcessId,  InitiatingProcessG2ParentCommandLine=ProcessCommandLine, InitiatingProcessG2ParentCreationTime=todatetime(ProcessCreationTime), 
                         InitiatingProcessG3ParentFileName=InitiatingProcessFileName,InitiatingProcessG3ParentFolderPath=InitiatingProcessFolderPath,InitiatingProcessG3ParentSHA1=InitiatingProcessSHA1, InitiatingProcessG3ParentId=InitiatingProcessId,  InitiatingProcessG3ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG3ParentCreationTime=todatetime(InitiatingProcessCreationTime)
                       ) 
                       on DeviceId , InitiatingProcessG3ParentFileName, InitiatingProcessG3ParentId, InitiatingProcessG3ParentCreationTime
          // 2nd iteration of join.
          | join kind=leftouter (
                      DeviceProcessEvents
                          | where Timestamp > ago(timeframe)
                          | project DeviceId, InitiatingProcessG1ParentFileName=FileName,InitiatingProcessG1ParentFolderPath=FolderPath,InitiatingProcessG1ParentSHA1=SHA1, InitiatingProcessG1ParentId=ProcessId,  InitiatingProcessG1ParentCommandLine=ProcessCommandLine, InitiatingProcessG1ParentCreationTime=todatetime(ProcessCreationTime), 
                          InitiatingProcessG2ParentFileName=InitiatingProcessFileName,InitiatingProcessG2ParentFolderPath=InitiatingProcessFolderPath,InitiatingProcessG2ParentSHA1=InitiatingProcessSHA1, InitiatingProcessG2ParentId=InitiatingProcessId,  InitiatingProcessG2ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG2ParentCreationTime=todatetime(InitiatingProcessCreationTime)
                          ) 
                          on DeviceId , InitiatingProcessG2ParentFileName , InitiatingProcessG2ParentId, InitiatingProcessG2ParentCreationTime
              // 3rd iteration of join.
              | join kind=leftouter (
                          DeviceProcessEvents
                              | where Timestamp > ago(timeframe)
                              | project DeviceId, InitiatingProcessParentFileName=FileName,InitiatingProcessParentFolderPath=FolderPath,InitiatingProcessParentSHA1=SHA1, InitiatingProcessParentId=ProcessId,  InitiatingProcessParentCommandLine=ProcessCommandLine, InitiatingProcessParentCreationTime=ProcessCreationTime, 
                              InitiatingProcessG1ParentFileName=InitiatingProcessFileName,InitiatingProcessG1ParentFolderPath=InitiatingProcessFolderPath,InitiatingProcessG1ParentSHA1=InitiatingProcessSHA1, InitiatingProcessG1ParentId=InitiatingProcessId,  InitiatingProcessG1ParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessG1ParentCreationTime=todatetime(InitiatingProcessCreationTime)
                              ) 
                              on DeviceId , InitiatingProcessG1ParentFileName , InitiatingProcessG1ParentId, InitiatingProcessG1ParentCreationTime
                  // 4th iteration of join
                  | join kind=leftouter (
                              DeviceProcessEvents
                                  | where Timestamp > ago(timeframe)
                                  | project DeviceId, InitiatingProcessFileName=FileName,InitiatingProcessSHA1=SHA1, InitiatingProcessId=ProcessId,  InitiatingProcessCommandLine=ProcessCommandLine, InitiatingProcessCreationTime=ProcessCreationTime, 
                                  InitiatingProcessParentFileName=InitiatingProcessFileName,InitiatingProcessParentSHA1=InitiatingProcessSHA1, InitiatingProcessParentId=InitiatingProcessId,  InitiatingProcessParentCommandLine=InitiatingProcessCommandLine, InitiatingProcessParentCreationTime=InitiatingProcessCreationTime
                                  ) 
                                  on DeviceId , InitiatingProcessParentFileName , InitiatingProcessParentId, InitiatingProcessParentCreationTime
                      // 5th iteration of join
                      | join kind=leftouter (
                                  DeviceProcessEvents
                                      | where Timestamp > ago(timeframe)
                                      | project Timestamp, DeviceId, FileName,SHA1, ProcessId, ProcessCommandLine, ProcessCreationTime, 
                                      InitiatingProcessFileName,InitiatingProcessSHA1, InitiatingProcessId, InitiatingProcessCommandLine, InitiatingProcessCreationTime
                                      ) 
                                      on DeviceId , InitiatingProcessFileName , InitiatingProcessId, InitiatingProcessCreationTime
  );
  // Use the cached results and find the rare patterns based on process names.
  _process_tree_data
  |summarize count() by FileName,InitiatingProcessFileName,InitiatingProcessParentFileName,InitiatingProcessG1ParentFileName,InitiatingProcessG2ParentFileName,InitiatingProcessG3ParentFileName,InitiatingProcessG4ParentFileName
  | where count_ < 10 // If the count of a pattern is less than 10, it is anomalous. Threshold can be changed.
  // Now, join the anomalous patterns with the original results to get the details. 
  | join kind=inner _process_tree_data on FileName,InitiatingProcessFileName,InitiatingProcessParentFileName,InitiatingProcessG1ParentFileName,InitiatingProcessG2ParentFileName,InitiatingProcessG3ParentFileName,InitiatingProcessG4ParentFileName
  // Now, join the anomalous patterns with the original results to get the details. 
  |project Timestamp=case(isnotempty(Timestamp),Timestamp,isnotempty(InitiatingProcessParentCreationTime),InitiatingProcessParentCreationTime,isnotempty(InitiatingProcessG1ParentCreationTime),InitiatingProcessG1ParentCreationTime,
      isnotempty(InitiatingProcessG2ParentCreationTime),InitiatingProcessG2ParentCreationTime,isnotempty(InitiatingProcessG3ParentCreationTime),InitiatingProcessG3ParentCreationTime,InitiatingProcessG4ParentCreationTime),
      count_ , DeviceId, DeviceName, 
      InitiatingProcessG4ParentFileName,InitiatingProcessG3ParentFileName,InitiatingProcessG2ParentFileName,InitiatingProcessG1ParentFileName,InitiatingProcessParentFileName,InitiatingProcessFileName,FileName,
      InitiatingProcessG4ParentCommandLine, InitiatingProcessG3ParentCommandLine, InitiatingProcessG2ParentCommandLine, InitiatingProcessG1ParentCommandLine, InitiatingProcessCommandLine, ProcessCommandLine,
      InitiatingProcessG4ParentId,  InitiatingProcessG4ParentCreationTime,
      InitiatingProcessG3ParentId, InitiatingProcessG3ParentFolderPath ,InitiatingProcessG3ParentSHA1,  InitiatingProcessG3ParentCreationTime,
      InitiatingProcessG2ParentId,InitiatingProcessG2ParentFolderPath,InitiatingProcessG2ParentSHA1, InitiatingProcessG2ParentCreationTime,
      InitiatingProcessG1ParentId,InitiatingProcessG1ParentFolderPath,InitiatingProcessG1ParentSHA1,  InitiatingProcessG1ParentCreationTime,
      InitiatingProcessParentId, InitiatingProcessParentFolderPath,InitiatingProcessParentSHA1, InitiatingProcessParentCommandLine ,InitiatingProcessParentCreationTime,
      InitiatingProcessId, InitiatingProcessSHA1,  InitiatingProcessCreationTime,
      ProcessId, SHA1,  ProcessCreationTime
  | order by Timestamp, DeviceName, InitiatingProcessG4ParentCreationTime , InitiatingProcessG3ParentCreationTime , InitiatingProcessG2ParentCreationTime , InitiatingProcessG1ParentCreationTime , InitiatingProcessCreationTime

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.