Module 4: Understanding Log Sources & Investigating with Splunk

Module 4 cover: SIEM monitoring illustration

The SPL queries on this page are from the practical exercises in each module section. I consolidated them here so they are easier to reference later.

This module covered Splunk architecture, SPL fundamentals, app deployment, and threat hunting across large datasets. I kept the Skill Assessment and additional hunting queries on separate pages because those walkthroughs are longer and more command-heavy.

Module 4 Navigation

On this page

Skill Assessment

Additional queries

Consolidated SPL from the module exercises, organized for reuse: spl-threat-hunting-library on GitHub

Splunk overview

Splunk is a highly scalable data analytics platform engineered to ingest, index, analyze, and visualize massive volumes of machine data. While widely utilized for IT monitoring and compliance, its capabilities as an analytics-driven Security Information and Event Management (SIEM) solution make it a critical tool for cybersecurity monitoring, incident response, and threat hunting.

Core Architecture Components

Splunk processes data through a multi-tier architecture, dividing tasks across specialized components:

Splunk multi-tier architecture: forwarders, indexers, search heads, and management nodes

Once the data path made sense, the module moved into how Splunk packages that data for daily use.

The Splunk Ecosystem

Architecture tells you where logs land. SPL is how you actually question them.

Search Processing Language (SPL) Essentials

The Search Processing Language (SPL) is the backbone of data analysis in Splunk, containing over a hundred commands for filtering and transforming data. Below is a reference table for the most critical foundational commands:

Command Description Example Usage
search Filters events. It is implicitly applied at the start of most queries but can be written explicitly. Supports boolean operators (AND, OR, NOT). search index="main" "UNKNOWN"
fields Specifies which fields to include or exclude (-) in the results. ... \| fields host, ComputerName
table Formats output into structured columns based on selected fields. ... \| table host, Image, CommandLine
rename Modifies the display name of a field in the output. ... \| rename ComputerName AS Host
dedup Removes duplicate events based on a specified field. ... \| dedup host
sort Orders results chronologically or numerically. Use - for descending. ... \| sort - _time
stats Performs statistical operations, such as counting events by specific criteria. ... \| stats count by Image
chart Prepares statistical data for visual graphs, grouping data into unique rows and columns. ... \| chart count by Image
eval Creates new custom fields or redefines existing ones (e.g., forcing lowercase). ... \| eval len=len(CommandLine)
rex Extracts entirely new fields from raw event data using Regular Expressions. ... \| rex field=Details "(?<file>[^\\]+)$"
lookup Enriches indexed data by matching it against an external file, like a CSV. ... \| lookup asset_lookup ip AS dest_ip
transaction Groups related events sharing common characteristics over a specified time window, useful for tracking sessions. ... \| transaction ComputerName, Image
[ ] (Subsearch) Nests a search to compute a set of results that filter the outer main search. ... NOT [ search index="main" ... ]

I was honestly overwhelmed with queries and what you could do with it, but yes and accepted it takes time in practice and moved on.

SPL command reference diagram from the module

SPL commands only help if you know what indexes, sourcetypes, and fields you actually have. The module covered two ways to find that out.

Data and Field Identification

Effectively leveraging Splunk requires understanding what data is actively being ingested. There are two primary approaches to discovering data sources, sourcetypes, and fields:

Method 1: Utilizing SPL Queries

Using SPL allows for rapid, granular discovery of the environment:

List all Indexes

| eventcount summarize=false index=* | table index

List all Sourcetypes

| metadata type=sourcetypes index=* | table sourcetype

List all Data Sources

| metadata type=sources index=* | table source

Summarize Field Metrics

sourcetype="WinEventLog:Security" | fieldsummary

Identify Rare Anomalies

index=* sourcetype=* | rare limit=10 index, sourcetype

Method 2: Utilizing the Web Interface

The UI helps a lot actually with understanding fields and making up queries.

The Splunk UI provides built-in visual tools to map out available data structures:

Splunk UI for exploring fields, sourcetypes, and data models

After discovery, the module walked through deploying a Sysmon app and pointing dashboards at the right index and sourcetype.

Configuring and Deploying Splunk Applications

From there the module shifted into hunting. Module 3 was mostly one machine and raw event review. Here the dataset was over 500,000 events across the network, and the point was to trace TTPs by pivoting search to search instead of staring at one log stream.

The core of this methodology rests on three pillars:

  1. Query Efficiency: Prioritizing targeted searches over generalized regex or wildcard queries to reduce resource consumption and improve return times.
  2. Sysmon Intelligence: Leveraging specific Event IDs to identify anomalies such as irregular parent-child process hierarchies, credential dumping via lsass.exe, and DCSync attacks depending upon what you are looking for.
  3. High-Fidelity Alerting: Crafting resilient alerts by systematically filtering out “benign noise” from Just-In-Time (JIT) compilers and system processes, specifically focusing on calls from “UNKNOWN” memory regions that often indicate shellcode execution.

Earlier I only did event analysis on Windows. Now doing it on more event logs from many machines is very fun.

Optimization of Search Queries

Effective hunting hinges on crafting queries that target relevant data while minimizing extraneous noise. Search performance varies significantly based on query structure:

index="main" *string*
index="main" ComputerName="*string*"

The walkthrough below is what the module used on the HTB Academy lab data. Same pivot pattern throughout: one finding leads to the next question.

Network-Scale Threat Hunting

Phase 1: Spotting the Initial Anomaly (Process Monitoring)

Step 1: Identify Available Data

index="main" sourcetype="WinEventLog:Sysmon" | stats count by EventCode

Step 2: Hunt for Abnormal Process Trees

index="main" sourcetype="WinEventLog:Sysmon" EventCode=1 (Image="*cmd.exe" OR Image="*powershell.exe") | stats count by ParentImage, Image

Step 3: Deep Dive into the Anomaly

index="main" sourcetype="WinEventLog:Sysmon" EventCode=1 (Image="*cmd.exe" OR Image="*powershell.exe") ParentImage="C:\Windows\System32\notepad.exe"

Phase 2: Tracing Lateral Movement

The download came from http://10.0.0.229:8080. Next I needed to know what that host was and which other machines talked to it.

Step 4: Pivot to the Malicious IP

index="main" 10.0.0.229 | stats count by sourcetype
index="main" 10.0.0.229 sourcetype="linux:syslog"

Step 5: Identify All Victims

index="main" 10.0.0.229 sourcetype="WinEventLog:sysmon" | stats count by CommandLine, host

Phase 3: Detecting Full Domain Compromise

A DCSync script on one of the victim hosts meant the hunt was no longer about a single box. I pivoted into AD logs to see if domain credentials were actually at risk.

Step 6: Verify the Privilege Escalation

index="main" EventCode=4662 Access_Mask=0x100 Account_Name!=*$

Phase 4: Investigating Credential Harvesting (lsass dumping)

The module also stepped back in the timeline. Before DCSync mattered, something had to get credentials off the host in the first place.

Step 7: Look for Memory Dumping

index="main" EventCode=10 lsass | stats count by SourceImage

Step 8: Inspect the Call Trace

index="main" EventCode=10 lsass SourceImage="C:\Windows\System32\notepad.exe"

Creating a High-Fidelity Alert

The UNKNOWN call trace was a good detection lead, but a raw alert on that string fired 1,575 times. The module then walked through stripping noise out layer by layer before calling it production-ready.

Step 9: Filtering the Alert Step-by-Step

Filter 1: Self-Access

index="main" CallTrace=" *UNKNOWN* " | where SourceImage!=TargetImage | stats count by SourceImage

Filter 2: JIT Compilers (.NET/C#)

index="main" CallTrace=" *UNKNOWN* " SourceImage!=" *Microsoft.NET* " CallTrace!= *ni.dll* CallTrace!= *clr.dll* | where SourceImage!=TargetImage | stats count by SourceImage

Filter 3: WOW64

index="main" CallTrace=" *UNKNOWN* " SourceImage!=" *Microsoft.NET* " CallTrace!= *ni.dll* CallTrace!= *clr.dll* CallTrace!= *wow64* | where SourceImage!=TargetImage | stats count by SourceImage

Filter 4: Explorer

index="main" CallTrace=" *UNKNOWN* " SourceImage!=" *Microsoft.NET* " CallTrace!= *ni.dll* CallTrace!= *clr.dll* CallTrace!= *wow64* SourceImage!="C:\Windows\Explorer.EXE" | where SourceImage!=TargetImage | stats count by SourceImage, TargetImage, CallTrace

Step 10: Think Like an Attacker (Alert Evasion)

Detecting Attacker Behavior: Spotting Known TTPs

After the full attack chain walkthrough, the module split detection into two styles. The first was Spot the Known: write searches around behaviors you already recognize (recon, PsExec, archives, odd ports, and similar TTPs).

Scenario 1: Detecting Reconnaissance (Living off the Land)

Attackers frequently use native Windows binaries (like net.exe or whoami.exe) to map the network and find privilege escalation opportunities without triggering antivirus alarms.

index="main" sourcetype="WinEventLog:Sysmon" EventCode=1 Image= *\ipconfig.exe OR Image=* \net.exe OR Image= *\whoami.exe OR Image=* \netstat.exe OR Image= *\nbtstat.exe OR Image=* \hostname.exe OR Image=*\tasklist.exe | stats count by Image,CommandLine | sort - count

Scenario 2: Catching Payloads on Whitelisted Domains

To bypass company proxies, attackers often host their malicious payloads on reputable, whitelisted domains like githubusercontent.com.

index="main" sourcetype="WinEventLog:Sysmon" EventCode=22  QueryName=" *github* " | stats count by Image, QueryName

Scenario 3: Exposing Lateral Movement (PsExec)

PsExec is a potent system admin tool that allows users to run commands on remote systems, often under the highest NT AUTHORITY\SYSTEM account. Attackers love it for lateral movement. It works by copying a service executable to a hidden admin share, modifying the registry, and using named pipes to communicate.

We can detect this using three different Sysmon Event IDs:

Query A: Registry Modifications (Event 13)

index="main" sourcetype="WinEventLog:Sysmon" EventCode=13 Image="C:\\Windows\\system32\\services.exe" TargetObject="HKLM\\System\\CurrentControlSet\\Services\\*\\ImagePath" | rex field=Details "(?<reg_file_name>[^\\\]+)$ " | eval reg_file_name = lower(reg_file_name), file_name = if(isnull(file_name),reg_file_name,lower(file_name)) | stats values(Image) AS Image, values(Details) AS RegistryDetails, values(_time) AS EventTimes, count by file_name, ComputerName

Phew phew Regex i am having hard time on it too just understood basics but its now on my list to atleast learn basics

PsExec detection regex example from the module

Query B: File Creation (Event 11)

index="main" sourcetype="WinEventLog:Sysmon" EventCode=11 Image=System | stats count by TargetFilename

Query C: Named Pipes (Event 18)

index="main" sourcetype="WinEventLog:Sysmon" EventCode=18 Image=System | stats count by PipeName

Scenario 4: Data Exfiltration via Archive Files

Attackers compress data into archive files (like .zip or .7z) before transferring it out of the network.

index="main" EventCode=11 (TargetFilename=" *.zip" OR TargetFilename="* .rar" OR TargetFilename="*.7z") | stats count by ComputerName, User, TargetFilename | sort - count

Scenario 5: Drive-By Downloads (PowerShell & MS Edge)

Attackers use PowerShell to fetch tools silently, or deceive users into downloading malware via their web browsers.

PowerShell download pivot

index="main" sourcetype="WinEventLog:Sysmon" EventCode=11 Image=" *powershell.exe* " |  stats count by Image, TargetFilename |  sort + count

MS Edge and Zone.Identifier pivot

index="main" sourcetype="WinEventLog:Sysmon" EventCode=11 Image=" *msedge.exe" TargetFilename=* "Zone.Identifier" |  stats count by TargetFilename |  sort + count

Scenario 6: Execution from Atypical Locations

Malware is frequently executed directly from the user’s Downloads folder, which is atypical for legitimate enterprise software.

index="main" EventCode=1 | regex Image="C:\\Users\\.* \\Downloads\\.*" |  stats count by Image

Scenario 7: Rogue Binaries Outside the Windows Directory

Legitimate system executables belong in specific protected folders. Malware often drops .exe or .dll files outside of the standard Windows directories.

index="main" EventCode=11 (TargetFilename=" *.exe" OR TargetFilename="* .dll") TargetFilename!=" *\windows\* " | stats count by User, TargetFilename | sort + count

Scenario 8: Misspelled Legitimate Binaries (Evasion)

Attackers try to hide by intentionally misspelling legitimate binaries (e.g., naming their malware psexe.exe instead of the legitimate PSEXESVC.exe).

index="main" sourcetype="WinEventLog:Sysmon" EventCode=1 (CommandLine=" *psexe* .exe" NOT (CommandLine="*PSEXESVC.exe" OR CommandLine="*PsExec64.exe")) OR (ParentCommandLine=" *psexe* .exe" NOT (ParentCommandLine="*PSEXESVC.exe" OR ParentCommandLine="*PsExec64.exe")) OR (ParentImage=" *psexe* .exe" NOT (ParentImage="*PSEXESVC.exe" OR ParentImage="*PsExec64.exe")) OR (Image=" *psexe* .exe" NOT (Image="*PSEXESVC.exe" OR Image="*PsExec64.exe")) |  table Image, CommandLine, ParentImage, ParentCommandLine

Scenario 9: Using Non-Standard Network Ports

Attackers often use non-standard ports to transfer tools or communicate with command-and-control servers.

index="main" EventCode=3 NOT (DestinationPort=80 OR DestinationPort=443 OR DestinationPort=22 OR DestinationPort=21) | stats count by SourceIp, DestinationIp, DestinationPort | sort - count

Known TTP searches are precise, but an attacker can rename a binary or change a port and slip past them. The module then moved into Spot the Unusual. I am not great at the maths side of it, but the idea clicked once I saw it on real Sysmon data.

Statistical Anomaly Detection: Spot the Unusual

Instead of hunting a specific malicious string, these searches baseline normal behavior and flag drift with streamstats, eventstats, and transaction.

Scenario 1: Uncovering Network Beacons & Data Exfiltration

Malware often communicates with Command and Control (C2) servers or exfiltrates data, causing an unusual spike in network connections.

index="main" sourcetype="WinEventLog:Sysmon" EventCode=3 | bin _time span=1h | stats count as NetworkConnections by _time, Image | streamstats time_window=24h avg(NetworkConnections) as avg stdev(NetworkConnections) as stdev by Image | eval isOutlier=if(NetworkConnections > (avg + (0.5*stdev)), 1, 0) | search isOutlier=1

Scenario 2: Catching Obfuscated and Abnormally Long Commands

Attackers frequently employ excessively long, obfuscated command lines to execute malicious scripts or bypass security filters.

index="main" sourcetype="WinEventLog:Sysmon" Image=*cmd.exe ParentImage!="*msiexec.exe" ParentImage!="*explorer.exe" | eval len=len(CommandLine) | table User, len, CommandLine | sort - len

Scenario 3: Spikes in Command-Line Activity

Sometimes the command itself isn’t anomalous, but the frequency is. A sudden burst of cmd.exe executions could indicate an automated malicious script running.

index="main" EventCode=1 (CommandLine=" *cmd.exe* ") | bucket _time span=1h | stats count as cmdCount by _time User CommandLine | eventstats avg(cmdCount) as avg stdev(cmdCount) as stdev | eval isOutlier=if(cmdCount > avg+1.5*stdev, 1, 0) | search isOutlier=1

Scenario 4: Malware Unpacking (Rapid DLL Loading)

It is highly common for malware to unpack itself and load multiple different DLLs in rapid succession to execute its payload.

index="main" EventCode=7 NOT (Image="C:\Windows\System32*") NOT (Image="C:\Program Files (x86) *") NOT (Image="C:\Program Files* ") NOT (Image="C:\ProgramData*") NOT (Image="C:\Users\waldo\AppData*") | bucket _time span=1h | stats dc(ImageLoaded) as unique_dlls_loaded by _time, Image | where unique_dlls_loaded > 3 | stats count by Image, unique_dlls_loaded | sort - unique_dlls_loaded

Scenario 5: Correlating Duplicate Process Executions

If the exact same process is executed repeatedly on the same computer, it can indicate malicious persistence mechanisms or process injection.

index="main" sourcetype="WinEventLog:Sysmon" EventCode=1 | transaction ComputerName, Image | where mvcount(ProcessGuid) > 1 | stats count by Image, ParentImage
index="main" sourcetype="WinEventLog:Sysmon" EventCode=1 | transaction ComputerName, Image | where mvcount(ProcessGuid) > 1 | search Image="C:\Windows\System32\rundll32.exe" ParentImage="C:\Windows\System32\svchost.exe" | table CommandLine, ParentCommandLine

Too many queries too many scenarios but I learnt a lot in this module and yes.

Threat hunting in a massive environment is not about writing a single perfect query; it is about building a layered defense. By establishing a profile of normal behavior and utilizing statistical models to identify deviations, you can detect compromises much more rapidly.

The most successful security teams combine the precision of “Spot the Known” (TTP monitoring) with the broad, dynamic safety net of “Spot the Unusual” (Anomaly analysis) to ensure that no matter how an attacker maneuvers, they leave a measurable trace in the logs.

Key Takeaway

Splunk hunting at scale is less about memorizing every SPL command and more about knowing what to pivot on next. The module walked architecture and SPL first, then showed how one finding should lead to the next question across a large dataset.

What stuck with me:

I consolidated the practical exercise queries on this page, and I am building them out in spl-threat-hunting-library so they are easier to reference and reuse later.

Where AI Can Help

I used Claude Code as an assistant while working through this module, mainly for generating SPL query drafts and thinking through the next pivot when I got stuck on a hunt step.

What it helped with:

  1. First-pass SPL for longer searches (rex, streamstats, transaction, alert tuning).
  2. Suggesting what to pivot on after a discovery (for example, IP to sourcetype, injector to child processes).
  3. Cleaning up rough query notes into something I could paste into Splunk and test.

What I still had to do myself:

  1. Run every query against the real dataset and confirm field names.
  2. Decide whether the output actually answered the question.
  3. Own the hunt logic and the final call on what was suspicious.

Same balance as Module 3: AI speeds up the draft and the pivot ideas, but the analyst still owns the evidence.

References

[HTB Academy] Certified Defensive Security Analyst (CDSA) - Module 4: Understanding Log Sources & Investigating with Splunk. https://academy.hackthebox.com/

[spl-threat-hunting-library] Environment-agnostic Splunk SPL threat-hunting queries from CDSA Module 4, organized by attacker phase. https://github.com/kismatkunwar89/spl-threat-hunting-library

[SwiftOnSecurity] sysmon-config (Sysmon configuration baseline referenced across hunting scenarios). https://github.com/SwiftOnSecurity/sysmon-config

Skill Assessment and Additional Queries

The module notes above are the reference material. The skill assessment and the extra searches I ran afterward are where I applied the same pivot habit to specific questions.