Detection rules › Kusto

Suspicious MSC File Launched

Group by
FolderPath, MscFile
Author
FalconForce
Source
github.com/FalconForceTeam/FalconFriday

The query searches for suspicious MSC files that are launched on the system. The following types of suspicious files are detected: MSC files downloaded by web browsers, MSC files in the Downloads folder, MSC files extracted from ZIP files, and MSC files with Mark Of The Web (MOTW).

MITRE ATT&CK coverage

References

Event coverage

Rule body kusto

let timeframe = 2*1h;
let RegexValidateTempZipPath = @"((?i)[^=|\/]*?AppData\\Local\\Temp\\(7z.........\\|wz....\\|Temp\d{1,3}_\w+)\b[^( ;)|]*)";
let MscRenamedFromCrDownload=(
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed"
    | where FileName endswith ".msc"
    | where PreviousFileName endswith ".crdownload"
    | extend SuspiciousReason="MSC file downloaded by web browser."
);
let MscWrittenByBrowser=(
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where InitiatingProcessFileName in~ ("chrome.exe", "msedge.exe", "brave.exe", "opera.exe", "vivaldi.exe", "iexplore.exe", "msedgewebview2.exe", "firefox.exe")
    | extend SuspiciousReason="MSC file downloaded by web browser."
);
let MscInDownloadsFolder=(
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where FolderPath contains @"\downloads\"
    | extend SuspiciousReason="MSC file downloaded by web browser."
);
let MscDecompressed=(
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where InitiatingProcessFileName in~ ("7zfm.exe", "7zg.exe", "7z.exe", "winzip64.exe", "winrar.exe", "winzip.exe")
    or FolderPath matches regex RegexValidateTempZipPath
    or FolderPath contains @".zip\"
    | extend SuspiciousReason="MSC file extracted from zip file."
);
let MscMOTW=(
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where isnotempty(FileOriginUrl)
    | extend SuspiciousReason="MSC file with Mark Of The Web (MOTW)."
);
let SuspiciousMscFiles=(
    union MscRenamedFromCrDownload, MscWrittenByBrowser, MscInDownloadsFolder, MscDecompressed, MscMOTW
    | distinct FolderPath=tolower(FolderPath), DeviceId, FileOriginUrl, MscSHA1=SHA1, SuspiciousReason, MscCreatedBy=InitiatingProcessFolderPath, MscCreatedByCommandLine=InitiatingProcessCommandLine
);
DeviceProcessEvents
| where ingestion_time() >= ago(timeframe)
| where ActionType == "ProcessCreated"
| where FileName =~ "mmc.exe"
| extend ParsedCommandLine=parse_command_line(ProcessCommandLine, "windows")
// Look for process creations of mmc.exe where the .msc file is on the command-line, indicating that the user clicked on the .msc file.
| where tostring(ParsedCommandLine) contains ".msc"
// When a .msc file is opened in MMC, the file path is passed as an argument to MMC.
// Based on testing this is the first argument in the command line. In some cases a command-line switch /32 is passed as the first argument
// and the file path is the second argument. This is handled by the iif statement below.
| extend MscFile=ParsedCommandLine[1]
| extend MscFile=iif(MscFile startswith "/", ParsedCommandLine[2], MscFile)
| extend MscFile=tolower(MscFile)
| lookup kind=inner SuspiciousMscFiles on DeviceId, $left.MscFile == $right.FolderPath
| project-reorder Timestamp, DeviceId, DeviceName, SuspiciousReason, MscFile,  MscCreatedBy, MscCreatedByCommandLine, MscSHA1
// Begin environment-specific filter.
// End environment-specific filter.

Stages and Predicates

Parameters

let timeframe = 2*1h;

Let binding: RegexValidateTempZipPath

let RegexValidateTempZipPath = @"((?i)[^=|\/]*?AppData\\Local\\Temp\\(7z.........\\|wz....\\|Temp\d{1,3}_\w+)\b[^( ;)|]*)";

Let binding: MscRenamedFromCrDownload

let MscRenamedFromCrDownload = (
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed"
    | where FileName endswith ".msc"
    | where PreviousFileName endswith ".crdownload"
    | extend SuspiciousReason="MSC file downloaded by web browser."
);

Derived from timeframe.

Let binding: MscWrittenByBrowser

let MscWrittenByBrowser = (
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where InitiatingProcessFileName in~ ("chrome.exe", "msedge.exe", "brave.exe", "opera.exe", "vivaldi.exe", "iexplore.exe", "msedgewebview2.exe", "firefox.exe")
    | extend SuspiciousReason="MSC file downloaded by web browser."
);

Derived from timeframe.

Let binding: MscInDownloadsFolder

let MscInDownloadsFolder = (
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where FolderPath contains @"\downloads\"
    | extend SuspiciousReason="MSC file downloaded by web browser."
);

Derived from timeframe.

Let binding: MscDecompressed

let MscDecompressed = (
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where InitiatingProcessFileName in~ ("7zfm.exe", "7zg.exe", "7z.exe", "winzip64.exe", "winrar.exe", "winzip.exe")
    or FolderPath matches regex RegexValidateTempZipPath
    or FolderPath contains @".zip\"
    | extend SuspiciousReason="MSC file extracted from zip file."
);

Derived from timeframe, RegexValidateTempZipPath.

Let binding: MscMOTW

let MscMOTW = (
    DeviceFileEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "FileRenamed" or ActionType == "FileCreated"
    | where FileName endswith ".msc"
    | where isnotempty(FileOriginUrl)
    | extend SuspiciousReason="MSC file with Mark Of The Web (MOTW)."
);

Derived from timeframe.

Let binding: SuspiciousMscFiles

let SuspiciousMscFiles = (
    union MscRenamedFromCrDownload, MscWrittenByBrowser, MscInDownloadsFolder, MscDecompressed, MscMOTW
    | distinct FolderPath=tolower(FolderPath), DeviceId, FileOriginUrl, MscSHA1=SHA1, SuspiciousReason, MscCreatedBy=InitiatingProcessFolderPath, MscCreatedByCommandLine=InitiatingProcessCommandLine
);

Derived from MscRenamedFromCrDownload, MscWrittenByBrowser, MscInDownloadsFolder, MscDecompressed, MscMOTW.

Stage 1: source

DeviceProcessEvents

Stage 2: where

| where ingestion_time() >= ago(timeframe)

Stage 3: where

| where ActionType == "ProcessCreated"

Stage 4: where

| where FileName =~ "mmc.exe"

Stage 5: extend

| extend ParsedCommandLine=parse_command_line(ProcessCommandLine, "windows")

Stage 6: where

| where tostring(ParsedCommandLine) contains ".msc"

Stage 7: extend (3 consecutive steps)

| extend MscFile=ParsedCommandLine[1]
| extend MscFile=iif(MscFile startswith "/", ParsedCommandLine[2], MscFile)
| extend MscFile=tolower(MscFile)

Stage 8: kusto:lookup

| lookup kind=inner SuspiciousMscFiles on DeviceId, $left.MscFile == $right.FolderPath

Stage 9: project-reorder

| project-reorder Timestamp, DeviceId, DeviceName, SuspiciousReason, MscFile,  MscCreatedBy, MscCreatedByCommandLine, MscSHA1

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
ActionTypeeq
  • ProcessCreated transforms: cased corpus 10 (kusto 10)
FileNameeq
  • mmc.exe
ParsedCommandLinecontains
  • .msc transforms: tostring

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
ParsedCommandLineextend
MscFileextend