PAM Trust

Enumerating PAM trust

Enumerate if our current forest has any PAM trust with any other forest

Using the ADModule, we can simply run Get-ADTrust and look for a trust which has ForestTransitive set to True and SIDFilteringQuarantined set to False - this means that SID Filtering is disabled.

Get-ADTrust -Filter {(ForestTransitive -eq $True) -and (SIDFilteringQuarantined -eq $False)}

Enumerate if your current forest is managed by a bastion forest

Look for ForestTransitive set to True and SIDFilteringForestAware set to True. In this case, TrustAttributes is also a very good indicator. It is 0x00000400 (1024 in decimal) for PAM/PIM trust. Simplifying it, it is 1096 for PAM + External Trust + Forest Transitive.

Get-ADTrust -Filter * -Properties *

INSERT IMAGE

Enumerate the shadow security principals

Enumerate the members from the current (bastion) forest and privileges in the user/production forest.

Run with Active Directory module Get-ADObject

Get-ADObject -SearchBase ("CN=Shadow Principal Configuration,CN=Services," + (Get-ADRootDSE).configurationNamingContext) -Filter * -Properties * | select Name,member,msDS-ShadowPrincipalSid | fl

Please note that if Kerberos AES Encryption is not enabled for the PAM trust, we need to add the machines of existing forest in WSMan TrustedHosts and use '-Authentication Negotiate' option with PowerShell remoting cmdlets.

Add user to shadow security principal

Adding user oneliner

Set-ADObject -Identity "CN=infraforest-ShadowEnterpriseAdmin,CN=Shadow Principal Configuration,CN=Services,CN=Configuration,DC=gcbtech,DC=local" -Add @{'member'="<TTL=3600,CN=exam user,CN=Users,DC=gcbtech,DC=local>"}

Import below script and execute below command.

Add-ADShadowGroupMember -GroupNameValue "accforest-ShadowEnterpriseAdmin" -MemberNameValue "syslogagent" -TypeValue user -TTLValue "3600" -ADModulePATH "C:\Windows\temp\AD\ADModule\ActiveDirectory\ActiveDirectory.psd1"

Add-ADShadowGroupMember.ps1

function Add-ADShadowGroupMember {
    Param(
      [Parameter(Mandatory=$true,Position=1)]
        [string]$GroupNameValue,
      [Parameter(Mandatory=$true,Position=2)]
        [string]$MemberNameValue,
     [parameter(Mandatory=$true,Position=3)]
     [ValidateSet("user", "group")]
        [String]$TypeValue,
     [Parameter(Mandatory=$False,Position=4)]
        [string]$TTLValue,
     [Parameter(Mandatory=$False,Position=5)]
        [string]$ADModulePATH
    )
    <#
    .SYNOPSIS
    Add a new member in an existing AD ShadowGroup

    .DESCRIPTION
    Add a new member in an existing AD ShadowGroup. The member could be a user or a group but must be located in the same AD hosting the Shadow Group.
 
    .PARAMETER GroupNameValue
    Mandatory parameter
    -GroupNameValue string
    Provide Shadow Group name to be used in configuration partition of directory (cn=Shadow Principal Configuration,cn=Services...) (object to be searched only in the current AD)
     
    .PARAMETER MemberNameValue
    Mandatory parameter
    -MemberNameValue string
    Provide the name of user or group to be added in the "member" attribute of the AD Shadow Group (object to be searched only in the current AD)
     
    .PARAMETER MemberNameValue
    Mandatory parameter
    -TypeValue string (user or group)
    Provide the type of member to add (user or group) (object to be searched only in the current AD)
     
    .PARAMETER TTLValue
    Optional parameter
    -TTLValue string (time in second)
    Provide the TTL membership for the entry to be added (user or group). At the end of the TTL, the entry is removed automatically from the member attribute of the object.

    .PARAMETER ADModulePATH
    Optional parameter
    -ADModulePATH string (path to ADModule .psd1)
    Provide the path to the ActiveDirectory.psd1 file
 
    .EXAMPLE
    C:\PS> Add-ADShadowGroupMember -GroupNameValue "Shadow-Domain Admins" -MemberNameValue "Domain Admins" -TypeValue group
     
    .EXAMPLE
    C:\PS> Add-ADShadowGroupMember -GroupNameValue "Shadow-Domain Admins" -MemberNameValue "Super-Admin" -TypeValue user
     
    .EXAMPLE
    C:\PS> Add-ADShadowGroupMember -GroupNameValue "Shadow-Domain Admins" -MemberNameValue "Temp-Super-Admin" -TypeValue user -TTLValue "3600"

    .EXAMPLE
    C:\PS> Add-ADShadowGroupMember -GroupNameValue "accforest-ShadowEnterpriseAdmin" -MemberNameValue "syslogagent" -TypeValue user -TTLValue "3600" -ADModulePATH "C:\Windows\temp\AD\ADModule\ActiveDirectory\ActiveDirectory.psd1"
    #>
	If ($ADModulePATH) {
        try {
	        import-module $ADModulePATH
	    } catch {
	        Write-Host "Not able to load active directory module - KO"  -foregroundcolor "Red"
	        Write-Host "Please check RSAT is installed if you are running the script on A PC"  -foregroundcolor "Red"
	        write-host "Error Type: $($_.Exception.GetType().FullName)" -ForegroundColor "Yellow"
	        write-host "Error Message: $($_.Exception.Message)" -ForegroundColor "Yellow"
	        return 
	    }
    } Else {
        try {
	        import-module ActiveDirectory
	    } catch {
	        Write-Host "Not able to load active directory module - KO"  -foregroundcolor "Red"
	        Write-Host "Please check RSAT is installed if you are running the script on A PC"  -foregroundcolor "Red"
	        write-host "Error Type: $($_.Exception.GetType().FullName)" -ForegroundColor "Yellow"
	        write-host "Error Message: $($_.Exception.Message)" -ForegroundColor "Yellow"
	        return 
	    }
    }
    $CurrentConfigurationPartDN = ([ADSI]"LDAP://RootDSE").configurationNamingContext
    $ADPArtDN = ([ADSI]"LDAP://RootDSE").defaultNamingContext
    $ShadowGroupPath = "cn=Shadow Principal Configuration,cn=Services,$($CurrentConfigurationPartDN)"
    $CheckShadowObject = get-adobject -Filter "ObjectClass -eq 'msDS-ShadowPrincipal' -and Name -eq '$($GroupNameValue)'" -SearchBase "$($ShadowGroupPath)" -properties member
    $CheckShadowObjectDN = $CheckShadowObject.DistinguishedName | select-object
    If (-not $CheckShadowObject) {
        Write-Host "ShadowPrincipal group $($GroupNameValue) not found ! - KO"  -foregroundcolor "Red"
        return
    }
    try {
        $checkUserObject = get-adobject -Filter "ObjectClass -eq '$($TypeValue)' -and cn -eq '$($MemberNameValue)'" -SearchBase "$($ADPArtDN)" -SearchScope Subtree -properties *
        $checkUserObjectDN = $checkUserObject.DistinguishedName | select-object
    } catch {
        Write-Host "Not able to find $($MemberNameValue) in current AD - KO"  -foregroundcolor "Red"
        write-host "Error Type: $($_.Exception.GetType().FullName)" -ForegroundColor "Yellow"
        write-host "Error Message: $($_.Exception.Message)" -ForegroundColor "Yellow"
        return 
    }
    
    If ($TTLValue) {
        try {
            Set-ADObject -Identity "$($CheckShadowObjectDN)" -Add @{'member'="<TTL=$($TTLValue),$($checkUserObjectDN)>"}
        } catch {
            Write-Host "Not able to add $($MemberNameValue) to $($GroupNameValue) with TTL $($TTLValue) - KO"  -foregroundcolor "Red"
            write-host "Error Type: $($_.Exception.GetType().FullName)" -ForegroundColor "Yellow"
            write-host "Error Message: $($_.Exception.Message)" -ForegroundColor "Yellow"
            return 
        }
    } Else {
        try {
            Set-ADObject -Identity "$($CheckShadowObjectDN)" -Add @{'member'="$($checkUserObjectDN)"}
        } catch {
            Write-Host "Not able to add $($MemberNameValue) to $($GroupNameValue) - KO"  -foregroundcolor "Red"
            write-host "Error Type: $($_.Exception.GetType().FullName)" -ForegroundColor "Yellow"
            write-host "Error Message: $($_.Exception.Message)" -ForegroundColor "Yellow"
            return 
        }
    }
    $CheckObject = get-adobject -Filter "ObjectClass -eq 'msDS-ShadowPrincipal' -and Name -eq '$($GroupNameValue)'" -SearchBase "$($ShadowGroupPath)" -properties *
    $CheckObject
}

References

Last updated