EXPLORE
← Back to Explore
elastichighTTP

PowerShell Kerberos Ticket Request

Detects PowerShell script content that references KerberosRequestorSecurityToken, which can request Kerberos service tickets. Attackers request service tickets to perform Kerberoasting for offline password cracking of service accounts.

MITRE ATT&CK

credential-accessexecution

Detection Query

event.category:process and host.os.type:windows and
  powershell.file.script_block_text : "KerberosRequestorSecurityToken" and
  not powershell.file.script_block_text : (
    ("sentinelbreakpoints" and ("Set-PSBreakpoint" or "Set-HookFunctionTabs")) or
    ("function global" and "\\windows\\sentinel\\4")
  )

Author

Elastic

Created

2022/01/24

Data Sources

PowerShell Logslogs-windows.powershell*winlogbeat-*

Tags

Domain: EndpointOS: WindowsUse Case: Threat DetectionTactic: Credential AccessResources: Investigation GuideData Source: PowerShell Logs
Raw Content
[metadata]
creation_date = "2022/01/24"
integration = ["windows"]
maturity = "production"
updated_date = "2026/04/27"

[rule]
author = ["Elastic"]
description = """
Detects PowerShell script content that references KerberosRequestorSecurityToken, which can request Kerberos service
tickets. Attackers request service tickets to perform Kerberoasting for offline password cracking of service accounts.
"""
from = "now-9m"
index = ["logs-windows.powershell*", "winlogbeat-*"]
language = "kuery"
license = "Elastic License v2"
name = "PowerShell Kerberos Ticket Request"
references = [
    "https://www.cobalt.io/blog/kerberoast-attack-techniques",
    "https://github.com/EmpireProject/Empire/blob/master/data/module_source/credentials/Invoke-Kerberoast.ps1",
]
risk_score = 73
rule_id = "eb610e70-f9e6-4949-82b9-f1c5bcd37c39"
severity = "high"
tags = [
    "Domain: Endpoint",
    "OS: Windows",
    "Use Case: Threat Detection",
    "Tactic: Credential Access",
    "Resources: Investigation Guide",
    "Data Source: PowerShell Logs",
]
timestamp_override = "event.ingested"
type = "query"

query = '''
event.category:process and host.os.type:windows and
  powershell.file.script_block_text : "KerberosRequestorSecurityToken" and
  not powershell.file.script_block_text : (
    ("sentinelbreakpoints" and ("Set-PSBreakpoint" or "Set-HookFunctionTabs")) or
    ("function global" and "\\windows\\sentinel\\4")
  )
'''

note = """## Triage and analysis

### Investigating PowerShell Kerberos Ticket Request

#### Possible investigation steps

- What does the reconstructed script actually do with KerberosRequestorSecurityToken?
  - Focus: Reconstruct full 4104 content on `host.id` with `powershell.file.script_block_id`, `powershell.sequence`, and `powershell.total`; interpret `powershell.file.script_block_text`.
  - Hint: pull fragments with matching `host.id` and `powershell.file.script_block_id`, order by `powershell.sequence`, and note gaps before judging intent. $investigate_2
  - Implication: escalate when the script requests SPN TGS tickets, loops across "Get-DomainUser -SPN" results, or emits John/Hashcat, "TicketByteHexStream", "$krb5tgs$", or ".kirbi" material; lower suspicion only when reconstruction proves incidental text, comments, or a bounded fixed-SPN test with no output logic.

- Do the user, host, and script source fit a bounded recognized Kerberos test?
  - Focus: `user.id`, `user.name`, `user.domain`, `host.id`, and `file.path`.
  - Hint: absent `file.path` means the script block may be interactive, pasted, or generated in memory, so require stronger corroboration before closure.
  - Implication: escalate when a standard user, shared workstation, production server, user-writable `file.path`, or absent `file.path` pairs with broad SPN targeting; lower suspicion only for a recognized identity test or Kerberos diagnostic on the expected host and user with a fixed SPN set.

- If endpoint process telemetry is available for this host, how did the PowerShell session start?
  - Focus: `process.command_line`, `process.parent.executable`, `process.parent.command_line`, and `process.Ext.session_info.logon_type`.
  - Hint: recover the process via `host.id + process.pid` before interpreting `process.*` or `process.parent.*`; if absent after a wider lookup, keep launch context unresolved and scope later pivots with `host.id`, `user.id`, and alert time. $investigate_3
  - Implication: escalate when launch context shows encoded commands, pasted or remote delivery, Office or browser parents, unexpected service or network logon, or alternate-credential use; lower suspicion when command line and parent chain match the exact recognized test workflow.

- Did the activity create ticket, hash, or target-list artifacts?
  - Focus: If endpoint file telemetry exists, scope writes to `host.id`, `user.id`, and the alert window; use the recovered process only after process recovery succeeds, and review `file.path` and `file.Ext.header_bytes`. $investigate_4
  - Implication: escalate when writes show SPN lists, ".kirbi" tickets, "$krb5tgs$" or John/Hashcat text, "TicketByteHexStream", base64 blobs, archives, or temp/share/user-writable staging; no file output does not clear direct hash output or memory-only ticket export, and missing file telemetry is unresolved, not benign.

- Do domain-controller ticket events confirm active Kerberoasting behavior?
  - Focus: DC-side Windows Security `event.code` 4769 near alert time, starting with `winlog.event_data.TargetUserName` = alert `user.name` for domain requesters; review `winlog.event_data.TargetDomainName`, `source.ip`, `winlog.event_data.ServiceName`, `winlog.event_data.TicketEncryptionType`, and target SPN volume. $investigate_5
  - Hint: if the alert user is local, SYSTEM, or the transform is quiet, retry DC 4769 with UPN/domain variants from `user.name` + `user.domain`, then pivot by source host/address and candidate requester from reconstruction or launch context.
  - Implication: escalate when 4769 events show broad SPN enumeration, RC4 or weak encryption, service-account-heavy targeting, or client addresses inconsistent with the expected workflow. Missing authentication telemetry is unresolved, not benign.

- Is this ticket-request activity isolated or part of broader suspicious behavior?
  - Focus: same-scope events or alerts for `user.id` in the last 48 hours for credential access, execution, discovery, or lateral movement. $investigate_0
  - Hint: use the host pivot separately when user scope is noisy or service-account-heavy. $investigate_1
  - Implication: broaden response when either pivot shows adjacent credential access, execution, discovery, or lateral movement; keep the case local only when related alerts stay quiet or match the same bounded recognized workflow.

- Escalate active service-ticket collection without a recognized owner or with suspicious scope, output, launch, artifact, DC 4769, or same-scope evidence; close only when alert-local evidence and supported recovery bind one exact bounded workflow and outside confirmation resolves gaps; preserve evidence and escalate when findings are mixed or incomplete.

### False positive analysis

- Recognized Kerberos diagnostics, identity validation, or red-team tests can trigger this rule when reconstructed `powershell.file.script_block_text` stays limited to a fixed SPN set, creates no ticket or hash output, and the script source fits. If process telemetry was recovered via `host.id + process.pid`, require `process.command_line` and `process.parent.executable` to match. Require test-record alignment when present; otherwise close only when current telemetry proves the same fixed-SPN, no-output, user-host, source, and launch-chain pattern.
- Build exceptions from the minimum confirmed workflow: `user.id`, `host.id`, exact source pattern, recovered launch chain, and fixed SPN set. If prior alerts exist, verify they do not add expanded targets, crackable output, or a different launch path; for a first verified case, prefer a narrow candidate or time-bounded exception over broad suppression. Avoid exceptions on "KerberosRequestorSecurityToken" alone, `user.name` alone, or host alone.

### Response and remediation

- If confirmed benign, reverse any temporary containment and record the evidence that proved the recognized diagnostics, lab, or identity-test workflow: stable user-host pairing, fixed SPN scope, script source, recovered launch chain when available, and no contradictory artifact or same-scope evidence. Create only a narrow exception from that confirmed evidence; use prior alerts to tighten scope when they exist, not as the primary proof.
- If suspicious but unconfirmed, preserve the reconstructed `powershell.file.script_block_text`, `powershell.file.script_block_id`, `powershell.sequence`, `powershell.total`, `process.pid`, any recovered process details, named SPNs, output paths, and available identity records before containment. Apply reversible containment first, such as temporary host isolation or account restriction matched to host criticality, and avoid destructive cleanup until service-account exposure is scoped.
- If confirmed malicious, contain the host and affected account when script intent, recovered launch context, named SPNs, output artifacts, or same-scope events support unauthorized ticket collection. Record the recovered PowerShell command line, parent chain, named SPNs, output locations, and available identity evidence before terminating processes, deleting files, or purging sessions.
- If targeted or bulk service-ticket requests are confirmed, prioritize the named service accounts for password rotation, privilege review, and downstream logon analysis, then review affected services for anomalous authentication or access tied to the same period.
- Eradicate only the unauthorized scripts, SPN lists, ticket or hash output, scheduled tasks, and persistence mechanisms uncovered during the investigation, then remediate the delivery path or administrative-control gap that allowed the script to run.
- After containment, hunt for the same reconstructed script fragments, SPN patterns, and ticket-request evidence across other hosts, and retain PowerShell Script Block Logging plus supporting endpoint or identity telemetry where gaps limited the investigation.
"""

setup = """## Setup

PowerShell Script Block Logging must be enabled to generate the events used by this rule (e.g., 4104).
Setup instructions: https://ela.st/powershell-logging-setup
"""

[rule.investigation_fields]
field_names = [
    "@timestamp",
    "user.name",
    "user.id",
    "user.domain",
    "powershell.file.script_block_text",
    "powershell.file.script_block_id",
    "powershell.sequence",
    "powershell.total",
    "file.path",
    "file.directory",
    "file.name",
    "process.pid",
    "host.name",
    "host.id",
    "powershell.file.script_block_length"
]

[transform]

[[transform.investigate]]
label = "Alerts associated with the user"
description = ""
providers = [
  [
    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
    { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
  ]
]
relativeFrom = "now-48h/h"
relativeTo = "now"

[[transform.investigate]]
label = "Alerts associated with the host"
description = ""
providers = [
  [
    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
  ]
]
relativeFrom = "now-48h/h"
relativeTo = "now"

[[transform.investigate]]
label = "All PowerShell 4104 fragments for this script on this host"
description = ""
providers = [
  [
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "powershell.file.script_block_id", queryType = "phrase", value = "{{powershell.file.script_block_id}}", valueType = "string" },
    { excluded = false, field = "event.code", queryType = "phrase", value = "4104", valueType = "string" }
  ]
]
relativeFrom = "now-1h"
relativeTo = "now"

[[transform.investigate]]
label = "Process events for the PowerShell instance"
description = ""
providers = [
  [
    { excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" }
  ]
]
relativeFrom = "now-1h"
relativeTo = "now"

[[transform.investigate]]
label = "File events for the PowerShell process"
description = ""
providers = [
  [
    { excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "event.category", queryType = "phrase", value = "file", valueType = "string" }
  ]
]
relativeFrom = "now-1h"
relativeTo = "now"

[[transform.investigate]]
label = "Kerberos service ticket events for the alert user name"
description = ""
providers = [
  [
    { excluded = false, field = "winlog.event_data.TargetUserName", queryType = "phrase", value = "{{user.name}}", valueType = "string" },
    { excluded = false, field = "event.code", queryType = "phrase", value = "4769", valueType = "string" }
  ]
]
relativeFrom = "now-24h"
relativeTo = "now"

[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1558"
name = "Steal or Forge Kerberos Tickets"
reference = "https://attack.mitre.org/techniques/T1558/"
[[rule.threat.technique.subtechnique]]
id = "T1558.003"
name = "Kerberoasting"
reference = "https://attack.mitre.org/techniques/T1558/003/"

[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"

[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[[rule.threat.technique.subtechnique]]
id = "T1059.001"
name = "PowerShell"
reference = "https://attack.mitre.org/techniques/T1059/001/"

[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"