Skip to content

Instantly share code, notes, and snippets.

@jsecurity101
Last active June 18, 2023 17:03
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save jsecurity101/4f82d1ec608671bdf722a43b9291a8ba to your computer and use it in GitHub Desktop.
Save jsecurity101/4f82d1ec608671bdf722a43b9291a8ba to your computer and use it in GitHub Desktop.
Kerberos Detection/Investigation
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Query 1 - Kerberoasting with ProcessEvents

SecurityEvent
| where EventID == 4769 
| extend ticketOptions = toint(extract("<Data Name=\\"TicketOptions\\">(.*?)</Data>", 1, EventData))
| extend IpPort = toint(extract("<Data Name=\\"IpPort\\">(.*?)</Data>", 1, EventData))
| extend IpAddress = extract("<Data Name=\\"IpAddress\\">(.*?)</Data>", 1, EventData)
| extend TargetUserName = extract("<Data Name=\\"TargetUserName\\">(.*?)@.*?</Data>", 1, EventData)
| extend ServiceName = extract("<Data Name=\\"ServiceName\\">(.*?)</Data>", 1, EventData)
| extend TicketEncryptionType = toint(extract("<Data Name=\\"TicketEncryptionType\\">(.*?)</Data>", 1, EventData))
| project ServiceName, toint(IpPort), SourceIp = toint(split(IpAddress, '::ffff:')[1]), ticketOptions, TicketEncryptionType
|join kind = inner ( 
    Sysmon
| where EventID == 3 and Computer !contains "dc" and DestinationPort == 88
| project-rename IpPort = SourcePort
| project TimeGenerated, Image, toint(IpPort), toint(ProcessId), toint(SourceIp), CommandLine, Computer
) on IpPort, SourceIp
| project TimeGenerated, Image, IpPort, ProcessId, CommandLine, Computer, ServiceName, TicketEncryptionType, ticketOptions
| join kind=inner(
DeviceProcessEvents
| project-rename Image = FileName
| project TimeGenerated ,toint(ProcessId), Image, AccountName, ProcessCommandLine, DeviceName
) on ProcessId
| project TimeGenerated, DeviceName, TimeGenerated1, Image, ProcessId, AccountName, ServiceName, ProcessCommandLine, TicketEncryptionType, ticketOptions

Query 2 - Kerberoasting w/o ProcessEvents

SecurityEvent
| where EventID == 4769 
| extend ticketOptions = toint(extract("<Data Name=\"TicketOptions\">(.*?)</Data>", 1, EventData))
| extend IpPort = toint(extract("<Data Name=\"IpPort\">(.*?)</Data>", 1, EventData))
| extend IpAddress = extract("<Data Name=\"IpAddress\">(.*?)</Data>", 1, EventData)
| extend TargetUserName = extract("<Data Name=\"TargetUserName\">(.*?)@.*?</Data>", 1, EventData)
| extend ServiceName = extract("<Data Name=\"ServiceName\">(.*?)</Data>", 1, EventData)
| extend TicketEncryptionType = toint(extract("<Data Name=\"TicketEncryptionType\">(.*?)</Data>", 1, EventData))
| extend DestinationComputer = Computer
| project ServiceName, toint(IpPort), SourceIp = toint(split(IpAddress, '::ffff:')[1]), ticketOptions, TicketEncryptionType, DestinationComputer
|join kind = inner ( 
    Sysmon
| where EventID == 3 and Computer !contains "dc" and DestinationPort == 88
| project-rename IpPort = SourcePort, SourceComputer = Computer
| project TimeGenerated, Image, toint(IpPort), toint(ProcessId), toint(SourceIp), CommandLine, SourceComputer
) on IpPort, SourceIp
| project TimeGenerated, Image, IpPort, ProcessId, CommandLine, SourceComputer, DestinationComputer, ServiceName, TicketEncryptionType, ticketOptions

Query 1 - S4U2Self:

index=windows EventCode=4769 Ticket_Options=0x40800018 AND Failure_Code=0x0
| eval temp=split(Client_Address, ":")
| eval Client_Address=mvindex(temp,-1)
| eval alt_account_name=upper(mvindex(split(Account_Name,"@"),0)) 
| eval alt_service_name=upper(mvindex(Service_Name,0))
| where alt_account_name == alt_service_name
| rename Client_Port AS SourcePort, Client_Address AS SourceAddress
| join SourcePort, SourceAddress
[
search index=windows EventCode=5156 Direction=Outbound Destination_Port=88 host!=*DC*
| rename Source_Port AS SourcePort, Source_Address AS SourceAddress, Application_Name AS ApplicationName
]
| table SourceAddress, SourcePort, ApplicationName, Ticket_Encryption_Type, Service_Name, Account_Name

Query 2 - Kerberoasting:

index=windows EventCode=4769 Service_Name!="*$" Service_Name!="krbtgt" Failure_Code ="0x0" Account_Name!="*$*"  AND ((Ticket_Encryption_Type=0x17 AND (Ticket_Options=0x40800018) OR (Ticket_Options=0x40800000)) OR (Ticket_Encryption_Type=0x12 AND Ticket_Options=0x40800000))
| eval temp=split(Client_Address, ":")
| eval Client_Address=mvindex(temp,-1)
| rename Client_Port AS SourcePort, Client_Address AS SourceAddress
| join SourcePort, SourceAddress
[
search index=windows EventCode=5156 Direction=Outbound Destination_Port=88 host!=*DC*
| rename Source_Port AS SourcePort, Source_Address AS SourceAddress, Application_Name AS ApplicationName
]
| table SourceAddress, SourcePort, ApplicationName, Ticket_Encryption_Type, Service_Name, Account_Name

Query 3 - AskTGT:

index=windows EventCode=4768 Ticket_Encryption_Type=0x17 ```Attacker can change encryption type```
| eval temp=split(Client_Address, ":")
| eval Client_Address=mvindex(temp,-1)
| rename Client_Port AS SourcePort, Client_Address AS SourceAddress
| join SourcePort, SourceAddress
[
search index=windows EventCode=5156 Direction=Outbound Destination_Port=88 host!=*DC*
| rename Source_Port AS SourcePort, Source_Address AS SourceAddress
]
| table SourceAddress, SourcePort, ApplicationName, Ticket_Encryption_Type, Service_Name, Account_Name, Application_Name
@jurelou
Copy link

jurelou commented Jul 15, 2022

Hello, I could not successfully use your detection against this sample: https://github.com/mdecrevoisier/EVTX-to-MITRE-Attack/tree/master/TA0006-Credential%20Access/T1558-Steal%20or%20Forge%20Kerberos%20Tickets

in your first search query = "search index=windows sourcetype=Security EventCode=4769 Service_Name!=*$ Service_Name!=krbtgt Failure_Code =0x0 Account_Name!=*$* AND ((Ticket_Encryption_Type=0x17 AND (Ticket_Options=0x40800018) OR (Ticket_Options=0x40800000)) OR (Ticket_Encryption_Type=0x12 AND Ticket_Options=0x40800000)) earliest=-1hr"

You are checking for RC4 + options = 0x40800018 OR 0x40800000

In my dataset, options are 0x40810000.
(the difference between the options is that the 16th bit is set)

Also, from the microsoft docs, thoses bits are marked as "unused"
Do you have any ideas why ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment