System DLL loaded from outside the Windows system directories
Matches Sysmon Module Load where the loaded module carries the file name of a library that Windows ships only under its own system directories, yet the path it was loaded from is not System32, SysWOW64 or WinSxS. That name-plus- location mismatch is the shared shape of the three abuses in this technique — a planted copy next to a trusted executable (side-loading), a copy earlier in the search order than the real one (search-order hijacking), and a file created where the loader looked and found nothing (phantom hijacking). The DLL names are authored for this rule, chosen as libraries Windows itself installs only under its system directories — several of them (version.dll, dbgcore.dll) are nonetheless carried privately by legitimate applications, which is the first false positive below. MITRE's AllowedDllPaths and ProcessAllowList knobs are the intended place for an estate to record its own exceptions, and the path filter here is the minimum viable version of the first. That filter is anchored on the drive-root colon (':\Windows\System32\') rather than on the bare directory name, because a bare '\Windows\System32\' substring is cleared by any lookalike directory an adversary can create in a writable location, and the filter is the only discriminator this rule has. This is deliberately not the same test as the T1129 rule already in this corpus, which keys on temp, roaming and UNC paths together with a non-Valid signature: a DLL planted inside a properly signed application folder in Program Files passes that test and fails this one. What this rule cannot see is a hijack that replaces the real file in place under System32, since the path filter clears it, and it says nothing about whether the module was malicious — only about where it came from. Requires Sysmon with Module Load enabled; the event is absent from a default Windows install and is among the first trimmed in shipped Sysmon configurations for volume, so an empty result means blind rather than clean. UNVERIFIED AS AUTHORED — derived from MITRE ATT&CK DET0201, not hand-written and not tested by its author. Any lab result is on this rule's own page.Full descriptionShow less
The detection
The 4 SIEM queries below are previews produced by Siemphony’s own translator, not pySigma, and none has been executed against a real backend — review before you deploy.
detection.yml
Sentinel · KQL
Run this as a search.
DeviceImageLoadEvents| where ((FolderPath endswith "\\version.dll" or FolderPath endswith "\\wtsapi32.dll" or FolderPath endswith "\\dbgcore.dll" or FolderPath endswith "\\secur32.dll" or FolderPath endswith "\\sspicli.dll" or FolderPath endswith "\\userenv.dll" or FolderPath endswith "\\profapi.dll" or FolderPath endswith "\\cryptsp.dll" or FolderPath endswith "\\dwmapi.dll" or FolderPath endswith "\\uxtheme.dll" or FolderPath endswith "\\propsys.dll" or FolderPath endswith "\\edputil.dll" or FolderPath endswith "\\textinputframework.dll" or FolderPath endswith "\\winhttp.dll" or FolderPath endswith "\\wininet.dll" or FolderPath endswith "\\apphelp.dll") and not ((FolderPath contains ":\\Windows\\System32\\" or FolderPath contains ":\\Windows\\SysWOW64\\" or FolderPath contains ":\\Windows\\WinSxS\\")))
Splunk · SPL
Run this as a search.
index=* ((ImageLoaded="*\\version.dll" OR ImageLoaded="*\\wtsapi32.dll" OR ImageLoaded="*\\dbgcore.dll" OR ImageLoaded="*\\secur32.dll" OR ImageLoaded="*\\sspicli.dll" OR ImageLoaded="*\\userenv.dll" OR ImageLoaded="*\\profapi.dll" OR ImageLoaded="*\\cryptsp.dll" OR ImageLoaded="*\\dwmapi.dll" OR ImageLoaded="*\\uxtheme.dll" OR ImageLoaded="*\\propsys.dll" OR ImageLoaded="*\\edputil.dll" OR ImageLoaded="*\\textinputframework.dll" OR ImageLoaded="*\\winhttp.dll" OR ImageLoaded="*\\wininet.dll" OR ImageLoaded="*\\apphelp.dll") AND NOT ((ImageLoaded="*:\\Windows\\System32\\*" OR ImageLoaded="*:\\Windows\\SysWOW64\\*" OR ImageLoaded="*:\\Windows\\WinSxS\\*")))Elastic · ES|QL
Run this as a search.
FROM logs-*| WHERE ((TO_LOWER(file.path) LIKE "*\\\\version.dll" OR TO_LOWER(file.path) LIKE "*\\\\wtsapi32.dll" OR TO_LOWER(file.path) LIKE "*\\\\dbgcore.dll" OR TO_LOWER(file.path) LIKE "*\\\\secur32.dll" OR TO_LOWER(file.path) LIKE "*\\\\sspicli.dll" OR TO_LOWER(file.path) LIKE "*\\\\userenv.dll" OR TO_LOWER(file.path) LIKE "*\\\\profapi.dll" OR TO_LOWER(file.path) LIKE "*\\\\cryptsp.dll" OR TO_LOWER(file.path) LIKE "*\\\\dwmapi.dll" OR TO_LOWER(file.path) LIKE "*\\\\uxtheme.dll" OR TO_LOWER(file.path) LIKE "*\\\\propsys.dll" OR TO_LOWER(file.path) LIKE "*\\\\edputil.dll" OR TO_LOWER(file.path) LIKE "*\\\\textinputframework.dll" OR TO_LOWER(file.path) LIKE "*\\\\winhttp.dll" OR TO_LOWER(file.path) LIKE "*\\\\wininet.dll" OR TO_LOWER(file.path) LIKE "*\\\\apphelp.dll") AND NOT ((TO_LOWER(file.path) LIKE "*:\\\\windows\\\\system32\\\\*" OR TO_LOWER(file.path) LIKE "*:\\\\windows\\\\syswow64\\\\*" OR TO_LOWER(file.path) LIKE "*:\\\\windows\\\\winsxs\\\\*")))
Wazuh · XML rule
Deploy to your manager — this is a rule, not a search.
<group name="sigma,windows,image_load,"> <!-- Rule ids must be unique on your manager; 100000+ is the user range. --> <rule id="100000" level="7"> <!-- Set <if_sid> to the decoder/base rule for windows so this only evaluates relevant events. --> <field name="ImageLoaded" type="pcre2">(?i)(\\version\.dll$|\\wtsapi32\.dll$|\\dbgcore\.dll$|\\secur32\.dll$|\\sspicli\.dll$|\\userenv\.dll$|\\profapi\.dll$|\\cryptsp\.dll$|\\dwmapi\.dll$|\\uxtheme\.dll$|\\propsys\.dll$|\\edputil\.dll$|\\textinputframework\.dll$|\\winhttp\.dll$|\\wininet\.dll$|\\apphelp\.dll$)</field> <field name="ImageLoaded" negate="yes" type="pcre2">(?i)(:\\Windows\\System32\\|:\\Windows\\SysWOW64\\|:\\Windows\\WinSxS\\)</field> <description>System DLL loaded from outside the Windows system directories</description> <mitre> <id>T1574.001</id> </mitre> </rule></group>
Verdicts · reactions · comments
Community
Verdicts from engineers who actually deployed it, and the conversation around it.
Nobody has run this in a real environment and said what happened.
Verdicts from engineers who deployed it
0 castNo verdicts reported yet. The first one is worth more than the tenth — say what you ran it against.
Log in to report a verdict.
Log in to join the discussion.
1 thread
@owen-mackay
version.dll is the highest-value entry in that list and also the noisiest — every crash reporter on earth ships a private copy next to its own binary. If you can only afford one tuning pass, allowlist by the loading process's signer rather than by path. The path list grows forever and each addition is a hole; the signer list converges after about a week.
@tomas-eriksen
Agreed. One thing I checked expecting to find a gap and did not: the WinSxS filter is a `contains`, so it also covers the servicing stack loading out of a WinSxS temp directory mid-patch. Tighten that to a `startswith` and you will page the on-call every patch window. Leaving it broad looks sloppy and is actually the correct choice.