MedusaLocker: CMSTPLUA COM UAC Bypass — Detection
Detection material for the auto-elevated COM bypass MedusaLocker uses to reach high integrity without a consent prompt. Technique write-up: MedusaLocker_CMSTPLUA_UACBypass.
MITRE ATT&CK: T1548.002
Detection Indicators
| Indicator | Value |
|---|---|
CLSID (CMSTPLUA → ICMLuaUtil) |
{3E5FC7F9-9A51-4367-9063-A120244FBEC7} |
CLSID (ColorDataProxy → ICMLuaUtil) |
{D2E7041B-2927-42FB-8E9F-7CE93B6DC937} |
| Provider DLLs | cmlua.dll, colorui.dll |
| Moniker string | Elevation:Administrator!new: |
| Process artifact | dllhost.exe /Processid:{<clsid>} at High integrity |
| Discriminator | a High-integrity child of a Medium-integrity parent with no consent.exe in between |
The last row is the one that matters. The CLSIDs are fast to match and trivial to rotate; the
absence of consent.exe before a silent elevation is structural and survives the attacker
switching to a different auto-elevate object.
Log Sources
- Microsoft Defender XDR / Defender for Endpoint (
DeviceProcessEvents,DeviceEvents) - Sysmon EID 1 (process create), EID 7 (image load), EID 10 (process access)
- PowerShell Script Block Logging (EID 4104) for the script-based variants
- Windows Security 4688 with command line inclusion, where Sysmon is not deployed
Files
| File | Contents |
|---|---|
sigma_cmstplua_uac_bypass.yml |
5 Sigma rules — surrogate launch, elevated child, LOLBin backstop, moniker in script, provider DLL load |
cmstplua_uac_bypass.yar |
4 YARA rules — file, native PE, script and memory scanning |
hunting_queries.md |
KQL, SPL and EQL hunts, plus the Sysmon config needed to feed them |
Detection Engineering with Sigma
Five rules, layered from most specific to most durable.
| Rule | Level | Catches |
|---|---|---|
| COM Surrogate Launched for an Auto-Elevating CLSID | high | the setup step — dllhost.exe spawned for a known-abused CLSID |
| Child Process Spawned by Auto-Elevating COM Surrogate | critical | the payload itself, as a child of that surrogate |
| Suspicious Interpreter or LOLBin Spawned by COM Surrogate | high | the same shape for CLSIDs not on the list |
| Elevation Moniker String in Script or Command Line | critical | PowerShell / JScript / C# variants, via script block logs |
| ICMLuaUtil Provider DLL Loaded by Unexpected Process | medium | in-process variants and provider hijacks — hunt input, not an alert |
The highest-fidelity signal is the second: ICMLuaUtil::ShellExec runs the payload as a child
of the surrogate, so the parent command line still carries the CLSID.
detection:
selection:
ParentImage|endswith: '\dllhost.exe'
ParentCommandLine|contains:
- '3E5FC7F9-9A51-4367-9063-A120244FBEC7'
- 'D2E7041B-2927-42FB-8E9F-7CE93B6DC937'
condition: selection
level: critical
Detection Engineering with Defender XDR
The CLSID-agnostic hunt — a silent elevation with no consent prompt in the preceding 30 seconds. This is the one to weight alerting toward.
let window = 30s;
let elevated =
DeviceProcessEvents
| where ProcessIntegrityLevel in ("High", "System")
| where InitiatingProcessIntegrityLevel == "Medium"
| project Timestamp, DeviceId, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName,
InitiatingProcessCommandLine, ProcessId;
let consents =
DeviceProcessEvents
| where FileName =~ "consent.exe"
| project DeviceId, ConsentTime = Timestamp;
elevated
| join kind=leftouter consents on DeviceId
| summarize ConsentInWindow = countif(ConsentTime between ((Timestamp - window) .. Timestamp))
by DeviceId, ProcessId, Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
| where ConsentInWindow == 0
| order by Timestamp desc
The remaining queries — surrogate launch, elevated child, moniker in script content, plus the
Splunk and Elastic equivalents — are in hunting_queries.md.
Detection Engineering with YARA
Four rules covering file, native PE, script and memory scanning. The CLSIDs are matched in
three forms: ASCII, UTF-16LE, and the little-endian binary GUID a compiler emits into
.rdata, so a sample that never stores the CLSID as text is still caught.
{3E5FC7F9-9A51-4367-9063-A120244FBEC7}
-> F9 C7 5F 3E 51 9A 67 43 90 63 A1 20 24 4F BE C7
UACBypass_ICMLuaUtil_Memory is deliberately loose and is meant for process dumps only, not a
filesystem sweep.
Validation and tuning
Baseline first. Query 30 days of dllhost.exe command lines and allow-list the CLSIDs your
estate legitimately surrogates. On most fleets these never appear, which makes the CLSID rules
near zero-noise. Environments deploying Connection Manager profiles through cmstp.exe are the
main exception.
Test with vetted tooling. Atomic Red Team T1548.002 has sandboxed, documented atomics for this technique. Use those to confirm the rules fire rather than authoring a bypass.
Known blind spot. If the payload is delivered in-process — for example by writing a
registry value through ICMLuaUtil::SetRegistryStringValue and letting another process consume
it — there is no elevated child to catch. The provider-DLL-load rule and registry monitoring
cover that path.
Disclaimer
For educational purposes only!!!