I instrumented a lab Active Directory forest with Sysmon and Splunk, then hunted the most common identity attacks using BloodHound attack-path analysis. The detection logic flagged Pass-the-Hash attempts within two minutes and surfaced three service accounts exposed to Kerberoasting.

This writeup walks through the full engagement end to end: building the lab forest, deploying telemetry (Sysmon + Splunk Universal Forwarders), collecting attack-path data with SharpHound, writing detections for the four highest-value Kerberos and credential attacks, and validating every rule by executing the attacks myself with Rubeus and Mimikatz in the isolated environment.

The goal was not just to "run some tools" but to close the loop on a real hunt cycle: form a hypothesis from MITRE ATT&CK, collect the right telemetry, write a query, prove it fires on a simulated attack, and tune out false positives until the alert is trustworthy enough to page someone at 3 a.m.

Threat Model & MITRE ATT&CK Mapping

Active Directory is the identity backbone, which makes credential and ticket abuse the highest-impact post-compromise activity. Each hunt hypothesis maps to a specific ATT&CK sub-technique and a corresponding Sysmon/Splunk detection.

  • T1558.003 Kerberoasting, TGS-REP requests for SPN-bearing service accounts.
  • T1558.004 AS-REP Roasting, accounts without Kerberos pre-auth.
  • T1550.002 Pass-the-Hash, NTLM logons with anomalous logon type 9.
  • T1558.001 Golden Ticket, forged TGTs granting persistence as any user.

Why these four? They share a common trait: the attacker never needs to touch endpoint malware. Kerberoasting and AS-REP roasting abuse normal Kerberos ticket requests to extract crackable password material. Pass-the-Hash reuses a stolen NTLM hash without ever knowing the plaintext password. A Golden Ticket, forged with the KRBTGT hash, grants indefinite persistence as any user. All four show up in Windows Security event logs and Sysmon if you know which fields to look at.

Hunt assumptions. I assume the attacker already has a foothold as a standard domain user (phish, password spray, whatever, the initial access is out of scope). I also assume a mostly-AES environment: Server 2022 defaults to AES128/AES256 for Kerberos, so any RC4 ticket request is an anomaly worth investigating rather than background noise. Finally, I assume logs are the source of truth, which is why the telemetry layer is built and verified before a single detection is written.

The BloodHound graph below shows why this matters: a single phished user on a workstation can chain AdminTo, HasSession, and group-membership edges into a path that ends at Domain Admins. Hunting these attack classes is how you cut that path before it is walked.

Each hypothesis gets a measurable detection. For Kerberoasting: an unusual volume of RC4-encrypted service-ticket requests (event 4769, encryption type 0x17) from a single account. For AS-REP roasting: 4768 TGT requests with pre-authentication type 0. For Pass-the-Hash: logon type 9 (NewCredentials) events using the seclogo process, which is what Mimikatz sekurlsa::pth produces. For Golden Tickets: TGTs whose lifetime exceeds the domain maximum or service tickets with no corresponding 4768 from the same account.

Learning Objectives

  • Collect Active Directory attack data with SharpHound and import it into BloodHound.
  • Query BloodHound for shortest paths to Domain Admin.
  • Write Splunk detections for Kerberoasting (event 4769 with RC4).
  • Detect AS-REP roasting via event 4768 without pre-authentication.
  • Identify Pass-the-Hash activity from logon type 9 events.
  • Spot Golden Ticket use through anomalous TGT lifetime and encryption anomalies.

Environment & Prerequisites

Prerequisites

  • Windows Server 2022 domain controller and 2 domain-joined Windows 11 workstations (isolated Hyper-V lab, no internet route).
  • Sysmon with the SwiftOnSecurity configuration shipping to Splunk.
  • BloodHound with the SharpHound collector.
  • PowerShell remoting enabled for detection scripts.
  • A honeypot service account with a fake SPN to catch Kerberoasting attempts.
  • Written authorization: this lab attacks a lab domain (lab.local) only.

The lab runs on isolated Hyper-V VMs with no route to the internet or the production network. The domain is lab.local, functional level 2016, seeded with realistic noise: 40 user accounts, 8 service accounts, tiered OUs, and a scheduled task that generates background logons so the detections have real baseline traffic to compete against.

Deploy Sysmon with the SwiftOnSecurity config

Sysmon supplies the process, network, and process-access telemetry the Security log lacks, most importantly Event ID 10 (ProcessAccess), which catches tools opening a handle to lsass.exe. Install it on every DC and workstation with the community-hardened SwiftOnSecurity configuration:

Install Sysmon with the SwiftOnSecurity configuration

curl -o sysmonconfig.xml https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml
.\Sysmon64.exe -accepteula -i sysmonconfig.xml

Verify the config is loaded (expected output)

.\Sysmon64.exe -c
# Current configuration: schema version 4.90
# Hashing algorithms: SHA1,IMPHASH
# Network connection logging: enabled

Common mistake: forgetting -accepteula or running from a non-elevated prompt, Sysmon silently refuses to install. Verify with Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 5; an empty log means the service is not running.

Enable Kerberos audit policy on the DC

The Security-log events this lab depends on (4768, 4769) are not all on by default. I enabled them through Advanced Audit Policy on the Default Domain Controllers Policy rather than the legacy audit settings, because advanced categories are granular and don't get clobbered by basic policy:

Confirm the audit subcategories are enabled

auditpol /get /subcategory:"Kerberos Service Ticket Operations"
#   Success and Failure
auditpol /get /subcategory:"Kerberos Authentication Service"
#   Success and Failure

Without "Audit Kerberos Service Ticket Operations (Success)" there are simply no 4769 events to hunt with, this is the single most common reason a Kerberoasting detection "doesn't work".

Ship logs to Splunk

Each Windows host runs a Splunk Universal Forwarder. The inputs.conf below collects the Security log (where 4624/4625/4768/4769 live) and the Sysmon operational log into separate indexes so queries stay fast and field extractions stay clean:

Install the forwarder and point it at the indexer

msiexec /i splunkforwarder-9.2.1-x64-release.msi AGREETOLICENSE=Yes /quiet
.\splunk.exe add forward-server splunk.lab.local:9997 -auth admin:changeme

inputs.conf on each forwarder

[WinEventLog://Security]
index = wineventlog
disabled = false

[WinEventLog://Microsoft-Windows-Sysmon/Operational]
index = sysmon
disabled = false

On the Splunk side I installed the Splunk Add-on for Microsoft Windows so fields like EventCode, Account_Name, Logon_Type, and Ticket_Encryption_Type are extracted automatically at search time.

Verify time synchronization

Every correlation search in this lab assumes the DC, workstations, and Splunk indexer agree on the time. Kerberos rejects tickets with more than 5 minutes of skew, and a misconfigured workstation silently breaks both the attack simulations and the detection timelines:

Point all hosts at the domain hierarchy and verify

w32tm /config /syncfromflags:domhier /update
w32tm /resync
w32tm /query /status
# Source: DC01.lab.local   (must be the PDC emulator, not "Local CMOS Clock")

Build the Kerberoasting honeypot

The honeypot is a service account with a deliberately fake SPN, a 60-character random password (so it can never actually be cracked), and zero legitimate use. Any TGS request for it is malicious by definition, which makes it a near-zero-false-positive tripwire:

Create the honeypot account and register a fake SPN

New-ADUser -Name "svc_honeypot" -SamAccountName "svc_honeypot" `
  -AccountPassword (Read-Host -AsSecureString "Password") `
  -Enabled $true -Description "SQL service account - do not modify"
setspn -S HTTP/sql-prod01.lab.local svc_honeypot

Why it works: an attacker enumerating SPNs (via setspn -Q */* or PowerView's Get-DomainUser -SPN) sees a juicy "SQL" service account and roasts it. The moment anyone requests a ticket for that SPN, a 4769 fires that no legitimate process would ever generate. Verify the trap with one manual request from a test account before trusting the alert.

The Kerberoasting detection pipeline, from raw event to alert, looks like this:

Step-by-Step Execution

1. Collect attack paths with SharpHound

SharpHound enumerates group membership, local admins, active sessions, ACLs, and trusts over LDAP and SMB, then packages everything as a JSON zip for BloodHound. Running -c All captures every collection method including sessions, which are the key ingredient for finding HasSession lateral-movement edges.

.\SharpHound.exe -c All -zipfilename lab-collection

For a realistic picture I also ran a looped collection over a full workday, because session edges are transient, a collection at 9 a.m. misses the admin who logs on at 3 p.m.:

Looped session collection over two hours

Expected output:

.\SharpHound.exe -c Session,LoggedOn --loop --loopduration 02:00:00 -zipfilename lab-sessions

Expected collector output

2026-06-17T09:14:22 Starting LDAP enumeration for lab.local
2026-06-17T09:16:41 Resolved collection methods: Group, LocalAdmin, Session, ACL, Container, ObjectProps
2026-06-17T09:18:03 Finished enumeration. 3,412 objects collected.
2026-06-17T09:18:04 Zip archive written: 20260617091804_lab-collection.zip

Opsec note (useful for the blue-team mindset): SharpHound itself is noisy. The session collection opens SMB connections to every reachable computer, and the LDAP queries are enumerable. In a real assessment this traffic is detectable, which is exactly why I ran it here first: my own Sysmon logs now contain a known-good sample of what collection traffic looks like, useful as a detection reference later.

Common mistake: running SharpHound from a non-domain context (e.g., a local account or an off-domain box). The collector then authenticates to nothing and returns an empty zip. Verify domain context with whoami and LDAP reachability with nltest /dsgetdc:lab.local before collecting.

What this teaches: SharpHound turns raw AD objects into a graph, which is the only practical way to reason about attack paths at scale.

2. Import into BloodHound and query attack paths

Drag the zip into the BloodHound CE GUI (PostgreSQL-backed in current releases, not the legacy Neo4j build) and the graph materializes. The first question I always ask: who can reach Domain Admins, and how many hops does it take? The built-in "Shortest Paths to Domain Admins" prebuilt query answers it, but the raw Cypher is worth understanding:

Cypher: shortest paths from any user to Domain Admins

Expected output:

MATCH p=shortestPath((u:User)-[*1..]->(g:Group {name:"DOMAIN [email protected]"}))
RETURN p
LIMIT 100

Cypher: every Kerberoastable user and their SPNs

MATCH (u:User {hasspn:true})
WHERE NOT u.name STARTS WITH "KRBTGT"
RETURN u.name, u.serviceprincipalnames, u.pwdlastset

Expected output (illustrative)

u.name                  u.serviceprincipalnames        u.pwdlastset
[email protected]       [MSSQLSvc/db01.lab.local:1433] 2021-03-02
[email protected]    [CIFS/fs01.lab.local]          2020-11-19
[email protected]  [HTTP/sql-prod01.lab.local]    2026-06-10

The pwdlastset column is the money column: a service account whose password has not rotated in five years is a crack waiting to happen. In this lab the query surfaced 15+ distinct lateral-movement paths to Domain Admins, mostly through stale local-admin rights on the two workstations.

To make the hunt concrete I marked the assumed-breach user as owned in the GUI and asked what that one account controls outbound. This turns "15 paths exist" into "here is the exact path this phished user would walk":

Cypher: outbound control from one compromised user

MATCH p=shortestPath((u:User {name:"[email protected]"})-[*1..]->(g:Group {name:"DOMAIN [email protected]"}))
RETURN p

How to verify: spot-check one path manually. If the graph says jsmith -> AdminTo -> WS02, confirm on WS02 with net localgroup administrators. Graph edges come from real ACL and session data, if the spot-check fails, the collection method (not the graph) is suspect.

What this teaches: BloodHound queries reveal paths (not just vulnerabilities) an attacker can walk to Domain Admin.

3. Splunk detection for Kerberoasting (event 4769, RC4)

Legitimate Kerberos traffic in a modern domain uses AES (0x11 AES128, 0x12 AES256); 0x17 is RC4-HMAC. Attack tools like Rubeus and Impacket's GetUserSPNs request RC4 tickets because RC4 tickets are encrypted with the service account's NTLM hash, which is far cheaper to crack offline. Alerting on RC4 TGS requests for non-machine accounts is therefore a high-signal detector, high-signal, not proof: legacy clients and old service configurations also negotiate RC4, so the alert fires on the anomaly and the baseline comparison plus the honeypot SPN below decide whether it is an attack.

index=wineventlog EventCode=4769 Ticket_Encryption_Type=0x17 | stats count by Account_Name, Service_Name

Expected output:

Account_Name  Service_Name        count
labuser       MSSQLSvc/db01:1433  14
labuser       CIFS/fs01            9

In event 4769, Account_Name is the ticket requester (here the attacker's account, labuser) and Service_Name is the targeted SPN. Grouping by requester is what surfaces one account hammering many service tickets, the Kerberoasting pattern.

Reading the underlying event helps make sense of the field names Splunk extracts. A raw 4769 looks like this (trimmed):

Raw 4769 event (trimmed, illustrative)

A service ticket was requested.
  Account Name:        [email protected]
  Service Name:        MSSQLSvc/db01.lab.local:1433
  Ticket Encryption Type:  0x17
  Client Address:      ::ffff:10.0.0.22
  Failure Code:        0x0

To cut false positives I refined the search: exclude machine accounts (Account_Name!=*$), exclude known-good legacy apps after a tuning period, and spike-check against the account's own baseline:

Tuned Kerberoasting hunt with baseline comparison

index=wineventlog EventCode=4769 Ticket_Encryption_Type=0x17 Account_Name!=*$
| bin _time span=1h
| stats count as rc4_requests by _time, Account_Name
| eventstats avg(rc4_requests) as baseline stdev(rc4_requests) as sd by Account_Name
| where rc4_requests > baseline + 3*sd AND rc4_requests >= 5

The dedicated honeypot alert is a separate, trivially simple search, any hit is actionable:

Honeypot tripwire alert (fires on first touch)

index=wineventlog EventCode=4769 Service_Name="*sql-prod01*"
| table _time, Account_Name, Client_Address, Service_Name

Common mistake: alerting on all 4769s. Busy domains generate thousands per hour. The RC4 filter plus the machine-account exclusion is what turns noise into signal.

What this teaches: Kerberoasting is visible in the ticket request itself: RC4 encryption on a service ticket is the signal.

4. AS-REP roasting detection (event 4768, pre-auth type 0)

Accounts with "Do not require Kerberos preauthentication" set hand out an encrypted AS-REP to anyone who asks, no credentials needed. The detection watches for TGT requests where Pre_Authentication_Type is 0:

Hunt for pre-auth-disabled accounts being roasted

Expected output:

index=wineventlog EventCode=4768 Pre_Authentication_Type=0
| stats count by Account_Name, Client_Address
| where count >= 2

Before trusting this alert, enumerate which accounts even have the flag so you know your exposure:

Find accounts with pre-auth disabled

Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} -Properties DoesNotRequirePreAuth |
  Select-Object Name, SamAccountName

How to verify: in a healthy modern domain this list should be empty. Mine had one legacy account left over from the seeded noise, which immediately became both a finding and the test subject for validating the rule.

What this teaches: accounts that do not require pre-authentication let attackers request crackable AS-REP data with no password.

5. Pass-the-Hash detection (logon type 9, seclogo)

Mimikatz's sekurlsa::pth spawns a process with stolen NTLM credentials using the NewCredentials logon type (type 9) and the seclogo logon process. Type 9 is rare in normal operations, runas /netonly is the main legitimate source, so seclogo + type 9 from a non-admin workstation is a strong indicator:

index=wineventlog EventCode=4624 Logon_Type=9 Logon_Process=seclogo | table _time, Account_Name, Workstation

The second PtH layer is upstream of the logon: catching the credential theft itself. Mimikatz must open a handle to lsass.exe with access masks like 0x1010, which Sysmon Event ID 10 records:

Sysmon hunt for LSASS access by unsigned processes

Expected output:

index=sysmon EventCode=10 TargetImage="*lsass.exe"
  NOT SourceImage IN ("C:\\Windows\\System32\\*", "C:\\Program Files\\*")
| stats count by SourceImage, GrantedAccess, SourceUser

Expected output during a simulated dump

SourceImage                          GrantedAccess   SourceUser
C:\Users\labuser\Downloads\mimikatz.exe  0x1010      LAB\labuser

To make this page-worthy rather than a manual search, both queries became scheduled alerts. The saved-search configuration (search head savedsearches.conf) runs every minute and throttles repeat hits per account so one noisy host doesn't flood the queue:

Scheduled alert definition

[PtH - NewCredentials seclogo logon]
search = index=wineventlog EventCode=4624 Logon_Type=9 Logon_Process=seclogo
cron_schedule = * * * * *
dispatch.earliest_time = -2m@m
alert_type = always
alert.suppress = 1
alert.suppress.period = 3600s
alert.suppress.fields = Account_Name

Common mistake: copying the NOT SourceImage allowlist blindly. Build the exclusion list from your own environment's baseline (a week of | stats count by SourceImage), otherwise you either drown in AV/EDR noise or accidentally allowlist an attacker's renamed binary path.

What this teaches: logon type 9 with the seclogo process is the forensic fingerprint of a Pass-the-Hash logon.

6. Golden Ticket detection

A forged TGT has no legitimate 4768 issuance event from the KDC, which is the core of the log-based detection: correlate 4769 service-ticket requests against recent 4768 issuance for the same account. A separate endpoint check, ticket lifetime in klist output, catches the absurd lifetimes attackers assign (Rubeus defaults to 10 years); the lifetime is a property of the ticket, not of the 4769 event, so it is validated on the endpoint, not in Splunk.

Correlate 4769 requests against recent 4768 issuance

Expected output:

index=wineventlog EventCode=4769 Account_Name!=*$ earliest=-24h
| stats count as tgs_reqs by Account_Name
| join type=left Account_Name
  [search index=wineventlog EventCode=4768 | stats count as tgt_issued by Account_Name]
| where isnull(tgt_issued) OR tgt_issued = 0

Coverage caveat: this join is only as good as your 4768 coverage. A missing 4768 can also mean the issuing DC's logs rolled over or never forwarded, not necessarily a forged ticket. Run the correlation only after confirming every DC forwards Security logs to Splunk with retention covering the window, and treat isolated hits as leads to check against DC log availability before declaring a Golden Ticket.

Post-incident hygiene matters too: after any suspected KRBTGT compromise, follow Microsoft's documented process, reset the KRBTGT password twice (its password history is two deep), allowing full AD replication between the two resets, to invalidate all forged tickets:

Check KRBTGT password age

Get-ADUser krbtgt -Properties PasswordLastSet | Select-Object Name, PasswordLastSet

How to verify: a PasswordLastSet older than your other privileged credentials is a finding in itself. In the lab I reset it twice and confirmed with Rubeus klist that previously forged tickets were rejected afterwards.

What this teaches: Golden Tickets betray themselves through missing KDC issuance events and impossible ticket lifetimes.

How It Works

Kerberos authenticates users with tickets, and several ticket operations are attacker-abusable. Kerberoasting requests a service ticket for an account with a service principal name; the ticket is encrypted with the account's password hash, so any authenticated user can request it and crack it offline. The defense is detection (event 4769 with RC4) plus remediation (long random passwords, AES-only, managed service accounts).

Pass-the-Hash abuses NTLM: the hash itself is the credential, so stealing it from LSASS memory is equivalent to stealing the password. It shows up as network logons (type 3) or explicit-credential logons (type 9 via seclogo) from unexpected workstations. Golden Tickets go further: with the KRBTGT hash, an attacker forges ticket-granting tickets with arbitrary lifetime and group membership, which is why KRBTGT must be rotated twice after a suspected compromise.

BloodHound models AD as a graph of users, groups, computers, and the edges between them (member-of, admin-to, has-session). Attack path analysis asks which edges connect an owned principal to Domain Admin, turning a sprawling directory into a prioritized list of chokepoints to fix. Threat hunting here means looking for the techniques before the alert fires: honeypot SPNs, baseline deviations in 4769 volume, and impossible logon patterns.

Validation & Testing

Run authorized Rubeus/Mimikatz simulations in the isolated lab to generate Kerberoasting and PtH telemetry, then confirm the Splunk searches and honeypot SPN both fire. Pass criteria: PtH detected within 2 minutes and the honeypot account triggers on first TGS request (alt text: Splunk alert timeline correlating simulated attack with detection).

Simulate Kerberoasting with Rubeus

From a domain-joined workstation as a standard user, request RC4 tickets for every SPN-bearing account:

Roast all roastable accounts

.\Rubeus.exe kerberoast /rc4opsec /nowrap

Expected Rubeus output (truncated, illustrative)

[*] Action: Kerberoasting
[*] Found 3 users with SPNs set
[*] SamAccountName         : svc_sql
[*] DistinguishedName      : CN=svc_sql,OU=Service Accounts,DC=lab,DC=local
[*] Hash                   : $krb5tgs$23$*svc_sql$lab.local$MSSQLSvc/db01*$A1B2C3...

Simulate Pass-the-Hash with Mimikatz

Spawn a process with a stolen NTLM hash

mimikatz # sekurlsa::pth /user:svc_backup /domain:lab.local /ntlm:5fbc3d5fec8206a30f4b6c473d68ae76 /run:cmd.exe

Within seconds the 4624 type-9 seclogo event hits the Security log, the forwarder ships it, and the Splunk alert (scheduled every 60 seconds) fires. Measured end-to-end detection time across five runs: 45 to 110 seconds, comfortably under the 2-minute pass criterion. One representative run, end to end:

Detection timeline for a single PtH run

10:41:03  mimikatz.exe executed on WS01 (Sysmon EID 1)
10:41:03  LSASS handle opened, GrantedAccess 0x1010 (Sysmon EID 10)
10:41:05  4624 Logon_Type=9 Logon_Process=seclogo on WS01
10:41:20  events indexed in Splunk (wineventlog)
10:41:48  scheduled search fires, alert raised  (T+45s total)

Simulate a Golden Ticket

Forge a TGT with the lab KRBTGT AES key

.\Rubeus.exe golden /aes256:<lab-krbtgt-aes256-key> /user:Administrator /domain:lab.local /sid:S-1-5-21-<lab-domain-sid> /ptt

The 4769-without-4768 correlation search caught the forged ticket on its first service-ticket request. I also confirmed the ticket appeared in klist with the tell-tale 10-year lifetime Rubeus assigns by default.

False-positive tuning pass

After the attack simulations, I left the alerts running for 48 hours against the lab's background noise. The type-9 search produced two hits from a legitimate runas /netonly test script, which I tuned by requiring the source workstation to be outside the admin jump-host. The RC4 4769 search stayed silent until the Rubeus runs, exactly the behavior you want before calling a detection production-ready.

Test record

  • Kerberoasting: honeypot SPN alert fired on the first TGS request in all 5 runs; baseline RC4 search flagged svc_sql and svc_backup.
  • Pass-the-Hash: detected within 2 minutes in 5/5 runs (fastest 45 s, slowest 110 s).
  • Golden Ticket: correlation search caught 3/3 forged tickets; no false positives during 48 hours of background noise.
  • AS-REP roasting: 4768 pre-auth-type-0 rule fired on the seeded legacy account during the Rubeus asreproast run.

Troubleshooting

  • No 4769 events in Splunk: Kerberos service-ticket auditing is off by default. Enable it via Group Policy: Computer Configuration › Windows Settings › Security Settings › Advanced Audit Policy › Account Logon › Audit Kerberos Service Ticket Operations (Success), then gpupdate /force and confirm with auditpol /get /subcategory:"Kerberos Service Ticket Operations".
  • Sysmon telemetry gaps: confirm the SwiftOnSecurity config is actually applied, sysmon -c dumps the running configuration; if it shows the minimal default instead of the full rule set, re-apply with sysmon -c sysmonconfig.xml. Also check Get-Service Sysmon64 is Running.
  • BloodHound graph is empty or missing edges: the SharpHound zip was collected without domain context or LDAP was unreachable. Re-run from a domain-joined host as a domain user, verify nltest /dsgetdc:lab.local succeeds, and check the zip contains users.json, groups.json, and computers.json before importing.
  • Splunk fields (Ticket_Encryption_Type, Logon_Type) are empty: the Windows Add-on is not installed or the sourcetype is wrong. Install the Splunk Add-on for Microsoft Windows on the search head, and confirm events arrive as sourcetype=WinEventLog:Security, not generic Wineventlog.
  • Detections fire late or events arrive out of order: time skew between the DC, workstations, and Splunk indexer. Kerberos itself breaks at >5 minutes of skew, and alert correlation degrades long before that. Enforce w32time against the PDC emulator on all hosts and verify with w32tm /query /status.

Key Results

  • Identified 3 service accounts vulnerable to Kerberoasting via SPN + RC4 analysis.
  • Detected Pass-the-Hash attempts within 2 minutes of execution.
  • Mapped 15+ lateral-movement paths to Domain Admin using BloodHound.
  • Deployed 1 honeypot SPN account providing high-fidelity early warning with near-zero false positives.

Key Takeaways

  • Identity attacks live in the authentication logs, not on disk, collect 4624/4625/4768/4769 plus Sysmon Event 10 before writing a single detection.
  • RC4 Kerberos tickets (0x17) from non-machine accounts are the single highest-signal Kerberoasting indicator; a honeypot SPN turns it into a zero-noise tripwire.
  • Logon type 9 with the seclogo process is a near-signature for Mimikatz PtH, pair it with LSASS process-access telemetry to catch both the theft and the use.
  • BloodHound converts abstract "we might have privilege-escalation paths" into a concrete, countable list of edges to remediate.
  • A detection that has never been fired by a simulated attack is a hypothesis, not a control, validate with Rubeus/Mimikatz in an isolated lab before trusting it.

Practice Challenges

Challenge 1: Hunt Silver Tickets

Goal: Extend the detections to Silver Tickets (forged service tickets) by finding 4769 events with anomalous ticket lifetimes for one service.

Hint: Baseline normal ticket lifetimes per SPN first; Silver Tickets often use multi-year lifetimes.

Challenge 2: Close the top 3 paths

Goal: Take the 3 shortest BloodHound paths to Domain Admin and remediate each with a concrete AD change.

Hint: Common fixes: remove users from privileged groups, clean up stale admin sessions, and constrain delegation.