Incident Investigation Walkthrough: Splunk Boss of the SOC v1
2026-08
Context
Boss of the SOC (BOTS) is Splunk's blue-team CTF dataset: real log data (or realistic recreations of it) from a simulated breach, released for anyone to practise investigation on. Version 1, from 2016, centers on two linked stories: an external attacker ("Po1s0n1vy") defacing a Wayne Enterprises property site, imreallynotbatman.com, and a separate ransomware incident (Cerber) that hits an internal workstation at Wayne Enterprises weeks later.
The goal of this exercise was to set up my own Splunk instance, load the BOTS v1 dataset into it, and work the investigation myself using SPL, treating it exactly like a live incident: form a hypothesis, write a query, see what the data says, and follow wherever it leads, including the dead ends.
Setup
Splunk Enterprise was already running locally. BOTS v1 ships in a
few formats; the officially recommended one is a
pre-indexed archive that has to be extracted directly into
Splunk's app directory and loaded via a restart, not something a
browser can do on its own, so that one step (extracting
botsv1-attack-only.tgz, the 135MB attack-only subset,
and restarting Splunk) was run manually in a terminal. Everything
else, the download, the verification, and the entire investigation,
was done through the Splunk web UI.
Once the restart finished and indexing settled,
index=botsv1 earliest=0 confirmed the load:
955,807 events across 22 sourcetypes.
Sourcetype breakdown:
| Sourcetype | Events |
|---|---|
| XmlWinEventLog:Sysmon | 270,597 |
| stream:smb | 151,568 |
| suricata | 125,584 |
| WinEventLog:Security | 87,430 |
| WinRegistry | 74,720 |
| stream:ip | 62,083 |
| fgt_traffic | 55,279 |
| stream:tcp | 28,291 |
| fgt_utm | 25,586 |
| stream:http | 23,936 |
| iis | 22,615 |
The heavy weighting toward Sysmon, WinRegistry and stream:smb told me upfront that the attack-only subset would have much richer coverage of the endpoint/ransomware side of the story than the initial web-application compromise, which turned out to be exactly right, and shaped where the investigation could and couldn't go.
The investigation
1. First indicator of compromise: who's scanning the website?
index=botsv1 sourcetype=stream:http imreallynotbatman.com
| stats count by src_ip, http_user_agent | sort -count
One source IP, 40.80.148.42, accounts for 1,928 of the 10,010 matching HTTP-stream events, using a Chrome-spoofed user agent string. A follow-up search for the literal string "acunetix" scoped to that IP returns 17,469 hits, and a search for "joomla" against the site returns 19,751. So before anything else happens, someone is running the Acunetix web vulnerability scanner against a Joomla site. That's the first indicator of compromise: automated reconnaissance, well before any exploitation.
2. Initial access: how did they get in?
I tried to find the actual defacement (the modified homepage / uploaded image) first, since that's usually the most visible artifact of this kind of attack:
index=botsv1 sourcetype=stream:http dest_ip=192.168.250.70 (url=*batman* OR url=*poison*)
| table _time, url, http_method, src_ip
Zero results. So was
sourcetype=iis (poison OR batman), and a plain keyword
search for "poison" scoped to the web server. This is one of the
real dead ends of working from the attack-only (135MB) package
instead of the full 6.1GB dataset: that particular artifact doesn't
appear to have made the cut into the smaller subset. Rather than
keep guessing at field names, I went looking for the exploitation
itself instead:
index=botsv1 dest_ip=192.168.250.70 sourcetype=stream:http "multipart/form-data"
Four events. One of them is the payload: a POST to
/joomla/administrator/index.php?option=com_extplorer
(Joomla's file-manager component) with a multipart body containing
userfile[0] = 3791.exe and
userfile[1] = agent.php, complete
with the raw MZ/PE header ("This program cannot be run in DOS
mode") sitting in the capture, and a server response of
'success':true,'message':'Upload successful!'.
Timestamp: 2016-08-10 23:52:47 UTC, same source IP
as the recon traffic.
I went looking for an MD5 hash of that executable next, since
that's usually asked in these exercises. file_hash
and md5 came back empty on that event. Splunk Stream
wasn't configured to compute file hashes in this environment, so
that particular fact isn't recoverable from the network capture
alone; it would need an endpoint-side artifact (which, per the
timeline below, lands on a different host two weeks
later).
3. A second, separate compromise: the ransomware side
The web-server attack is dated August 10. Searching more broadly for ransomware indicators turns up a cluster of activity from August 24, two weeks later, and on a different machine entirely:
index=botsv1 we8105desk | stats count by host, sourcetype | sort -count
we8105desk is a literal hostname in the data: a
Windows workstation generating 117,611 Sysmon events and 34,289
Security events, logged in as WAYNECORPINC\bob.smith.
This is clearly a separate intrusion chain, not a continuation of
the web app compromise.
Pulling Sysmon process-creation events on that host around the same timeframe:
index=botsv1 host=we8105desk sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" (.tmp OR .vbs OR cerber)
The Microsoft Sysmon Splunk add-on wasn't installed (it's one of
seven prerequisite TAs listed for the full dataset), so these came
back as raw, unparsed XML instead of clean
CommandLine/Image fields, a second
honest limitation of a minimal setup. Reading the raw events
anyway: at 18:17:31 UTC, csc.exe (the
C# compiler) spawns cvtres.exe, compiling code staged
into %TEMP% (RES958E.tmp /
CSC958D.tmp). That's a living-off-the-land pattern,
using a trusted, signed Microsoft binary to compile and run a
payload in memory, consistent with a VBScript or macro-based
dropper that's trying to avoid writing an obviously malicious
executable to disk.
4. Ransomware detonation
index=botsv1 cerber | stats count by sourcetype
21,596 events reference "cerber" across fgt_traffic,
fgt_utm, WinEventLog:Security,
stream:smb, and suricata. Narrowing to
the firewall's IPS signatures:
index=botsv1 cerber sourcetype=fgt_utm | table _time, msg, srcip, dstip
At 18:49:41 UTC, 32 minutes after the in-memory
compile, the FortiGate fires 9,231 "Botnet: Cerber.Botnet" alerts
in the same second, all from 192.168.250.100
(we8105desk's IP), each one to a different address in
the 85.93.63.0/24 block. That's a known Cerber
technique: instead of one static C2 domain that's easy to
blocklist, the payload sprays connection attempts across an entire
/24 of decoy addresses.
5. Impact: does it stay on one machine?
index=botsv1 sourcetype=stream:smb (cerber OR readme OR ransom) | stats count by src_ip, dest_ip
152 SMB sessions from 192.168.250.100 go to 192.168.250.20, a file server, not the infected workstation, carrying ransom-note-related keywords. The ransomware reached at least one shared network drive, which is the difference between "one user's laptop is down" and "we need to check what else was mapped to that share."
Timeline
View the interactive timeline →
| Time (UTC) | Phase | Event |
|---|---|---|
| 2016-08-10 | Recon | 40.80.148.42 scans imreallynotbatman.com with Acunetix |
| 2016-08-10 23:52:47 | Initial access | 3791.exe + agent.php uploaded via Joomla com_extplorer |
| 2016-08-24 18:17:31 | Endpoint compromise | csc.exe → cvtres.exe in-memory compile on we8105desk (bob.smith) |
| 2016-08-24 18:49:41 | Ransomware detonation | Cerber C2 burst, 192.168.250.100 → 85.93.63.0/24 |
| 2016-08-24 (following) | Lateral impact | Ransomware reaches file server 192.168.250.20 over SMB |
What I'd check next
With the full 6.1GB dataset instead of the attack-only subset, the obvious next steps would be: recover the actual defacement artifact and the brute-force login attempts against the Joomla admin panel (both absent from this smaller package), pull a proper MD5/SHA256 on 3791.exe from an endpoint-side Sysmon file-creation event once the Sysmon TA is installed, and count how many files on the file server were actually touched or renamed by Cerber.
Lessons from doing this "for real" instead of just reading a walkthrough
- A missing prerequisite add-on doesn't block an investigation, it just changes the shape of the evidence. No Sysmon TA meant reading raw XML instead of clean fields, that's slower, not impossible.
- The size of the dataset you load determines the story you can tell. The attack-only package is excellent for the ransomware chain and nearly silent on the web-app defacement artifact itself, worth knowing before promising a stakeholder "the full picture."
- Dead ends are data too. A zero-result query against the right field names is often the fastest way to learn what isn't in your evidence, which matters as much as what is.