Build a Mini SOC Lab with Splunk
Ingest attack data into Splunk and write SPL queries to detect threats.
Introduction
30 Second Summary
Every time you log into your bank account, swipe your badge at work, or connect to Wi-Fi, a security event is recorded somewhere. Security Operations Center (SOC) Analysts are the people who monitor those events and catch attackers in real time.
In this project, you will build a Mini SOC Lab on your Windows PC using Python and Splunk. You will go from generating simulated attack data to creating automated alerts that catch the attackers.
What You'll Build
A local Security Information and Event Management (SIEM) lab that simulates the daily work of a Tier 1 SOC Analyst, from log ingestion to automated alerting.
By the end of this project, you'll have:
- A Python script that generates realistic security events simulating brute-force attacks, port scans, and encoded PowerShell execution.
- A Splunk instance running locally with your simulated data ingested and searchable.
- Three SPL detection queries that identify each attack pattern in the log data, plus an automated alert for one detection.
- Secret Mission: Write a professional incident report documenting your findings, just like a real SOC Analyst would.
Are there any prerequisites?
You need a Windows PC running Windows 10 or newer. No prior cybersecurity or programming experience is needed.
Set Up Python and Splunk
Your SOC Lab needs two core tools. Python generates the simulated attack data that mimics real-world cyberattacks.
Splunk Enterprise acts as the SIEM. It ingests your security logs and lets you search through them to find threats. In this step, you'll install both tools on your Windows PC.
In this step, get ready to:
- Install Python 3.13.14 on your PC.
- Install Splunk Enterprise 10.4.0 and access the web interface.
- Verify both tools are running.
Install Python 3.13
Python powers the script that generates simulated security events. You need it installed and accessible from the command line.
- Press the Windows key to open your search bar.
- Type PowerShell and press Enter to open it.
What is PowerShell?
PowerShell is the command-line tool built into Windows. You'll use it to run Python scripts and check that your tools are installed correctly.
- Check if Python is already installed by running this command:
python --version
✔️ I see Python 3.13 or higher
Python 3.13 or higher is already installed and ready to go. Skip ahead to the next substep.
ⓧ I see an older version
You have Python installed, but this project uses 3.13. Installing Python 3.13.14 will add it alongside your existing version and update which version runs when you type python.
- Go to the Python 3.13.14 release page in your browser.
- Scroll down to the Files table and click Windows installer (64-bit) (marked as Recommended).
- Run the downloaded installer.
- Check the Add Python to PATH checkbox at the bottom of the installer window before doing anything else.
- Click Install Now.
- Close the installer when it finishes.
- Close your PowerShell window and open a new one to pick up the updated PATH.
- Confirm the installation by running the version check again:
python --version
You should see Python 3.13.14 in the output.
ⓧ 'python' is not recognized
Python isn't installed on your PC yet. Let's install it now.
- Go to the Python 3.13.14 release page in your browser.
- Scroll down to the Files table and click Windows installer (64-bit) (marked as Recommended).
- Run the downloaded installer.
- Check the Add Python to PATH checkbox at the bottom of the installer window before doing anything else.
- Click Install Now.
- Close the installer when it finishes.
- Close your PowerShell window and open a new one to pick up the new PATH.
- Confirm the installation by running this command:
python --version
You should see Python 3.13.14 in the output.
Why Add Python to PATH?
The PATH tells Windows where to find programs when you type their name in PowerShell. Without this checkbox, you'd have to type the full file path to Python every time you wanted to run it.
Still not seeing Python 3.13.14?
Make sure you checked Add Python to PATH during installation. If you missed it, run the installer again, select Modify, and make sure the PATH option is checked.
You must close and reopen PowerShell after installing. The PATH update only takes effect in new terminal windows.
Help me troubleshoot my Python installation on Windows.
Install Splunk Enterprise
Splunk Enterprise is the SIEM platform you'll use to ingest and analyze security logs throughout this project. The installer is about 1 GB, so the download may take a few minutes depending on your internet connection.
What is a SIEM?
A SIEM (Security Information and Event Management) system collects logs from across an organization's network and makes them searchable. It's the primary tool SOC Analysts use to detect threats.
Think of it as a search engine for security events. Logs flow in, and you write queries to find suspicious patterns like brute-force attacks or port scans.
- Go to the Splunk Enterprise download page in your browser.
- Click Sign Up to create a free Splunk account if you don't already have one.
- Fill in the required fields and verify your email address.
- Once signed in, find the Windows section and download the .msi installer for version 10.4.0.
This is a large download
The Splunk Enterprise installer is about 1 GB. The download may take several minutes depending on your internet connection. While it downloads, feel free to read ahead.
Once the download finishes, you'll walk through the Splunk installer. It will ask you to accept a license agreement and set admin credentials.
- Double-click the downloaded .msi file to launch the installer.
- Check the box to accept the License Agreement.
- Keep the default install location (C:\Program Files\Splunk).
- When the installer asks for admin credentials, choose a username and password you will remember.
- Complete the installation. Splunk starts automatically as a Windows service once the install finishes.
Why remember your admin credentials?
You'll use this username and password to log into Splunk Web every time you open it. Write them down somewhere safe if needed.
Now let's confirm Splunk is running.
- Open your browser and go to http://localhost:8000.
- Log in with the admin username and password you just set.
You should see the Splunk Enterprise home screen. This is Splunk Web, the interface you'll use to search and analyze security logs throughout this project.
About your Splunk license
You're on a 60-day Enterprise Trial license with full functionality. No credit card is needed.
After the trial ends, Splunk converts to a perpetual Free license with a 500 MB per day indexing limit. This project generates well under that limit, so either license works perfectly.
Can't access Splunk Web?
Make sure you're going to http://localhost:8000 and not https. Splunk uses HTTP by default.
If the page still doesn't load, the Splunk service may not have started. Open a new PowerShell window as Administrator and run:
NET START splunkd
Then refresh http://localhost:8000 in your browser.
Help me get Splunk Web running at localhost:8000 on Windows.
Verify both tools are ready
Both tools are now installed and running on your Windows PC. Let's do a final check.
- Switch back to PowerShell and confirm that python --version returns Python 3.13.14.
- In your browser, confirm that http://localhost:8000 loads the Splunk Enterprise home screen.
What did you just set up?
Python is installed locally and ready to run scripts from PowerShell. You'll use it in the next step to generate simulated attack data.
Splunk Enterprise is running as a Windows service and accessible at http://localhost:8000. It's ready to ingest and search security data whenever you need it.
Your lab environment is ready. Next up, you'll write a Python script that generates realistic attack data to feed into Splunk.
Generate Attack Data with Python
Your tools are installed and ready to go. Now it's time to create the data that your SOC lab will analyze.
Every SIEM needs log data to work with. In a real SOC, this data flows in from firewalls, servers, and endpoints around the clock. For your lab, you will generate realistic security events using a Python script that simulates four common attack patterns.
In this step, get ready to:
- Create a project folder and Python script on your Desktop.
- Run the script to generate 95 simulated security events.
Create the Python script
The script you are about to create generates 95 security events across four attack scenarios. These events look like the kind of log entries a real SOC team sees flowing into their SIEM every day.
- In your PowerShell window, move to your Desktop by running this command:
cd ~\Desktop
- Create your project folder and move into it by running these commands:
mkdir mini-soc-lab
cd mini-soc-lab
- Confirm the folder exists by running:
ls
The folder should be empty for now. You should see no files listed.
- Create and open a new file called generate_events.py by running:
notepad generate_events.py
Notepad will ask to create the file
Since generate_events.py does not exist yet, Notepad will ask if you want to create a new file. Click Yes to create it.
You now have an empty Notepad window. You will paste the script code into it in three sections, building up the full file piece by piece.
- Paste the following code into the empty Notepad window to set up the imports, configuration, and the helper function:
import json
import random
from datetime import datetime, timedelta
OUTPUT_FILE = "security_events.jsonl"
SEED = 42
random.seed(SEED)
users = ["alice", "bob", "charlie", "diana", "admin"]
normal_ips = ["10.0.1.10", "10.0.1.20", "10.0.1.30", "10.0.1.40", "10.0.1.50"]
attacker_ips = ["185.244.25.10", "203.0.113.70"]
servers = ["web-01", "vpn-01", "dc-01", "mail-01", "helpdesk-01"]
base_time = datetime(2026, 6, 20, 8, 0, 0)
events = []
def make_event(timestamp, src_ip, user, server, action, event_type, detail="", country="DE"):
return {
"timestamp": timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"),
"src_ip": src_ip,
"user": user,
"server": server,
"action": action,
"event_type": event_type,
"detail": detail,
"country": country,
}
What does this code do?
This section sets up the building blocks for every event the script will generate.
- SEED = 42 locks the random number generator so the script produces the exact same 95 events every time you run it.
- The users, normal_ips, attacker_ips, and servers lists define the cast of characters in your simulated network.
- make_event() is a helper function that takes event details and returns a dictionary with fields like timestamp, src_ip, user, and action. Every event in the file will be built by this function.
You won't see a change yet. The next section adds the actual attack scenarios.
- Place your cursor at the end of the code you just pasted (after the closing } of the make_event function) and press Enter twice to create a blank line.
- Paste the following code to generate four attack scenarios:
# 1. Normal login events
for i in range(50):
t = base_time + timedelta(minutes=random.randint(0, 1440))
events.append(
make_event(
t,
random.choice(normal_ips),
random.choice(users),
random.choice(servers),
"success",
"login",
"Normal login",
"DE",
)
)
# 2. Brute force: 25 failed logins from attacker IP against user "bob"
for i in range(25):
t = base_time + timedelta(hours=2, minutes=i)
events.append(
make_event(
t,
attacker_ips[0],
"bob",
"vpn-01",
"failed",
"login",
"Invalid password",
"RU",
)
)
# Successful login after brute force
events.append(
make_event(
base_time + timedelta(hours=2, minutes=26),
attacker_ips[0],
"bob",
"vpn-01",
"success",
"login",
"Login after multiple failures",
"RU",
)
)
# 3. Port scan: one IP scanning 16 ports on web-01
scanned_ports = [21, 22, 23, 25, 53, 80, 110, 135, 139, 443, 445, 993, 1433, 3306, 3389, 8080]
for port in scanned_ports:
t = base_time + timedelta(hours=5, minutes=random.randint(0, 10))
events.append(
make_event(
t,
attacker_ips[1],
"unknown",
"web-01",
"connection",
"port_scan",
f"Port {port}",
"CN",
)
)
# 4. Encoded PowerShell execution
events.append(
make_event(
base_time + timedelta(hours=7),
"10.0.1.30",
"charlie",
"helpdesk-01",
"execution",
"process",
"powershell.exe -EncodedCommand SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0AA==",
"DE",
)
)
# 5. Impossible travel: alice logs in from DE, then JP 10 minutes later
events.append(
make_event(
base_time + timedelta(hours=9),
"10.0.1.10",
"alice",
"vpn-01",
"success",
"login",
"Normal login",
"DE",
)
)
events.append(
make_event(
base_time + timedelta(hours=9, minutes=10),
"45.76.200.5",
"alice",
"vpn-01",
"success",
"login",
"Login from different country",
"JP",
)
)
What do these attack scenarios simulate?
- Normal logins (50 events): Legitimate users logging into random servers from internal IPs. These create a baseline of normal activity.
- Brute-force attack (26 events): An attacker at 185.244.25.10 tries 25 passwords against user bob on vpn-01, then succeeds on attempt 26. The IP originates from Russia.
- Port scan (16 events): IP 203.0.113.70 probes 16 common ports on web-01, looking for open services to exploit.
- Encoded PowerShell (1 event): User charlie runs an obfuscated PowerShell command on helpdesk-01. Attackers encode commands to evade detection.
- Impossible travel (2 events): User alice logs in from Germany, then from Japan 10 minutes later. No human can travel that fast, so one of those logins is suspicious.
You won't see a change yet. The next section sorts the events and writes them to a file.
- Place your cursor at the very end of the code you just pasted and press Enter twice to create a blank line.
- Paste the following code to sort the events and write them to a file:
# Sort events by timestamp and write to JSONL
events.sort(key=lambda x: x["timestamp"])
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
for event in events:
f.write(json.dumps(event) + "\n")
print(f"Generated {len(events)} events in {OUTPUT_FILE}")
What does this code do?
- events.sort() arranges all 95 events in chronological order, just like a real log stream.
- The with open() block writes each event as a single line of JSON to security_events.jsonl. JSONL (JSON Lines) is a format where each line is a separate JSON object. Splunk handles this format natively.
- The final print() line confirms how many events were generated and where they were saved.
- Save the file by pressing Ctrl+S in Notepad.
Notepad saved the file with a .txt extension?
If you see generate_events.py.txt instead of generate_events.py, Notepad added a .txt extension. Delete the file, reopen Notepad, paste the code again, and use File > Save As. Change the Save as type dropdown to All Files (*.*) and name the file generate_events.py.
Help me fix my generate_events.py file
✔️ Awesome, I've got everything!
Great. Double check you have saved generate_events.py in your mini-soc-lab folder.
ⓧ I'd like to double check the full code
Here is the complete generate_events.py file. Compare your Notepad content against this and make sure they match.
import json
import random
from datetime import datetime, timedelta
OUTPUT_FILE = "security_events.jsonl"
SEED = 42
random.seed(SEED)
users = ["alice", "bob", "charlie", "diana", "admin"]
normal_ips = ["10.0.1.10", "10.0.1.20", "10.0.1.30", "10.0.1.40", "10.0.1.50"]
attacker_ips = ["185.244.25.10", "203.0.113.70"]
servers = ["web-01", "vpn-01", "dc-01", "mail-01", "helpdesk-01"]
base_time = datetime(2026, 6, 20, 8, 0, 0)
events = []
def make_event(timestamp, src_ip, user, server, action, event_type, detail="", country="DE"):
return {
"timestamp": timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"),
"src_ip": src_ip,
"user": user,
"server": server,
"action": action,
"event_type": event_type,
"detail": detail,
"country": country,
}
# 1. Normal login events
for i in range(50):
t = base_time + timedelta(minutes=random.randint(0, 1440))
events.append(
make_event(
t,
random.choice(normal_ips),
random.choice(users),
random.choice(servers),
"success",
"login",
"Normal login",
"DE",
)
)
# 2. Brute force: 25 failed logins from attacker IP against user "bob"
for i in range(25):
t = base_time + timedelta(hours=2, minutes=i)
events.append(
make_event(
t,
attacker_ips[0],
"bob",
"vpn-01",
"failed",
"login",
"Invalid password",
"RU",
)
)
# Successful login after brute force
events.append(
make_event(
base_time + timedelta(hours=2, minutes=26),
attacker_ips[0],
"bob",
"vpn-01",
"success",
"login",
"Login after multiple failures",
"RU",
)
)
# 3. Port scan: one IP scanning 16 ports on web-01
scanned_ports = [21, 22, 23, 25, 53, 80, 110, 135, 139, 443, 445, 993, 1433, 3306, 3389, 8080]
for port in scanned_ports:
t = base_time + timedelta(hours=5, minutes=random.randint(0, 10))
events.append(
make_event(
t,
attacker_ips[1],
"unknown",
"web-01",
"connection",
"port_scan",
f"Port {port}",
"CN",
)
)
# 4. Encoded PowerShell execution
events.append(
make_event(
base_time + timedelta(hours=7),
"10.0.1.30",
"charlie",
"helpdesk-01",
"execution",
"process",
"powershell.exe -EncodedCommand SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0AA==",
"DE",
)
)
# 5. Impossible travel: alice logs in from DE, then JP 10 minutes later
events.append(
make_event(
base_time + timedelta(hours=9),
"10.0.1.10",
"alice",
"vpn-01",
"success",
"login",
"Normal login",
"DE",
)
)
events.append(
make_event(
base_time + timedelta(hours=9, minutes=10),
"45.76.200.5",
"alice",
"vpn-01",
"success",
"login",
"Login from different country",
"JP",
)
)
# Sort events by timestamp and write to JSONL
events.sort(key=lambda x: x["timestamp"])
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
for event in events:
f.write(json.dumps(event) + "\n")
print(f"Generated {len(events)} events in {OUTPUT_FILE}")
Run the script and verify the output
Your script is saved. Time to run it and generate the attack data that Splunk will ingest.
- Switch back to your PowerShell window. You should still be inside the mini-soc-lab folder from earlier.
- Run the script by entering this command:
python generate_events.py
You should see this output in PowerShell:
Generated 95 events in security_events.jsonl
Seeing a syntax error or file not found?
- If PowerShell says it cannot find generate_events.py, make sure you are in the mini-soc-lab folder. Run cd ~\Desktop\mini-soc-lab and try again.
- If you see a Python syntax error, compare your file against the full code in the double-check tab above. A missing comma, quote, or parenthesis is the most common cause.
- If the file was saved as generate_events.py.txt, rename it by running Rename-Item generate_events.py.txt generate_events.py in PowerShell.
Help me debug my generate_events.py script
- Confirm the output file was created by running:
ls
You should see both generate_events.py and security_events.jsonl listed in the output.
- Open the generated file in Notepad to inspect its contents by running:
notepad security_events.jsonl
You should see rows of JSON data. Each line is one security event with fields like timestamp, src_ip, user, server, action, event_type, detail, and country.
Why simulate attack data instead of using real logs?
Real security logs require access to a production network and often contain sensitive information. Simulated data gives you a safe sandbox to practice detection techniques without any risk.
The attack patterns in your script mirror the same threats that real SOC teams encounter daily. The skills you build hunting these simulated attacks transfer directly to a production environment.
Your attack data is ready. Next up, you will upload this file into Splunk and start hunting for threats using SPL queries.
Ingest Data into Splunk and Explore
In the previous step, you generated 95 simulated security events covering brute-force attacks, port scans, encoded PowerShell, and impossible travel. The data is sitting in a file on your Desktop, but Splunk doesn't know it exists yet.
In this step, you'll upload that data into Splunk and start querying it with SPL (Search Processing Language). SPL is the query language SOC Analysts use every day to hunt for threats in log data.
In this step, get ready to:
- Upload security_events.jsonl into Splunk and create a custom source type.
- Run SPL queries to search, filter, and aggregate the log data.
- Explore Splunk's field extraction and interface.
Upload the data file to Splunk
Splunk can ingest data from many sources including live network streams, file monitors, and forwarded logs. For this lab, you'll use the simplest method: uploading a file directly through the web interface.
- In Splunk Web at http://localhost:8000, click Settings in the top menu bar.
- Click Add Data under the Data section.
- Click Upload.
- Under Select Source, click Select File and choose the security_events.jsonl file from the mini-soc-lab folder on your Desktop.
- On the Set Source Type page, Splunk auto-detects the format as _json. In the Source type field, clear the current value and type mini_soc.
- Select Create a new source type when the option appears.
- Accept the defaults in the dialog and click Save.
- On the Input Settings page, keep the index set to main.
- Click Review, then click Submit.
- Click Start Searching.
What is a source type?
A source type tells Splunk how to format and parse incoming data. By creating a custom source type called mini_soc, you give Splunk a label that groups all of your security events together. This makes it easy to target only your lab data in searches.
The index (main) is the data store where Splunk keeps the events. Think of the index as the filing cabinet and the source type as the label on each folder inside it.
You should see your events listed in the Splunk search results. The search app runs an automatic query against your uploaded data.
Not seeing any events?
Make sure the time range picker (to the right of the search bar) is set to All time. Splunk defaults to Last 24 hours, which may not include your generated events depending on their timestamps.
Also confirm that you selected security_events.jsonl (not generate_events.py) during the upload step. If you uploaded the wrong file, go to Settings > Add Data and repeat the process with the correct file.
help me troubleshoot why my Splunk upload isn't showing events
Run your first SPL searches
Now that your data is in Splunk, you can query it using SPL. Every SOC Analyst's day starts with SPL searches to sift through log data and surface suspicious activity.
- Search for all of your events by typing this query into the Splunk search bar and pressing Enter:
index=main sourcetype=mini_soc
- Set the time range picker (to the right of the search bar) to All time. This ensures Splunk searches across every event, not just the last 24 hours.
Why set the time range to All time?
Splunk defaults to searching the last 24 hours only. Your generated events have timestamps from a specific date, so they may fall outside that default window. Setting the range to All time guarantees you see every event in the index.
You should see all 95 events in the search results.
- Filter for only failed login attempts by entering this search:
index=main sourcetype=mini_soc action=failed
The results narrow down to only the events where the action field equals failed. These are the brute-force login attempts against user "bob" that your Python script generated.
- Count the failed logins grouped by IP address and username by entering this search:
index=main sourcetype=mini_soc action=failed | stats count by src_ip, user
What does this SPL query do?
The pipe (|) sends your filtered results into the stats command. The stats count by src_ip, user part groups the events by source IP and username, then counts how many events fall into each group.
This is the same technique SOC Analysts use to spot patterns in millions of log entries. Instead of scrolling through individual events, you summarize the data into a table that immediately highlights outliers.
The results table shows that IP 185.244.25.10 had 25 failed login attempts against user bob. You just found the brute-force attack pattern.
Seeing 0 results?
Double-check that the time range picker is still set to All time. Splunk sometimes resets it when you enter a new search.
Make sure you typed mini_soc (with an underscore) in the search, not mini-soc (with a hyphen). The source type must match the name you created during the upload step.
help me fix my SPL query that returns 0 results
Explore the Splunk interface
Beyond the search bar, Splunk's interface gives you tools to drill into individual events and understand the shape of your data at a glance.
- Run the base search again by entering this query:
index=main sourcetype=mini_soc
- Click on any event in the results list to expand it. You should see all of the extracted fields: timestamp, src_ip, user, server, action, event_type, detail, and country.
- On the left sidebar, look for src_ip under Selected Fields or Interesting Fields. Click on it to see a breakdown of all source IPs in the data.
How does Splunk extract fields from JSON?
Because your data is in JSON format, Splunk automatically recognizes the key-value pairs and turns each key into a searchable field. This is why you can filter on action=failed or group by src_ip without any extra configuration.
In a real SOC, not all log sources send clean JSON. Analysts often write custom field extractions to parse messy log formats. Your lab data keeps things simple so you can focus on the analysis, not the parsing.
You can now identify every field in your data and see how Splunk makes them available for searching. This field-level visibility is what makes a SIEM so powerful for threat hunting.
Your data is loaded, searchable, and you've already spotted a brute-force attack using SPL. Next up, you'll write three formal detection queries and turn one into an automated alert.
Write Detection Queries and Create Alerts
Your 95 security events are indexed in Splunk and ready for analysis. In the last step, you proved you can search and filter the data with SPL.
Raw logs sitting in a SIEM are useless until someone writes queries that surface the attacks hiding in the noise. In this step, you will write three SPL detection queries and turn one into an automated alert.
In this step, get ready to:
- Write three SPL detection queries that surface brute-force attacks, port scans, and suspicious PowerShell execution.
- Save one detection query as a scheduled Splunk alert.
- Review your complete detection pipeline.
Write three detection queries
Each detection query targets a specific attack pattern from your simulated data. You will enter these queries in the Splunk search bar and verify that they return the expected results.
Make sure the time range picker in Splunk is set to All time before running each query. The default time range may filter out your events.
- In the Splunk search bar, enter this SPL query to detect brute-force login attempts:
index=main sourcetype=mini_soc action=failed | stats count by src_ip, user | where count > 10
What does this query do?
- action=failed filters for only failed login events.
- stats count by src_ip, user groups the results by source IP and username, then counts how many failures each combination has.
- where count > 10 keeps only the combinations with more than 10 failures. This threshold catches brute-force patterns while ignoring the occasional typo.
- Press Enter to run the query.
- You should see one result: IP 185.244.25.10 with 25 failed login attempts against user bob.
Not seeing any results?
- Make sure the time range picker is set to All time. The default time range may filter out your events.
- Check that the query matches exactly. SPL field values like failed are case-sensitive.
- Confirm your sourcetype is mini_soc (not _json). You set this custom sourcetype during the upload step.
Why isn't my brute-force detection query returning results in Splunk?
- Clear the search bar and enter this query to detect port scanning activity:
index=main sourcetype=mini_soc event_type=port_scan | stats dc(detail) as unique_ports by src_ip, server | where unique_ports > 10
What does this query do?
- event_type=port_scan filters for port scan events only.
- dc(detail) is the distinct count function. It counts how many unique port numbers each IP connected to on each server.
- where unique_ports > 10 flags any IP that touched more than 10 unique ports. This is a strong indicator of reconnaissance.
- Press Enter to run the query.
- You should see one result: IP 203.0.113.70 scanned 16 unique ports on server web-01.
Query returning zero results?
- Double-check that you typed dc(detail) and not count(detail). The dc() function counts distinct values, while count() counts all values including duplicates.
- Verify event_type=port_scan uses an underscore, not a hyphen.
Why isn't my port scan detection query working in Splunk?
- Clear the search bar and enter this query to detect suspicious PowerShell execution:
index=main sourcetype=mini_soc event_type=process EncodedCommand | table timestamp, user, server, detail
What does this query do?
- event_type=process EncodedCommand searches for process execution events that contain the text "EncodedCommand" anywhere in the event data.
- Attackers use EncodedCommand to run Base64-encoded PowerShell, which hides the actual command from basic log review.
- table displays the results as a clean table with only the fields you specify.
- Press Enter to run the query.
- You should see one result: user charlie ran an encoded PowerShell command on server helpdesk-01.
Seeing zero results?
- Make sure EncodedCommand is capitalized exactly as shown. SPL keyword searches are case-sensitive.
Why isn't my PowerShell detection query returning results in Splunk?
What is detection engineering?
You just did exactly what a SOC Analyst does every day. You wrote detection logic in SPL to surface threats from raw log data.
In a real SOC, these queries would run against live data flowing in from firewalls, endpoints, and servers. The patterns are the same. Only the volume changes.
Save a detection as a Splunk alert
In a real SOC, analysts do not run queries manually all day. They save their best detection queries as automated alerts that run on a schedule and fire when a threat is detected.
- Run the brute-force detection query again by entering it in the search bar and pressing Enter:
index=main sourcetype=mini_soc action=failed | stats count by src_ip, user | where count > 10
- Click Save As above the search bar.
- Select Alert.
- In the Title field, enter Mini SOC - Excessive Failed Logins.
- Set Alert type to Scheduled.
- Set the schedule to run every 5 minutes.
- Under Trigger Conditions, set Trigger alert when to Number of Results.
- Set the condition to is greater than 0.
- Click Save.
Why schedule an alert?
In a real SOC, this alert would continuously monitor incoming logs. Every 5 minutes, Splunk runs the brute-force query against new data. If it finds results, the alert fires and a SOC Analyst gets notified to investigate.
- Click Activity in the top menu bar.
- Click Triggered Alerts.
Your alert "Mini SOC - Excessive Failed Logins" should appear in the alerts list.
Don't see your alert listed?
- Make sure you clicked Save after configuring all the alert settings.
- Check that you selected Scheduled as the alert type. Real-time alerts have a different configuration flow.
- The alert may take a moment to appear if it has not triggered yet. Check Settings then Searches, reports, and alerts to confirm the alert was saved.
Why isn't my Splunk alert showing up in Triggered Alerts?
Review your SOC detection pipeline
You now have a complete detection pipeline. Data flows from your Python script into Splunk, three detection queries surface attack patterns, and an automated alert watches for brute-force attempts.
- Click Settings in the top menu bar.
- Click Searches, reports, and alerts to see your saved alert listed alongside any other saved searches.
Your alert is visible and configured. You have built the core of what a SOC team operates daily.
What did you just build?
You built the same detection pipeline that SOC teams run in production: a SIEM with log data, detection logic written in SPL, and automated alerting. The only difference is scale.
A real SOC ingests millions of events per day from firewalls, endpoints, and cloud services. Your pipeline handles the same concepts at a manageable size, which is exactly how professionals prototype new detections before deploying them to production.
Secret mission
Write a Professional Incident Report
You've built detections that catch attackers. But in a real SOC, catching the threat is only half the job. Your next challenge is to document the brute-force attack in a professional incident report, just like you'd hand off to a Tier 2 analyst.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on your local machine, so there are no ongoing cloud costs.
Resources you used:
- Splunk Enterprise 10.4.0 installed at C:\Program Files\Splunk, running as a Windows service.
- Python 3.13.14 installed locally and added to PATH.
- The mini-soc-lab folder on your Desktop containing generate_events.py, security_events.jsonl, and incident_report.md.
Keep everything running
No action needed. Choose this if you want to keep practicing SPL queries or add more data to your lab.
- Leave Splunk running to continue exploring the data and writing new detection queries.
- Your Enterprise Trial license is valid for 60 days. After that, it converts to a perpetual Free license with 500 MB/day indexing.
- Keep the mini-soc-lab folder to reference your scripts and incident report.
- Python will remain installed on your system. It takes minimal disk space and does not run any background processes.
Pause - I'll come back to this later
Stop the Splunk service to free up system resources. Your data, saved alert, and source type configuration stay intact for when you return.
- Open an administrative command prompt. Press the Windows key, type cmd, right-click Command Prompt, and select Run as administrator.
- Stop the Splunk service by running this command:
NET STOP splunkd
- To restart Splunk later, open an administrative command prompt again and run:
NET START splunkd
- Your indexed data, saved alert, and mini_soc source type are all preserved.
Delete - I don't want to use this again
Remove all project resources from your machine.
Uninstall Splunk Enterprise:
- Press the Windows key, type Add or remove programs, and press Enter.
- Find Splunk Enterprise in the list of installed apps.
- Click on it and select Uninstall. Follow the prompts to complete the removal.
Reboot prompt
The Microsoft installer might present a reboot prompt during uninstall. You can safely ignore this request without rebooting.
Delete the project folder:
- Delete the mini-soc-lab folder by running this command in PowerShell:
Remove-Item -Recurse -Force ~\Desktop\mini-soc-lab
Optionally uninstall Python:
- To remove Python 3.13.14, go back to Add or remove programs, find Python 3.13.14 in the list, and select Uninstall.
Nice Work!
Nice Work!
You just built a fully functional Mini SOC Lab on your own Windows PC. You went from zero to a working SIEM detection pipeline, the exact skill set that SOC Analyst job postings ask for.
You've learned how to:
- Built a local SIEM lab by installing Splunk Enterprise and ingesting simulated security event data (brute-force attacks, port scans, encoded PowerShell, impossible travel) generated with a Python script.
- Wrote three SPL detection queries that identified brute-force login attempts, port scan activity, and suspicious PowerShell execution in your log data.
- Created an automated Splunk alert that continuously monitors for brute-force login patterns, just like a real SOC team's detection pipeline.
- Secret Mission: Wrote a professional incident report documenting the brute-force attack with real data from your SIEM, practicing the documentation skills that SOC Analysts use daily.
Ready to quiz yourself?