Module 6: Detecting Windows Attacks with Splunk

Module 6 cover: detecting Windows attacks with Splunk

These notes are from the practical Splunk hunting sections in the module. Each section keeps the lab SPL as written, plus a short note on what the hunt is looking for and what showed up when I ran it.

Back to Module 4 fundamentals: Module 4: Understanding Log Sources & Investigating with Splunk

Module 6 Navigation

On this page

Skill Assessment

Introduction

This module was query-heavy. Most sections follow the same pattern: what the attack is, which logs to use, the lab SPL, and what stood out in the lab data.

Windows Event Log Hunts

1. Detecting Common User/Domain Recon

1. What is Active Directory Reconnaissance? Active Directory (AD) domain reconnaissance is the phase where attackers gather information about a target environment’s architecture, users, and groups to pinpoint high-value targets, escalate privileges, and move laterally. Attackers typically do this in two distinct ways:

2. How do you detect it? Because attackers use two different methodologies, you need two separate log sources to catch them:

3. The Splunk Queries & Logic (Note: You may need to adjust or remove the earliest and latest timestamps in these examples, as they are currently filtering for a specific timeframe.)

Detecting Native Tools:

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

How it works:

Detecting BloodHound:

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)

How it works:


2. Detecting Password Spraying

1. What is Password Spraying? Unlike traditional brute-force attacks that try many passwords against a single account, password spraying distributes the attack across multiple different accounts using a limited set of commonly used passwords. The primary goal is to evade standard account lockout policies (which trigger after a few failed attempts on a single account) and make the attack less noticeable.

2. How do you detect it? To detect password spraying, you need to monitor Windows Security Event Logs for patterns of multiple failed logons across different user accounts that originate from the same source IP address within a short time frame.

3. The Splunk Query & Logic (Note: You may need to adjust or remove the earliest and latest timestamps in this example, as they are currently filtering for a specific timeframe.)

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

How it works:


3. Detecting Responder-like Attacks

1. What is LLMNR/NBT-NS Poisoning?

LLMNR and NBT-NS are backup name resolution protocols used when standard DNS fails to find a hostname. Attackers, commonly utilizing a tool called Responder, exploit the lack of security in these protocols by listening for broadcast queries looking for mistyped or non-existent network shares. When a victim searches for a bad hostname, the attacker’s machine responds pretending to be the target, which forces the victim to connect to them. The ultimate goal is to steal the victim’s NetNTLM hash so the attacker can crack it or relay it for unauthorized access.

2. How do you detect it?

Detecting this activity requires monitoring for unusual name resolution traffic or rogue responses. You can use three log sources:

3. The Splunk Queries & Logic

(Note: As with previous examples, you should adjust or remove the earliest and latest timestamps depending on the timeframe you want to search in your environment.)

Detecting with Custom Honeypot Logs:

index=main earliest=1690290078 latest=1690291207 SourceName=LLMNRDetection
| table _time, ComputerName, SourceName, Message

How it works:

Detecting Mistyped Shares (Sysmon):

index=main earliest=1690290078 latest=1690291207 EventCode=22
| table _time, Computer, user, Image, QueryName, QueryResults

How it works:

Detecting Rogue Logons:

index=main earliest=1690290814 latest=1690291207 EventCode IN (4648)
| table _time, EventCode, source, name, user, Target_Server_Name, Message
| sort 0 _time

How it works:


4. Detecting Kerberoasting/AS-REPRoasting

1. What are Kerberoasting and AS-REProasting?

Both are Active Directory attacks aimed at extracting password hashes for offline cracking, but they target different accounts:

2. How do you detect them?

3. The Splunk Queries & Logic

(Note: Adjust or remove the earliest and latest timestamps depending on the timeframe you want to search in your environment.)

Detecting Kerberoasting (Ticket Requests without Logons):

index=main earliest=1690450374 latest=1690450483 EventCode=4648 OR (EventCode=4769 AND service_name=iis_svc)
| dedup RecordNumber
| rex field=user "(?<username>[^@]+)"
| search username!=*$
| transaction username keepevicted=true maxspan=5s endswith=(EventCode=4648) startswith=(EventCode=4769)
| where closed_txn=0 AND EventCode = 4769
| table _time, EventCode, service_name, username

How it works:

Detecting AS-REProasting (Disabled Pre-Authentication):

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

How it works:


5. Detecting Pass-the-Hash

1. What is a Pass-the-Hash Attack?

Pass-the-Hash (PtH) is a technique where attackers with local administrative privileges extract a user’s NTLM password hash directly from system memory, usually employing tools like Mimikatz. Instead of needing the victim’s plaintext password, the attacker reuses (or “passes”) this hash to authenticate and move laterally across the network.

2. How do you detect it?

When an attacker uses an alternate credential for remote access, it generates a specific Windows Security logon event (Event ID 4624 with Logon Type 9, meaning “NewCredentials”). However, searching only for this event can trigger false positives from legitimate system administration.

To accurately detect a PtH attack, you must correlate that logon event with the attacker’s tool physically accessing the credential memory. You detect this by linking the Logon Type 9 event with a Sysmon Process Access event (Event ID 10) specifically targeting the lsass.exe process.

3. The Splunk Query & Logic

(Note: Adjust or remove the earliest and latest timestamps depending on the timeframe you want to search in your environment.)

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

How it works:

What is seclogo? It’s the Secondary Logon service (seclogon, truncated in the event field), the mechanism behind runas and CreateProcessWithLogonW. When a process launches with alternate credentials, Windows logs it as Logon Type 9 (NewCredentials) through this service. It doesn’t validate the credential immediately - it caches it and only uses it once the process reaches out over the network. That’s exactly what Mimikatz’s sekurlsa::pth does: spawn a process via this same mechanism, handing it a stolen hash instead of a password.


6. Detecting Pass-the-Ticket

1. What is a Pass-the-Ticket (PtT) Attack?

Pass-the-Ticket is a lateral movement technique where an attacker extracts valid Kerberos tickets, either a Ticket Granting Ticket (TGT) or a Ticket Granting Service (TGS) ticket, from a compromised system’s memory using tools like Mimikatz or Rubeus. Instead of needing the user’s plaintext password or NTLM hash, the attacker injects these stolen tickets into their current session to securely authenticate and access other network resources.

2. How do you detect it?

Normal Kerberos authentication follows a strict sequence: a user must first request a TGT from the Domain Controller (Event ID 4768), and then use that TGT to request a Service Ticket for a specific resource (Event ID 4769).

When an attacker imports a stolen TGT into their session, the Domain Controller never sees the initial request originating from the attacker’s system. Therefore, you detect PtT by hunting for “partial” Kerberos authentication flows, specifically, looking for Service Ticket requests (Event 4769) that lack a preceding TGT request (Event 4768) from the same system within a standard timeframe.

3. The Splunk Query & Logic

(Note: You may need to adjust or remove the earliest and latest timestamps depending on the timeframe you want to search in your environment.)

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

How it works:

Scaling note: transaction over high event volume is expensive, and multi-DC/NAT environments will generate “orphaned” tickets from infrastructure alone, not just attackers - at enterprise scale this needs a stats-based correlation (or a LogonId-based join) instead of transaction.


7. Detecting Overpass-the-Hash

1. What is an Overpass-the-Hash Attack?

Overpass-the-Hash (also known as Pass-the-Key) is a technique where attackers use a stolen NTLM password hash or AES key to fraudulently request a legitimate Kerberos Ticket Granting Ticket (TGT). Unlike a standard Pass-the-Hash attack which relies on NTLM authentication, this technique upgrades the attacker’s access to Kerberos. Attackers typically use Mimikatz to extract the user’s hash from system memory (requiring local admin rights) and then use a tool like Rubeus to craft the raw ticket request to the Domain Controller.

2. How do you detect it?

If an attacker uses Mimikatz to perform this attack, it leaves the exact same memory-access artifacts as a standard Pass-the-Hash attack and can be detected using the same logic.

However, if they use Rubeus, standard detections may fail. Rubeus sends its ticket request directly to the Domain Controller, generating a standard TGT request log (Event ID 4768). The key to detecting this is monitoring network connections: legitimate Kerberos traffic to the Domain Controller should only originate from the system’s Local Security Authority process (lsass.exe). You can detect Rubeus by hunting for network traffic aimed at the Kerberos port (Port 88) originating from any other unusual process.

3. The Splunk Query & Logic

(Note: Adjust or remove the earliest and latest timestamps depending on the timeframe you want to search in your environment.)

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

How it works:


8. Detecting Golden Ticket and Silver Ticket Attacks

1. What are Golden and Silver Ticket Attacks?

Both are advanced Kerberos forging techniques where an attacker creates their own authentication tickets to gain unauthorized access, but they differ in scope and target:

2. How do you detect them?

Because the actual forging of these tickets happens offline, detecting the creation process is virtually impossible without catching the initial credential dumping. Instead, you must monitor for how these tickets are used:

3. The Splunk Queries & Logic

(Note: As always, you will want to adjust or remove the static timestamps like latest=1690545656 for your live environment).

Detecting Golden Tickets (The Pass-the-Ticket Approach):

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

How it works:

Detecting Silver Tickets (Hunting for Phantom Users):

(Prerequisite: You must first create a lookup table of valid users by running a background search for EventCode=4720 and outputting it to users.csv).

index=main latest=1690545656 EventCode=4624
| stats min(_time) as firstTime, values(ComputerName) as ComputerName, values(EventCode) as EventCode by user
| eval last24h = 1690451977
| where firstTime > last24h
| eval last24h=relative_time(now(),"-24h@h")
| convert ctime(firstTime)
| convert ctime(last24h)
| lookup users.csv user as user OUTPUT EventCode as Events
| where isnull(Events)

How it works:

Detecting Silver Tickets (Anomalous Special Privileges):

index=main latest=1690545656 EventCode=4672
| stats min(_time) as firstTime, values(ComputerName) as ComputerName by Account_Name
| eval last24h = 1690451977
| eval last24h=relative_time(now(),"-24h@h")
| where firstTime > last24h
| table firstTime, ComputerName, Account_Name
| convert ctime(firstTime)

How it works:


9. Detecting Delegation and Constrained Delegation Attacks

1. What are Active Directory Delegation Attacks?

Delegation is a feature allowing a service or computer to authenticate to another resource on behalf of a user. Attackers exploit this to impersonate high-privileged accounts, typically targeting two distinct configurations:

2. How do you detect them?

Because the actual ticket theft often happens directly in memory, the most reliable way to catch delegation attacks is by monitoring the initial discovery phase and the anomalous network traffic generated by the exploitation tools.

(Note: Because Unconstrained Delegation relies on reusing stolen tickets, you can also detect its execution using standard Pass-the-Ticket logic).

3. The Splunk Queries & Logic

(Note: Adjust or remove the earliest and latest timestamps depending on the timeframe you want to search in your environment).

Detecting Delegation Discovery (PowerShell):

index=main earliest=1690544538 latest=1690562556 source="WinEventLog:Microsoft-Windows-PowerShell/Operational" EventCode=4104 Message=" *TrustedForDelegation* " OR Message=" *userAccountControl:1.2.840.113556.1.4.803:=524288* " OR Message=" *msDS-AllowedToDelegateTo* "
| table _time, ComputerName, EventCode, Message

How it works:

Detecting Constrained Execution (Anomalous Kerberos Traffic):

index=main earliest=1690562367 latest=1690562556 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
| eventstats values(process) as process by process_id
| where EventCode=3 AND dest_port=88
| table _time, Computer, dest_ip, dest_port, Image, process

How it works:


10. Detecting DCSync and DCShadow

1. What are DCSync and DCShadow Attacks?

Both attacks abuse Active Directory replication permissions to either steal data or maliciously modify the environment:

2. How do you detect them?

3. The Splunk Queries & Logic

(Note: As with previous sections, adjust or remove the earliest and latest timestamps depending on the timeframe you want to search in your environment).

Detecting DCSync (Unauthorized Replication Requests):

index=main earliest=1690544278 latest=1690544280 EventCode=4662 Message=" *Replicating Directory Changes* "
| rex field=Message "(?P<property>Replicating Directory Changes.*)"
| table _time, user, object_file_name, Object_Server, property

How it works:

Detecting DCShadow (Rogue DC Registration):

index=main earliest=1690623888 latest=1690623890 EventCode=4742
| rex field=Message "(?P<gcspn>XX/[a-zA-Z0-9.-/]+)"
| table _time, ComputerName, Security_ID, Account_Name, user, gcspn
| search gcspn=*

How it works:

Zeek Network Hunts

The second half of the module shifts to Zeek-backed indexes. Same hunt pattern, but the signal is in network traffic instead of Windows Security or Sysmon.

11. Detecting RDP Brute Force

1. What is an RDP Brute Force Attack?

A Remote Desktop Protocol (RDP) brute force attack is a common method adversaries use to gain an initial foothold in a network. The concept is straightforward: attackers target an exposed RDP service and systematically guess different passwords until they successfully log into a remote session. This attack specifically exploits the fact that many organizations still rely on weak or default passwords.

2. How do you detect it?

Because brute-forcing requires a massive number of guesses to be successful, it generates a highly noisy footprint. You can detect this activity by monitoring your network traffic logs, specifically utilizing a tool like Zeek, to spot a high volume of RDP connection attempts originating from a single source IP address within a short timeframe.

3. The Splunk Query & Logic

(Note: As always, adjust your index or sourcetype names if they differ in your specific environment).

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

How it works:


12. Detecting Beaconing Malware

1. What is Cobalt Strike Beaconing?

Malware beaconing is a technique where an infected system periodically communicates back to an attacker’s Command and Control (C2) server, operating much like a lighthouse sending out a regular, repeating signal. Cobalt Strike is one of the most widely recognized and utilized C2 frameworks that relies on this behavior. Attackers use these beacons, typically small data packets sent over standard protocols like HTTP/HTTPS, DNS, or ICMP, to maintain a connection and receive instructions. The timing between these beacons can be completely fixed, or attackers can use “jitter” (slightly randomizing the timing) to make the automated traffic blend in with normal network behavior.

2. How do you detect it?

You detect beaconing by hunting for highly repetitive, predictable network communication patterns over time. Because attackers often use jitter, a simple search for an exact timestamp interval will fail. Instead, you must capture network traffic (often using a tool like Zeek) and use Splunk to mathematically calculate the average time difference between connections originating from the same source to the same destination. If a machine is making automated, periodic requests to an external server, you can expose the pattern by calculating the margins of that activity.

3. The Splunk Query & Logic

(Note: As always, adjust your index or sourcetype names if they differ in your specific environment).

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

How it works:


13. Detecting Nmap Port Scanning

1. What is Nmap Port Scanning?

Port scanning with Nmap is a technique attackers and penetration testers use to probe networked systems for open ports, which act as ‘doors’ for data to pass in and out of a system. Nmap systematically attempts to establish a TCP handshake with various ports; if successful, the target might send back a “banner” revealing what service is running. A key characteristic of standard Nmap scanning is that it does not send any actual data payload, aside from the TCP handshake itself, the originating bytes sent are zero.

2. How do you detect it?

To detect Nmap scanning, you need to monitor your network traffic logs (such as Zeek logs) rather than host-level event logs. You can spot this activity by hunting for network connections where the originating payload is exactly zero bytes. By analyzing these specific zero-byte connections, you can look for a single source IP rapidly probing multiple distinct destination ports on your internal network within a short time window.

3. The Splunk Query & Logic

(Note: As always, adjust the index name if it differs in your environment. The source example happens to use an index named “cobaltstrike_beacon”, but it is specifically pulling Zeek connection logs for this search).

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

How it works:

In this lab: one source hit 2,000+ distinct ports against a single host in one 5-minute window.


14. Detecting Kerberos Brute Force Attacks

1. What is a Kerberos Brute Force/Enumeration Attack?

When adversaries perform Kerberos-based user enumeration or brute-forcing, they send an AS-REQ (Authentication Service Request) message containing a guessed username to the Key Distribution Center (KDC). They then analyze the server’s response to see if the account exists: a valid username typically returns a Ticket Granting Ticket (TGT) or a KRB5KDC_ERR_PREAUTH_REQUIRED error message. Conversely, an invalid username returns a specific KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN error in the AS-REP (Authentication Service Response) message. By rapidly cycling through usernames and monitoring these specific responses, attackers can quickly map out valid accounts on the target system.

2. How do you detect it?

Because this attack requires sending numerous requests to validate users, it leaves a distinct footprint in network traffic. You can detect this by monitoring Kerberos communications using a network tool like Zeek. You need to hunt for a high volume of failed Authentication Service (AS) requests originating from a single source IP address within a short timeframe, while specifically filtering out the standard “preauthentication required” errors to isolate the malicious probing.

3. The Splunk Query & Logic

(Note: As always, adjust the index and sourcetype names if your network logging setup differs).

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

How it works:

In this lab: one source tried 593 distinct usernames against the KDC in a single 5-minute window, all with the same unknown-principal error.


15. Detecting Kerberoasting (Network)

1. What is Kerberoasting?

We already covered detecting Kerberoasting through Windows Event Logs - hunting for RC4-encrypted service ticket requests (EventCode 4769) and using request volume to separate a real attack from normal Kerberos chatter. This section covers the same attack from the network side instead.

2. How do you detect it?

While you can hunt for Kerberoasting using Windows Event Logs (as covered in a previous section), you can also detect it purely through network traffic analysis. By utilizing a network monitoring tool like Zeek, you can analyze Kerberos packets (specifically TGS-REQ and TGS-REP packets) and hunt for service ticket requests that specifically request the weak RC4 cipher along with specific ticket flags.

3. The Splunk Query & Logic

(Note: Adjust the index and sourcetype names if your network logging setup differs).

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

How it works:

In this lab: one account requested the same service 14 times within about one second under the RC4/forwardable/renewable filter.


16. Detecting Golden Tickets

1. What is a Golden Ticket Attack (Network Perspective)?

In a typical Kerberos authentication flow, a client must first request a Ticket Granting Ticket (TGT) from the Domain Controller, known as the AS-REQ and AS-REP process, before they can use that TGT to request a Service Ticket (TGS) to access a specific resource.

In a Golden Ticket (or Pass-the-Ticket) attack, the attacker completely bypasses this initial authentication process. Because they have generated a forged TGT (or stolen an existing one), they can jump straight to directly requesting TGS tickets to access services on the network without ever performing the standard AS-REQ and AS-REP steps.

2. How do you detect it?

While network monitoring tools like Zeek lack the ability to natively verify if a ticket is mathematically forged, you can detect the attack by hunting for the anomalous network behavior it creates. Specifically, you want to monitor your network traffic to find instances of “orphaned” Service Ticket requests, meaning a client machine is making TGS requests (asking for service access) without any preceding AS-REQ requests (asking for initial authentication) occurring within the same timeframe.

3. The Splunk Query & Logic

(Note: As always, adjust the index and sourcetype names if your network logging setup differs. This example relies on Zeek logs).

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

How it works:

In this lab: one client only showed TGS requests with no AS-REQ in the dataset.


17. Detecting Cobalt Strike PsExec

1. What is Cobalt Strike PSExec Lateral Movement?

Cobalt Strike’s PSExec is a lateral movement technique that mimics Microsoft’s legitimate Sysinternals PsExec tool to execute post-exploitation payloads on remote systems. Operating over the SMB protocol (port 445) and requiring local administrator privileges, the tool works in a specific sequence: it transfers a payload over the network to a hidden administrative share (like the ADMIN$ share), creates a temporary remote service to execute that payload, and then immediately stops and deletes the service to minimize its forensic footprint.

2. How do you detect it?

Because the attacker deletes the service after execution to hide their tracks, one of the most reliable ways to detect this activity is by monitoring the network for the initial payload delivery. Utilizing a network monitoring tool like Zeek, you can inspect SMB protocol traffic and hunt for the specific file transfer phase. You are looking for instances where executable files are being opened or written directly to administrative network shares.

3. The Splunk Query & Logic

(Note: As always, adjust the index and sourcetype names if your network logging setup differs).

index="cobalt_strike_psexec" sourcetype="bro:smb_files:json" action="SMB::FILE_OPEN" name IN ("*.exe", "*.dll", "*.bat") path IN ("*\\C$", "*\\ADMIN$") size>0

How it works:

In this lab: one executable transfer to the DC ADMIN$ share (be5312f.exe).


18. Detecting Zerologon

1. What is the Zerologon Vulnerability?

Zerologon (CVE-2020-1472) is a critical authentication bypass vulnerability in Microsoft’s Netlogon Remote Protocol (MS-NRPC). The flaw exists because the initialization vector (IV) for the protocol’s AES-CFB8 encryption mode is mistakenly hardcoded to a fixed value of all zeros, rather than being uniquely randomized. Attackers exploit this by sending a session key consisting entirely of zeros, which successfully bypasses the authentication process. Once authenticated, the attacker can execute the NetrServerPasswordSet2 function to change the Domain Controller’s computer account password to a blank value, instantly granting them full control over the entire Active Directory domain.

2. How do you detect it?

Exploiting Zerologon requires the attacker to spam the server with specific Netlogon messages until the zero-key authentication succeeds, a process that usually executes within seconds. You can detect this from a network perspective by monitoring for a massive spike in these specific Netlogon requests. Utilizing a network monitoring tool like Zeek, you can hunt for a rapid sequence of NetrServerReqChallenge, NetrServerAuthenticate3, and NetrServerPasswordSet2 operations occurring between a single client and the Domain Controller.

3. The Splunk Query & Logic

(Note: As always, adjust the index and sourcetype names if your network logging setup differs).

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

How it works:

In this lab: one source sent 881 combined NetrServerReqChallenge/NetrServerAuthenticate3 calls against the DC across two 1-minute windows.


19. Detecting HTTP Exfiltration

1. What is HTTP POST Data Exfiltration?

Data exfiltration inside an HTTP POST body is a technique attackers use to stealthily extract sensitive information from a compromised system. By packing the stolen data into the body of an HTTP POST request and sending it to their Command and Control (C2) server, attackers disguise the exfiltration as normal web traffic, since POST requests are constantly used for legitimate activities like form submissions and file uploads. To blend in even further, attackers often utilize innocuous URLs and standard web headers to camouflage the outbound data.

2. How do you detect it?

Because POST requests are a standard part of daily web traffic, you cannot simply flag every instance. Instead, you detect this by employing network monitoring tools (like Zeek) to aggregate all the data being sent to specific external IPs and ports. By analyzing the total volume of outgoing traffic, you can identify patterns of unusually large or abnormally frequent data transfers destined for a single, external location.

3. The Splunk Query & Logic

(Note: As always, adjust the index and sourcetype names if your network logging setup differs).

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

How it works:

In this lab: 256 MB of HTTP POST data from one internal host to one external IP on port 80.


20. Detecting DNS Exfiltration

1. What is DNS Exfiltration?

DNS-based exfiltration is a stealthy technique attackers use to covertly steal data, exploiting the fact that DNS traffic is almost always allowed by default through network firewalls. Once an attacker compromises a network and identifies sensitive data, they encode or encrypt it, split it into small chunks, and embed those chunks directly into the subdomains of DNS queries. These queries are sent to a DNS server controlled by the attacker, who then extracts, reassembles, and decodes the stolen data.

2. How do you detect it?

Because attackers have to cram stolen data into subdomain fields, exfiltration generates unusually long DNS queries. You can detect this by utilizing network monitoring tools like Zeek to analyze DNS traffic. The detection strategy relies on calculating the character length of all DNS queries, filtering out known legitimate services that naturally produce long strings, and alerting when a single host sends an abnormally high volume of these lengthy queries over a specific timeframe.

3. The Splunk Query & Logic

(Note: As always, adjust the index and sourcetype names if your network logging setup differs).

index=dns_exf sourcetype="bro:dns:json"
| eval len_query=len(query)
| search len_query>=40 AND query!="*.ip6.arpa*" AND query!="*amazonaws.com*" AND query!="*._googlecast.*" AND query!="*_ldap.*"
| bin _time span=24h
| stats count(query) as req_by_day by _time, id.orig_h, id.resp_h
| where req_by_day>60
| table _time, id.orig_h, id.resp_h, req_by_day

How it works:

In this lab: 17,116 long DNS queries in one day from one host to one destination, 13,402 distinct (~78%).


21. Detecting Ransomware

1. What is Ransomware (SMB Execution)?

When ransomware infects a machine, it often traverses the network using the Server Message Block (SMB) protocol to find and encrypt files stored on shared drives. Attackers typically use one of two distinct approaches over SMB to lock down these files:

2. How do you detect it?

Because these operations are happening over a network share, you can detect them by monitoring SMB file operations using a network monitoring tool like Zeek.

3. The Splunk Queries & Logic

(Note: As always, adjust the index and sourcetype names if your network logging setup differs).

Detecting the Overwrite Approach:

index="ransomware_open_rename_sodinokibi" sourcetype="bro:smb_files:json"
| where action IN ("SMB::FILE_OPEN", "SMB::FILE_RENAME")
| bin _time span=5m
| stats count by _time, source, action
| where count>30
| stats sum(count) as count values(action) dc(action) as uniq_actions by _time, source
| where uniq_actions==2 AND count>100

How it works:

Detecting the Renaming Approach (Anomalous Extensions):

index="ransomware_new_file_extension_ctbl_ocker" sourcetype="bro:smb_files:json" action="SMB::FILE_RENAME"
| bin _time span=5m
| rex field="name" "\.(?<new_file_name_extension>[^\.]*)$"
| rex field="prev_name" "\.(?<old_file_name_extension>[^\.]*)$"
| stats count by _time, id.orig_h, id.resp_p, name, source, old_file_name_extension, new_file_name_extension
| where new_file_name_extension!=old_file_name_extension
| stats count by _time, id.orig_h, id.resp_p, source, new_file_name_extension
| where count>20
| sort -count

How it works:

Overwrite approach: looks for high SMB::FILE_OPEN + SMB::FILE_RENAME volume from one host in a short window.

Renaming approach: looks for many files renamed to the same new extension in a short window.

In this lab: the overwrite query returned 22,073 combined open/rename actions from one source in one 5-minute window; the renaming query returned 4,227 files all renamed to .zhqxelf by one source against one host in the same window.

Skill Assessment

The skill assessment walkthrough is longer and more step-by-step than the main hunt sections, so I kept it on a separate page: Module 6: Skill Assessment (Empire beaconing TimeInterval, PrintNightmare source IP, and BloodHound collector IP).

Key Takeaway

Splunk hunting here came down to picking the right Zeek log for the attack, then asking one of four math questions instead of looking for a tool name.

What stuck with me:

References

[HTB Academy] Certified Defensive Security Analyst (CDSA) - Module 6: Detecting Windows Attacks with Splunk. https://academy.hackthebox.com/

[SPL Threat-Hunting Library] My reusable, environment-agnostic Splunk query library, organized by attacker phase - this is where these queries (and others from the series) live in cleaned-up, placeholder-swappable form. https://github.com/kismatkunwar89/spl-threat-hunting-library