# scan

This is example from WPNinja Summit 2022 session "Throwing KQL like a shuriken". Presented by Gianni Castaldi and Alex Verboon&#x20;

#### Example 1

```
// Find Evil
search "ntdsutil"

// Find Evil
DeviceImageLoadEvents
| where InitiatingProcessFileName =~ "ntdsutil.exe" 

// Step one samlib.dll
DeviceImageLoadEvents
| where InitiatingProcessFileName =~ "ntdsutil.exe" 
| sort by Timestamp asc
| scan with_match_id=funnel_id declare(Step:string, Delta:timespan) with
(
    step Authentication: InitiatingProcessFileName =~ "ntdsutil.exe" 
        and FileName =~ "samlib.dll" 
            => Step = "Authenticated";
)

// Step two add vss_ps.dll
DeviceImageLoadEvents
| where InitiatingProcessFileName =~ "ntdsutil.exe" 
| sort by Timestamp asc
| scan with_match_id=funnel_id declare(Step:string, Delta:timespan) with
(
    step Authentication: InitiatingProcessFileName =~ "ntdsutil.exe" 
        and FileName =~ "samlib.dll" 
            => Step = "Authenticated";
    step NTDSExport: InitiatingProcessFileName =~ "ntdsutil.exe" 
        and FileName =~ "vss_ps.dll" 
        and Authentication.Timestamp > 10m 
            => Step = "NTDS export"
            , Delta = Timestamp - Authentication.Timestamp;
)
| project-reorder Timestamp, DeviceId, DeviceName, funnel_id, FileName, Step

// Step three finalize all
DeviceImageLoadEvents
| where InitiatingProcessFileName =~ "ntdsutil.exe" 
| sort by Timestamp asc
| scan with_match_id=funnel_id declare(Step:string, Delta:timespan) with
(
    step Authentication: InitiatingProcessFileName =~ "ntdsutil.exe" 
        and FileName =~ "samlib.dll" 
            => Step = "Authenticated";
    step NTDSExport: InitiatingProcessFileName =~ "ntdsutil.exe" 
        and FileName =~ "vss_ps.dll" 
        and Authentication.Timestamp > 10m 
            => Step = "NTDS export"
            , Delta = Timestamp - Authentication.Timestamp;
)
| where Step == "NTDS export"
| project-reorder Timestamp, DeviceId, DeviceName, funnel_id, FileName, Step
```

#### Example 2

```
let SuspiciousFiles = dynamic([
    "dir.exe"
    , "ipconfig.exe"
    , "systeminfo.exe"
    , "ping.exe"
    , "type.exe"
    , "net.exe"
    , "dsquery.exe"
    , "csvde.exe"
    , "nbtstat.exe"
    , "nltest.exe"
    , "ntdsutil.exe"
    , "adfind.exe"
    , "nslookup.exe"
    , "procdump.exe"
    , "whoami.exe"
    , "wmic.exe"
    , "mimikatz.exe"
    , "tasklist.exe"
    , "rubeus.exe"]);
DeviceProcessEvents
| where FileName has_any(SuspiciousFiles)

let SuspiciousFiles = dynamic(["dir.exe", "ipconfig.exe", "systeminfo.exe", "ping.exe", "type.exe", "net.exe"
    , "dsquery.exe", "csvde.exe", "nbtstat.exe", "nltest.exe", "ntdsutil.exe", "adfind.exe", "nslookup.exe"
    , "procdump.exe", "whoami.exe", "wmic.exe", "mimikatz.exe", "tasklist.exe", "rubeus.exe"]);
DeviceProcessEvents
| where FileName has_any(SuspiciousFiles)
| project Timestamp, DeviceId, FileName, ProcessCommandLine, ReportId
| sort by DeviceId asc, Timestamp asc
| scan with_match_id=funnel_id declare(Step:int, Delta:timespan, Duration:timespan, Files:dynamic, CommandLines:dynamic) with
(
    step s1: FileName in(SuspiciousFiles) 
        => Step = 1, Delta = timespan(0)
        , Duration = timespan(0)
        , Files = pack_array(FileName)
        , CommandLines = pack_array(ProcessCommandLine);
)
| summarize arg_max(Timestamp, ReportId, *) by funnel_id, DeviceId, Step

let TimePeriod = 5m;
let Threshold = 3;
let SuspiciousFiles = dynamic(["dir.exe", "ipconfig.exe", "systeminfo.exe", "ping.exe", "type.exe", "net.exe"
    , "dsquery.exe", "csvde.exe", "nbtstat.exe", "nltest.exe", "ntdsutil.exe", "adfind.exe", "nslookup.exe"
    , "procdump.exe", "whoami.exe", "wmic.exe", "mimikatz.exe", "tasklist.exe", "rubeus.exe"]);
DeviceProcessEvents
| where FileName has_any(SuspiciousFiles)
| project Timestamp, DeviceId, FileName, ProcessCommandLine, ReportId
| sort by DeviceId asc, Timestamp asc
| scan with_match_id=funnel_id declare(Step:int, Delta:timespan, Duration:timespan, Files:dynamic, CommandLines:dynamic) with
(
    step s1: FileName in(SuspiciousFiles) 
        => Step = 1, Delta = timespan(0)
        , Duration = timespan(0)
        , Files = pack_array(FileName)
        , CommandLines = pack_array(ProcessCommandLine);
    step s2: FileName in(SuspiciousFiles) 
        and Timestamp - s1.Timestamp <= TimePeriod 
        and DeviceId == s1.DeviceId 
        and ProcessCommandLine != s1.ProcessCommandLine => Step = 2
        , Delta = Timestamp - s1.Timestamp
        , Duration = Timestamp - s1.Timestamp
        , Files = pack_array(s1.FileName, FileName)
        , CommandLines = pack_array(s1.ProcessCommandLine, ProcessCommandLine);
    step s3: FileName in(SuspiciousFiles) and Timestamp - s2.Timestamp <= TimePeriod and DeviceId == s2.DeviceId and ProcessCommandLine != s1.ProcessCommandLine and ProcessCommandLine != s2.ProcessCommandLine => Step = 3, Delta = Timestamp - s2.Timestamp, Duration = Timestamp - s1.Timestamp, Files = pack_array(s1.FileName, s2.FileName, FileName), CommandLines = pack_array(s1.ProcessCommandLine, s2.ProcessCommandLine, ProcessCommandLine);
    step s4: FileName in(SuspiciousFiles) and Timestamp - s3.Timestamp <= TimePeriod and DeviceId == s3.DeviceId and ProcessCommandLine != s1.ProcessCommandLine and ProcessCommandLine != s2.ProcessCommandLine and ProcessCommandLine != s3.ProcessCommandLine => Step = 4, Delta = Timestamp - s3.Timestamp, Duration = Timestamp - s1.Timestamp, Files = pack_array(s1.FileName, s2.FileName, s3.FileName, FileName), CommandLines = pack_array(s1.ProcessCommandLine, s2.ProcessCommandLine, s3.ProcessCommandLine, ProcessCommandLine);
    step s5: FileName in(SuspiciousFiles) and Timestamp - s4.Timestamp <= TimePeriod and DeviceId == s4.DeviceId and ProcessCommandLine != s1.ProcessCommandLine and ProcessCommandLine != s2.ProcessCommandLine and ProcessCommandLine != s3.ProcessCommandLine and ProcessCommandLine != s4.ProcessCommandLine => Step = 5, Delta = Timestamp - s4.Timestamp, Duration = Timestamp - s1.Timestamp, Files = pack_array(s1.FileName, s2.FileName, s3.FileName, s4.FileName, FileName), CommandLines = pack_array(s1.ProcessCommandLine, s2.ProcessCommandLine, s3.ProcessCommandLine, s4.ProcessCommandLine, ProcessCommandLine);
)
| summarize arg_max(Timestamp, ReportId, *) by funnel_id, DeviceId, Step

let TimePeriod = 5m;
let Threshold = 3;
let SuspiciousFiles = dynamic(["dir.exe"
    , "ipconfig.exe"
    , "systeminfo.exe"
    , "ping.exe"
    , "type.exe"
    , "net.exe"
    , "dsquery.exe"
    , "csvde.exe"
    , "nbtstat.exe"
    , "nltest.exe"
    , "ntdsutil.exe"
    , "adfind.exe"
    , "nslookup.exe"
    , "procdump.exe"
    , "whoami.exe"
    , "wmic.exe"
    , "mimikatz.exe"
    , "tasklist.exe"
    , "rubeus.exe"
]);
let ExcludedCommands = dynamic(["wuauserv"
]);
DeviceProcessEvents
| where FileName has_any(SuspiciousFiles)
| where not(ProcessCommandLine has_any(ExcludedCommands))
| where InitiatingProcessParentFileName != "MsSense.exe" and InitiatingProcessParentFileName != "SenseIR.exe" and InitiatingProcessFileName != "MsSense.exe"
| project Timestamp, DeviceId, FileName, ProcessCommandLine, ReportId
| sort by DeviceId asc, Timestamp asc
| scan with_match_id=funnel_id declare(Step:int, Delta:timespan, Duration:timespan, Files:dynamic, CommandLines:dynamic) with
(
    step s1: FileName in(SuspiciousFiles) => Step = 1, Delta = timespan(0), Duration = timespan(0), Files = pack_array(FileName), CommandLines = pack_array(ProcessCommandLine);
    step s2: FileName in(SuspiciousFiles) and Timestamp - s1.Timestamp <= TimePeriod and DeviceId == s1.DeviceId and ProcessCommandLine != s1.ProcessCommandLine => Step = 2, Delta = Timestamp - s1.Timestamp, Duration = Timestamp - s1.Timestamp, Files = pack_array(s1.FileName, FileName), CommandLines = pack_array(s1.ProcessCommandLine, ProcessCommandLine);
    step s3: FileName in(SuspiciousFiles) and Timestamp - s2.Timestamp <= TimePeriod and DeviceId == s2.DeviceId and ProcessCommandLine != s1.ProcessCommandLine and ProcessCommandLine != s2.ProcessCommandLine => Step = 3, Delta = Timestamp - s2.Timestamp, Duration = Timestamp - s1.Timestamp, Files = pack_array(s1.FileName, s2.FileName, FileName), CommandLines = pack_array(s1.ProcessCommandLine, s2.ProcessCommandLine, ProcessCommandLine);
    step s4: FileName in(SuspiciousFiles) and Timestamp - s3.Timestamp <= TimePeriod and DeviceId == s3.DeviceId and ProcessCommandLine != s1.ProcessCommandLine and ProcessCommandLine != s2.ProcessCommandLine and ProcessCommandLine != s3.ProcessCommandLine => Step = 4, Delta = Timestamp - s3.Timestamp, Duration = Timestamp - s1.Timestamp, Files = pack_array(s1.FileName, s2.FileName, s3.FileName, FileName), CommandLines = pack_array(s1.ProcessCommandLine, s2.ProcessCommandLine, s3.ProcessCommandLine, ProcessCommandLine);
    step s5: FileName in(SuspiciousFiles) and Timestamp - s4.Timestamp <= TimePeriod and DeviceId == s4.DeviceId and ProcessCommandLine != s1.ProcessCommandLine and ProcessCommandLine != s2.ProcessCommandLine and ProcessCommandLine != s3.ProcessCommandLine and ProcessCommandLine != s4.ProcessCommandLine => Step = 5, Delta = Timestamp - s4.Timestamp, Duration = Timestamp - s1.Timestamp, Files = pack_array(s1.FileName, s2.FileName, s3.FileName, s4.FileName, FileName), CommandLines = pack_array(s1.ProcessCommandLine, s2.ProcessCommandLine, s3.ProcessCommandLine, s4.ProcessCommandLine, ProcessCommandLine);
)
| summarize arg_max(Timestamp, ReportId, *) by funnel_id, DeviceId, Step
| where Step >= Threshold
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sandyzeng.gitbook.io/kql/kql-quick-guide/need-to-learn-later/scan.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
