Renamed System And Third Party Binaries With Signature Context
Query
// Renamed binaries: Python, command interpreters, third-party software, LOLBAS
// Detects processes whose executed file name differs from the PE OriginalFileName
// and enriches them with signature information from DeviceFileCertificateInfo.
let Lookback = 24h;
// Certificate data can arrive later than the process event, so a larger window is used
let CertLookback = 30d;
let CommandInterpreterNames = dynamic([
"bash.exe", "cmd.exe", "powershell.exe", "powershell_ise.exe",
"pwsh.exe", "pwsh.dll", "sh.exe",
"windowsterminal.exe", "wsl.exe", "wt.exe"
]);
// Covers psexec.exe, psexec64.exe, psexec64a.exe and similar
let CommandInterpreterWildcardRegex = @"^psexec.*\.(?:exe|c)$";
let ThirdPartyNames = dynamic([
"7z.exe", "7zg.exe", "7zfm.exe", "7za.exe",
"rar.exe", "unrar.exe", "peazip.exe", "anydesk.exe",
"tv_w32.exe", "tv_x64.exe", "ateraagent.exe", "srserver.exe",
"splashtopstreamer.exe", "lmiguardiansvc.exe", "logmein.exe",
"basupsrvc.exe", "tcclient.exe", "action1_agent.exe",
"rutserv.exe", "rfusclient.exe", "netscan.exe", "ipscan.exe",
"processhacker.exe", "systeminformer.exe", "rclone.exe",
"plink.exe", "mobaxterm.exe", "ngrok.exe", "cloudflared.exe",
"chisel.exe", "webbrowserpassview.exe", "mailpv.exe",
"autoit3.exe", "aut2exe.exe"
]);
let ThirdPartyWildcardRegex =
@"^(?:winrar.*|teamviewer.*|screenconnect.*|advanced_ip_scanner.*|advanced_port_scanner.*|adfind.*|winscp.*|putty.*)\.exe$";
let LolbasNames = dynamic([
"acccheckconsole.exe", "addinutil.exe", "adplus.exe",
"agentexecutor.exe", "appcert.exe", "appinstaller.exe",
"appvlp.exe", "aspnet_compiler.exe", "at.exe", "atbroker.exe",
"bitsadmin.exe", "cdb.exe", "certoc.exe", "certreq.exe",
"certutil.exe", "cmdkey.exe", "cmdl32.exe", "cmstp.exe",
"colorcpl.exe", "conhost.exe", "control.exe", "csc.exe",
"cscript.exe", "csi.exe", "curl.exe", "customshellhost.exe",
"datasvcutil.exe", "desktopimgdownldr.exe",
"devicecredentialdeployment.exe", "devinit.exe",
"devtoolslauncher.exe", "dfsvc.exe", "diantz.exe",
"diskshadow.exe", "dnscmd.exe", "dotnet.exe", "dsdbutil.exe",
"dumpminitool.exe", "dxcap.exe", "esentutl.exe",
"eventvwr.exe", "excel.exe", "expand.exe", "extexport.exe",
"extrac32.exe", "findstr.exe", "finger.exe", "fltmc.exe",
"forfiles.exe", "fsi.exe", "fsianycpu.exe", "fsutil.exe",
"ftp.exe", "gfxdownloadwrapper.exe", "gpscript.exe", "hh.exe",
"ie4uinit.exe", "iediagcmd.exe", "ieexec.exe", "ilasm.exe",
"imewdbld.exe", "infdefaultinstall.exe", "installutil.exe",
"jsc.exe", "ldifde.exe", "makecab.exe", "manage-bde.wsf",
"mavinject.exe", "mftrace.exe",
"microsoft.nodejstools.pressanykey.exe",
"microsoft.workflow.compiler.exe", "mmc.exe", "msaccess.exe",
"msbuild.exe", "msconfig.exe", "msdeploy.exe", "msdt.exe",
"mshta.exe", "msiexec.exe", "msohtmed.exe", "mspub.exe",
"netsh.exe", "ntdsutil.exe", "odbcconf.exe",
"offlinescannershell.exe", "pcalua.exe", "pcwrun.exe",
"pktmon.exe", "pnputil.exe", "powerpnt.exe",
"presentationhost.exe", "print.exe", "printbrm.exe",
"protocolhandler.exe", "provlaunch.exe", "psr.exe",
"rasautou.exe", "rdrleakdiag.exe", "reg.exe", "regasm.exe",
"regedit.exe", "regini.exe", "register-cimprovider.exe",
"regsvcs.exe", "regsvr32.exe", "replace.exe", "rpcping.exe",
"rundll32.exe", "runexehelper.exe", "runonce.exe", "sc.exe",
"schtasks.exe", "scriptrunner.exe", "setres.exe",
"settingsynchost.exe", "sqldumper.exe", "sqlps.exe",
"sqltoolsps.exe", "stordiag.exe", "syncappvpublishingserver.exe",
"tar.exe", "testwindowremoteagent.exe", "ttdinject.exe",
"tttracer.exe", "unregmp2.exe", "vbc.exe", "verclsid.exe",
"visualuiaverifynative.exe", "vsdiagnostics.exe", "vshadow.exe",
"vsiisexelauncher.exe", "vsjitdebugger.exe", "vsls-agent.exe",
"vstest.console.exe", "wab.exe", "wbadmin.exe", "wfc.exe",
"winproj.exe", "winword.exe", "wlrmdr.exe", "wmic.exe",
"workfolders.exe", "wscript.exe", "wsreset.exe", "wuauclt.exe",
"xwizard.exe"
]);
let PythonOriginalRegex =
@"^(?:py|pyw|python|pythonw|python32|python64|pythonw32|pythonw64|ipyw32|ipyw64|python3|pythonw3|python3\.\w+|pythonw3\.\w+)\.exe$";
let PythonAllowedNameRegex =
@"^(?:py|pyw|pip|pip3|python|pythonw|python32|python64|pythonw32|pythonw64|ipyw32|ipyw64|python3|pythonw3|python3\.\w+|pythonw3\.\w+|pip3\.\w+|idle3\.\w+)\.exe$";
// Exceptions as pairs "OriginalName|ExecutedName": they only apply to exactly this combination.
// Verify the pairs against your own data with the baseline query at the end.
let AllowedPairs = dynamic([
"excel.exe|excelcnv.exe",
"installutil.exe|installutil64.exe",
"vshadow.exe|vzshadow.exe",
"python.exe|dwagent.exe",
"python.exe|winutils.exe"
]);
// Original name unknown: move these into AllowedPairs after a baseline run and remove them here
let AllowedExecutedNameOnly = dynamic(["regwrite.exe", "protoc~1.exe"]);
// Determine candidates (cheap filters first, expensive regex operations afterwards)
let Candidates = materialize(
DeviceProcessEvents
| where Timestamp >= ago(Lookback)
| where ActionType == "ProcessCreated"
| where isnotempty(FileName) and isnotempty(ProcessVersionInfoOriginalFileName)
// Pre-filter: for the vast majority of events both names are identical (case-insensitive)
| where FileName !~ ProcessVersionInfoOriginalFileName
| extend
OriginalName = tolower(ProcessVersionInfoOriginalFileName),
ExecutedName = tolower(FileName)
| extend DetectionCategory = case(
OriginalName matches regex PythonOriginalRegex,
"Renamed Python",
OriginalName in (CommandInterpreterNames)
or OriginalName matches regex CommandInterpreterWildcardRegex,
"Renamed Command Interpreter",
OriginalName in (ThirdPartyNames)
or OriginalName matches regex ThirdPartyWildcardRegex,
"Renamed Third-Party Software",
OriginalName in (LolbasNames),
"Renamed LOLBAS",
""
)
| where isnotempty(DetectionCategory)
// PE metadata sometimes contains a source or DLL name
| extend ExpectedName = case(
OriginalName == "pwsh.dll", "pwsh.exe",
OriginalName matches regex @"^psexec.*\.c$",
replace_regex(OriginalName, @"\.c$", ".exe"),
OriginalName
)
| where ExecutedName != ExpectedName
// Accept regular PsExec architecture variants only for PsExec original metadata
| where not(
DetectionCategory == "Renamed Command Interpreter"
and OriginalName matches regex CommandInterpreterWildcardRegex
and ExecutedName in ("psexec.exe", "psexec64.exe", "psexec64a.exe")
)
// Regular Python launchers and tools, only within the Python category
| where not(
DetectionCategory == "Renamed Python"
and ExecutedName matches regex PythonAllowedNameRegex
)
// Exceptions bound to the combination of original and executed name
| extend Pair = strcat(OriginalName, "|", ExecutedName)
| where Pair !in (AllowedPairs)
| where ExecutedName !in (AllowedExecutedNameOnly)
| project-away Pair
);
// Load signature information only for the hashes found (small join set)
let CandidateHashes = Candidates
| where isnotempty(SHA1)
| distinct SHA1;
let CertInfo = DeviceFileCertificateInfo
| where Timestamp >= ago(CertLookback)
| where SHA1 in (CandidateHashes)
| summarize arg_max(Timestamp, IsSigned, IsTrusted, SignatureType, Signer, Issuer) by SHA1;
// Enrich and rate
Candidates
| join kind=leftouter CertInfo on SHA1
| extend SigningStatus = case(
isnull(IsSigned), "Unknown (no certificate data)",
IsSigned == false, "Unsigned",
IsSigned == true and IsTrusted == false, "Signed, not trusted",
"Signed and trusted"
)
// The signature is context, not a filter: LOLBAS binaries are signed by Microsoft,
// so a renamed certutil.exe stays suspicious even when it is signed.
| extend Severity = case(
SigningStatus in ("Unsigned", "Signed, not trusted"), "High",
SigningStatus startswith "Unknown", "Medium",
DetectionCategory in ("Renamed LOLBAS", "Renamed Command Interpreter"), "Medium",
"Low"
)
| project
Timestamp,
DeviceId,
DeviceName,
ReportId,
Severity,
DetectionCategory,
SigningStatus,
Signer,
Issuer,
SignatureType,
FileName,
ProcessVersionInfoOriginalFileName,
ExpectedName,
FolderPath,
ProcessCommandLine,
ProcessId,
AccountDomain,
AccountName,
AccountSid,
ProcessIntegrityLevel,
ProcessTokenElevation,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
InitiatingProcessFolderPath,
InitiatingProcessAccountName,
SHA1,
SHA256
| extend SeverityRank = case(Severity == "High", 1, Severity == "Medium", 2, 3)
| order by SeverityRank asc, Timestamp desc
| project-away SeverityRank
// Baseline query (run separately with a lookback of e.g. 30d to maintain AllowedPairs):
// Use the same query up to "| where ExecutedName !in (AllowedExecutedNameOnly)" without the exceptions, then:
// | summarize Events = count(), Devices = dcount(DeviceId)
// by DetectionCategory, OriginalName, ExecutedName
// | order by Events descAbout this query
Explanation
This query is designed to detect suspicious process creations on devices monitored by Microsoft Defender for Endpoint. Specifically, it looks for instances where the name of an executed file differs from its original name as stored in the file's metadata. This can indicate that an attacker has renamed a legitimate utility to avoid detection.
Key Points:
-
Purpose: The query identifies processes where the executed file name does not match the original file name in the metadata. This is a common tactic used by attackers to disguise malicious activity by renaming legitimate tools.
-
Categories: The query classifies these mismatches into four categories:
- Renamed Python: Python executables running under a different name.
- Renamed Command Interpreter: Command interpreters like
cmd.exeorpowershell.exerunning under a different name. - Renamed Third-Party Software: Includes remote access tools, archivers, and other third-party software.
- Renamed LOLBAS: Living-off-the-land binaries and scripts (LOLBAS) that are renamed.
-
Efficiency: The query uses an initial filter to quickly eliminate most events where the file names match, before applying more complex checks like regex operations.
-
Exceptions: Known legitimate name variations are excluded from detection. These exceptions are specific to exact combinations of original and executed names.
-
Signature Enrichment: The query enriches the results with signature information to determine if the file is signed and trusted. This helps assess the severity of the detection:
- High Severity: Unsigned or untrusted files.
- Medium Severity: Files with missing certificate data or signed LOLBAS/interpreters.
- Low Severity: All other cases.
-
Lookback Periods: The query uses a 24-hour lookback for process events and a 30-day lookback for certificate data, as certificate information may arrive later than the process event.
-
Output: The results include detailed information about the detected processes, such as device details, file names, paths, command lines, and account information. The results are sorted by severity and timestamp.
-
Baseline Query: A separate baseline query can be run to maintain the list of allowed name pairs, ensuring that legitimate variations are not flagged as suspicious.
Overall, this query helps security teams identify potentially malicious activity by detecting renamed binaries and assessing their trustworthiness through signature information.