Domain Reconnaissance
For detection, administrators can employ PowerShell to monitor for unusual scripts or cmdlets and process command-line monitoring.
User/Domain Reconnaissance Using BloodHound/SharpHound
The best option Windows can suggest is employing Event 1644
- the LDAP performance monitoring log. Even with it enabled, BloodHound may not generate many of the expected events.
Detecting User/Domain Recon With Splunk
1
2
3
4
| index=main source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventID=1 earliest=1690447949 latest=1690450687
| search process_name IN (arp.exe,chcp.com,ipconfig.exe,net.exe,net1.exe,nltest.exe,ping.exe,systeminfo.exe,whoami.exe) OR (process_name IN (cmd.exe,powershell.exe) AND process IN (*arp*,*chcp*,*ipconfig*,*net*,*net1*,*nltest*,*ping*,*systeminfo*,*whoami*))
| stats values(process) as process, min(_time) as _time by parent_process, parent_process_id, dest, user
| where mvcount(process) > 3
|
Detecting Recon By Targeting BloodHound
1
2
3
4
5
6
7
8
9
| index=main earliest=1690195896 latest=1690285475 source="WinEventLog:SilkService-Log"
| spath input=Message
| rename XmlEventData.* as *
| table _time, ComputerName, ProcessName, ProcessId, DistinguishedName, SearchFilter
| sort 0 _time
| search SearchFilter="*(samAccountType=805306368)*"
| stats min(_time) as _time, max(_time) as maxTime, count, values(SearchFilter) as SearchFilter by ComputerName, ProcessName, ProcessId
| where count > 10
| convert ctime(maxTime)
|
Password Spraying Detection Opportunities
A common pattern is multiple failed logon attempts with Event ID 4625 - Failed Logon
from different user accounts but originating from the same source IP address within a short time frame.
Other event logs that may aid in password spraying detection include:
4768 and ErrorCode 0x6 - Kerberos Invalid Users
4768 and ErrorCode 0x12 - Kerberos Disabled Users
4776 and ErrorCode 0xC000006A - NTLM Invalid Users
4776 and ErrorCode 0xC0000064 - NTLM Wrong Password
4648 - Authenticate Using Explicit Credentials
4771 - Kerberos Pre-Authentication Failed
1
2
3
| index=main earliest=1690280680 latest=1690289489 source="WinEventLog:Security" EventCode=4625
| bin span=15m _time
| stats values(user) as Users, dc(user) as dc_user by src, Source_Network_Address, dest, EventCode, Failure_Reason
|
Detecting Responder-like Attacks
Attack Steps:
- Victim device sends a name resolution query for a mistyped hostname (e.g.,
fileshrae
). - DNS fails to resolve the mistyped hostname.
- The victim device sends a name resolution query for the mistyped hostname using LLMNR/NBT-NS.
- The attacker’s host responds to the LLMNR/NBT-NS traffic, pretending to know the identity of the requested host, effectively poisoning the service.
Responder Detection Opportunities
- Deploy network monitoring solutions to detect unusual LLMNR and NBT-NS traffic patterns.
- Honeypot approach: name resolution for non-existent hosts should fail; success may indicate spoofing. Praetorian Blog Reference
1
2
3
| index=main earliest=1690290814 latest=1690291207 EventCode IN (4648)
| table _time, EventCode, source, name, user, Target_Server_Name, Message
| sort 0 _time
|
1
2
| index=main earliest=1690290078 latest=1690291207 EventCode=22
| table _time, Computer, user, Image, QueryName, QueryResults
|
Detecting Kerberoasting - TGS Requests
1
2
3
4
| | spath input=Message
| rename XmlEventData.* as *
| table _time, ComputerName, ProcessName, DistinguishedName, SearchFilter
| search SearchFilter="*(&(samAccountType=805306368)(servicePrincipalName=*)*"
|
1
2
3
4
5
6
7
| index=main earliest=1690450374 latest=1690450483 EventCode=4648 OR (EventCode=4769 AND service_name=iis_svc)
| dedup RecordNumber
| rex field=user "(?<username>[^@]+)"
| bin span=2m _time
| search username!=*$
| stats values(EventCode) as Events, values(service_name) as service_name, values(Additional_Information) as Additional_Information, values(Target_Server_Name) as Target_Server_Name by _time, username
| where !match(Events,"4648")
|
Detecting AS-REPRoasting With Splunk
1
2
3
4
5
| index=main earliest=1690392745 latest=1690393283 source="WinEventLog:SilkService-Log"
| spath input=Message
| rename XmlEventData.* as *
| table _time, ComputerName, ProcessName, DistinguishedName, SearchFilter
| search SearchFilter="*(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)*"
|
1
2
3
| index=main earliest=1690392745 latest=1690393283 source="WinEventLog:Security" EventCode=4768 Pre_Authentication_Type=0
| rex field=src_ip "(\:\:ffff\:)?(?<src_ip>[0-9\.]+)"
| table _time, src_ip, user, Pre_Authentication_Type, Ticket_Options, Ticket_Encryption_Type
|
Pass-the-Hash
1
2
3
4
5
| index=main earliest=1690450689 latest=1690451116 (source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=10 TargetImage="C:\\Windows\\system32\\lsass.exe" SourceImage!="C:\\ProgramData\\Microsoft\\Windows Defender\\platform\\*\\MsMpEng.exe") OR (source="WinEventLog:Security" EventCode=4624 Logon_Type=9 Logon_Process=seclogo)
| sort _time, RecordNumber
| transaction host maxspan=1m endswith=(EventCode=4624) startswith=(EventCode=10)
| stats count by _time, Computer, SourceImage, SourceProcessId, Network_Account_Domain, Network_Account_Name, Logon_Type, Logon_Process
| fields - count
|
Pass-the-Ticket
Pass-the-Ticket (PtT)
is a lateral movement technique using Kerberos tickets instead of NTLM hashes, allowing attackers to move across network resources.
Attack Steps:
- Extract valid TGT or TGS tickets from memory using tools like
Mimikatz
or Rubeus
. - Submit tickets for current logon session to authenticate elsewhere without passwords.
1
2
3
4
5
6
7
| index=main earliest=1690392405 latest=1690451745 source="WinEventLog:Security" user!=*$ EventCode IN (4768,4769,4770)
| rex field=user "(?<username>[^@]+)"
| rex field=src_ip "(\:\:ffff\:)?(?<src_ip_4>[0-9\.]+)"
| transaction username, src_ip_4 maxspan=10h keepevicted=true startswith=(EventCode=4768)
| where closed_txn=0
| search NOT user="*$@*"
| table _time, ComputerName, username, src_ip_4, service_name, category
|
Overpass-the-Hash
1
2
3
4
5
| index=main earliest=1690443407 latest=1690443544 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" (EventCode=3 dest_port=88 Image!=*lsass.exe) OR EventCode=1
| eventstats values(process) as process by process_id
| where EventCode=3
| stats count by _time, Computer, dest_ip, dest_port, Image, process
| fields - count
|
Golden Ticket
1
2
3
4
5
6
7
| index=main earliest=1690451977 latest=1690452262 source="WinEventLog:Security" user!=*$ EventCode IN (4768,4769,4770)
| rex field=user "(?<username>[^@]+)"
| rex field=src_ip "(\:\:ffff\:)?(?<src_ip_4>[0-9\.]+)"
| transaction username, src_ip_4 maxspan=10h keepevicted=true startswith=(EventCode=4768)
| where closed_txn=0
| search NOT user="*$@*"
| table _time, ComputerName, username, src_ip_4, service_name, category
|
Silver Ticket
1
2
3
| index=main latest=1690448444 EventCode=4720
| stats min(_time) as _time, values(EventCode) as EventCode by user
| outputlookup users.csv
|
Detecting Unconstrained Delegation Attacks With Splunk
1
2
| index=main earliest=1690544538 latest=1690544540 source="WinEventLog:Microsoft-Windows-PowerShell/Operational" EventCode=4104 Message="*TrustedForDelegation*" OR Message="*userAccountControl:1.2.840.113556.1.4.803:=524288*"
| table _time, ComputerName, EventCode, Message
|
Constrained Delegation
1
2
| index=main earliest=1690544553 latest=1690562556 source="WinEventLog:Microsoft-Windows-PowerShell/Operational" EventCode=4104 Message="*msDS-AllowedToDelegateTo*"
| table _time, ComputerName, EventCode, Message
|
Detecting RDP Brute Force Attacks With Splunk & Zeek Logs
1
2
3
4
| index="rdp_bruteforce" sourcetype="bro:rdp:json"
| bin _time span=5m
| stats count values(cookie) by _time, id.orig_h, id.resp_h
| where count>30
|
1
2
3
4
5
| index="ssh_bruteforce" sourcetype="bro:ssh:json"
auth_success="false"
| bin _time span=5m
| stats sum(auth_attempts) as num_attempts by _time, id.orig_h, id.resp_h, client, server
| where num_attempts>30
|
Detecting Beaconing Malware With Splunk & Zeek Logs
1
2
3
4
5
6
7
8
9
10
11
| index="cobaltstrike_beacon" sourcetype="bro:http:json"
| sort 0 _time
| streamstats current=f last(_time) as prevtime by src, dest, dest_port
| eval timedelta = _time - prevtime
| eventstats avg(timedelta) as avg, count as total by src, dest, dest_port
| eval upper=avg*1.1
| eval lower=avg*0.9
| where timedelta > lower AND timedelta < upper
| stats count, values(avg) as TimeInterval by src, dest, dest_port, total
| eval prcnt = (count/total)*100
| where prcnt > 90 AND total > 10
|
1
2
| index="cobaltstrike_beacon" sourcetype="bro:http:json" src=10.0.10.20 dest=192.168.151.181
| timechart count
|
Detecting Nmap Port Scanning With Splunk & Zeek Logs
1
2
3
4
| index="cobaltstrike_beacon" sourcetype="bro:conn:json" orig_bytes=0 dest_ip IN (192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8)
| bin span=5m _time
| stats dc(dest_port) as num_dest_port by _time, src_ip, dest_ip
| where num_dest_port >= 3
|
1
2
3
4
| index="cobaltstrike_beacon" sourcetype="bro:conn:json" dest_ip IN (192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8)
| bin span=5m _time
| stats dc(dest_port) as num_dest_port, values(dest_port) as dest_port by _time, src_ip, dest_ip
| where num_dest_port >= 3
|
Detecting Kerberos Brute Force Attacks With Splunk & Zeek Logs
1
2
3
4
5
6
| index="kerberos_bruteforce" sourcetype="bro:kerberos:json"
error_msg!=KDC_ERR_PREAUTH_REQUIRED
success="false" request_type=AS
| bin _time span=5m
| stats count dc(client) as "Unique users" values(error_msg) as "Error messages" by _time, id.orig_h, id.resp_h
| where count>30
|
Detecting Kerberoasting With Splunk & Zeek Logs
Now let’s explore how we can identify Kerberoasting, using Splunk and Zeek logs.
1
2
3
4
| index="sharphound" sourcetype="bro:kerberos:json"
request_type=TGS cipher="rc4-hmac"
forwardable="true" renewable="true"
| table _time, id.orig_h, id.resp_h, request_type, cipher, forwardable, renewable, client, service
|
Detecting Golden Tickets With Splunk & Zeek Logs
Now let’s explore how we can identify Golden Tickets, using Splunk and Zeek logs.
1
2
3
4
5
| index="golden_ticket_attack" sourcetype="bro:kerberos:json"
| where client!="-"
| bin _time span=1m
| stats values(client), values(request_type) as request_types, dc(request_type) as unique_request_types by _time, id.orig_h, id.resp_h
| where request_types=="TGS" AND unique_request_types==1
|
Detecting Cobalt Strike’s PSExec With Splunk & Zeek Logs
Now let’s explore how we can identify Cobalt Strike’s PSExec, using Splunk and Zeek logs.
1
2
3
4
5
6
| index="cobalt_strike_psexec"
sourcetype="bro:smb_files:json"
action="SMB::FILE_OPEN"
name IN ("*.exe", "*.dll", "*.bat")
path IN ("*\\c$", "*\\ADMIN$")
size>0
|
1
2
3
| index="change_service_config" endpoint=svcctl sourcetype="bro:dce_rpc:json"
operation IN ("CreateServiceW", "CreateServiceA", "StartServiceW", "StartServiceA", "ChangeServiceConfigW")
| table _time, id.orig_h, id.resp_h, endpoint, operation
|
Detecting Zerologon With Splunk & Zeek Logs
Now let’s explore how we can identify Zerologon, using Splunk and Zeek logs.
1
2
3
4
5
| index="zerologon" endpoint="netlogon" sourcetype="bro:dce_rpc:json"
| bin _time span=1m
| where operation == "NetrServerReqChallenge" OR operation == "NetrServerAuthenticate3" OR operation == "NetrServerPasswordSet2"
| stats count values(operation) as operation_values dc(operation) as unique_operations by _time, id.orig_h, id.resp_h
| where unique_operations >= 2 AND count>100
|
Detecting HTTP Exfiltration With Splunk & Zeek Logs
Now let’s explore how we can identify HTTP exfiltration, using Splunk and Zeek logs.
1
2
3
| index="cobaltstrike_exfiltration_http" sourcetype="bro:http:json" method=POST
| stats sum(request_body_len) as TotalBytes by src, dest, dest_port
| eval TotalBytes = TotalBytes/1024/1024
|