← Back to Lab Home

Splunk Detection Query Reference

Odapeeka Breach Scenario · All queries assume index=main host="odapeeka"

Phase 01 — Reconnaissance
T1595.001 · Active Scanning
nmap SYN scan from external attacker IP against odapeeka
Query 1A — Port scan detection (high volume, few paths)
index=main host="odapeeka" sourcetype="access_combined"
| stats count AS requests, dc(uri_path) AS unique_paths, values(status) AS status_codes BY clientip
| where requests > 5 AND unique_paths < 10
| sort -requests
| eval threat="Potential Port Scanner"
| rename clientip AS src_ip
| table src_ip, requests, unique_paths, status_codes, threat
Query 1B — Rapid connection bursts (60-second window)
index=main host="odapeeka" sourcetype="access_combined"
| bin _time span=60s
| stats count AS hits BY _time, clientip
| where hits > 30
| sort -hits
| eval threat="High-volume scanner"
| table _time, clientip, hits, threat
Query 1C — robots.txt access (recon indicator)
index=main host="odapeeka" sourcetype="access_combined" uri_path="/robots.txt"
| table _time, clientip, uri_path, status, bytes
| sort _time
Phase 02 — Web Enumeration
T1046 · Network Service Discovery
gobuster directory scan + manual browsing from attacker machine
Query 2A — Web scanner user-agent detection
index=main host="odapeeka" sourcetype="access_combined"
| search useragent="gobuster*" OR useragent="dirb*" OR useragent="dirbuster*" OR useragent="wfuzz*" OR useragent="feroxbuster*"
| stats count AS scans, values(uri_path) AS paths_hit BY clientip, useragent
| sort -scans
| eval threat="Web Directory Scanner Detected"
| table _time, clientip, useragent, scans, paths_hit, threat
Query 2B — High 404 rate from single IP (directory fuzzing)
index=main host="odapeeka" sourcetype="access_combined" status=404
| bin _time span=5m
| stats count AS not_found BY _time, clientip
| where not_found > 20
| sort -not_found
| eval threat="Directory Enumeration"
| table _time, clientip, not_found, threat
Phase 03 — Initial Access
T1190 · T1078 · T1110.001
SSH login as jchen using credentials from portal_config.bak
Query 3A — SSH brute force / password spray
index=main host="odapeeka" sourcetype="linux_secure" ("authentication failure" OR "Authentication failure")
| eval src_ip=coalesce(
    if(match(_raw,"rhost="),replace(_raw,".*rhost=([0-9\.]+).*","\1"),null()),
    if(match(_raw,"from [0-9]"),replace(_raw,".* from ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*","\1"),null()))
| eval user=coalesce(
    if(match(_raw,"user="),replace(_raw,".*\buser=(\S+)\s*$","\1"),null()),
    if(match(_raw,"for .* from"),replace(_raw,".* for (\S+) from.*","\1"),null()))
| stats count AS failures, dc(user) AS users_targeted, values(user) AS user_list BY src_ip
| where failures > 5 | sort -failures
| eval threat="SSH Brute Force"
| table src_ip, failures, users_targeted, user_list, threat
Query 3B — Successful login after failures (credential compromise)
index=main host="odapeeka" sourcetype="linux_secure"
  ("authentication failure" OR "Authentication failure" OR "Accepted publickey" OR "Accepted password")
| eval auth_result=case(
    match(_raw,"Accepted"),"Accepted",
    match(_raw,"failure"),"Failed",true(),"Other")
| eval src_ip=replace(_raw,".* from ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*","\1")
| eval user=replace(_raw,".* for (\S+) from.*","\1")
| where auth_result!="Other"
| stats values(auth_result) AS auth_events, count BY src_ip, user
| where like(mvjoin(auth_events," "),"%Failed%") AND like(mvjoin(auth_events," "),"%Accepted%")
| eval threat="Credential Stuffing — Failure then Success"
| table src_ip, user, auth_events, threat
Phase 04 — C2 Beacon
T1071.001 · Web Protocols
curl loop hitting /c2/beacon.php every ~30s from odapeeka itself
Query 4A — Beaconing detection (regular-interval HTTP)
index=main host="odapeeka" sourcetype="access_combined" uri_path="/c2/beacon.php"
| eval epoch=_time | sort epoch
| streamstats current=f window=1 last(epoch) AS prev_time
| eval interval=epoch-prev_time
| where isnotnull(interval)
| stats avg(interval) AS avg_interval_sec, stdev(interval) AS jitter, count AS beacon_count
    BY clientip, uri_path
| where beacon_count > 3
| eval regularity=if(jitter < 5, "HIGH (likely automated)", "MEDIUM")
| table clientip, uri_path, beacon_count, avg_interval_sec, jitter, regularity
Phase 05 — Internal Recon
T1059.004 · T1087 · T1082 · T1083
SSH session: id, whoami, uname, cat /etc/passwd, ls /home
Query 5A — Linux recon commands via auditd
index=main host="odapeeka" sourcetype="linux_audit" type=EXECVE
| eval cmd=replace(_raw, ".*\ba0=\"([^\"]+)\".*", "\1")
| search cmd IN ("id","whoami","uname","hostname","ifconfig","ip","netstat","ss","ps","env","last","who","w")
| stats count BY cmd, _time | sort _time
| table _time, cmd
Query 5B — Sensitive file access (passwd, shadow, sudoers)
index=main host="odapeeka" sourcetype="linux_audit" type=OPEN
| eval file=replace(_raw, ".*\bname=\"([^\"]+)\".*", "\1")
| where match(file, "passwd|shadow|sudoers|authorized_keys|crontab|proc/net")
| table _time, file, auid, uid | sort _time
Phase 06 — Exfiltration
T1560.001 · T1048.003
tar of /var/www/html + curl POST to external C2 IP
Query 6A — tar/zip archive creation (staging for exfil)
index=main host="odapeeka" sourcetype="linux_audit" type=EXECVE
| eval cmd=replace(_raw, ".*\ba0=\"([^\"]+)\".*", "\1")
| search cmd IN ("tar","zip","gzip","7z","rar")
| table _time, cmd, _raw | sort _time
Query 6B — Large outbound HTTP POST (data exfil)
index=main host="odapeeka" sourcetype="access_combined" method=POST
| where bytes > 10000
| table _time, clientip, uri_path, bytes, status, useragent | sort -bytes
| eval threat=if(bytes > 100000, "HIGH - Large Data Transfer", "MEDIUM - Elevated POST size")
Phase 07 — Ransomware
T1486 · T1490 · T1491.001
find + openssl encrypt all files + ransom note drop
Query 7A — Mass file encryption (openssl rapid execution)
index=main host="odapeeka" sourcetype="linux_audit" type=EXECVE
| eval cmd=replace(_raw, ".*\ba0=\"([^\"]+)\".*", "\1")
| search cmd="openssl" OR cmd="gpg"
| bin _time span=1m
| stats count AS encryptions BY _time
| where encryptions > 5
| eval threat="CRITICAL — Possible Ransomware Encryption"
| table _time, encryptions, threat
Query 7D — Website defacement (ransom note public)
index=main host="odapeeka" sourcetype="access_combined" uri_path="/RANSOM_NOTE.html"
| stats count AS views, dc(clientip) AS unique_visitors
| eval threat="CRITICAL — Defacement/Ransom Note Publicly Accessible"
| table views, unique_visitors, threat
Bonus — Full Attack Timeline
Correlated timeline across all log sources
index=main host="odapeeka" (sourcetype="access_combined" OR sourcetype="linux_secure" OR sourcetype="linux_audit")
| eval event_type=case(
    sourcetype="access_combined" AND match(uri_path, "robots.txt|backup|config|admin|staff"), "Phase 1-2: Recon/Enum",
    sourcetype="linux_secure" AND match(_raw, "Accepted password"), "Phase 3: Initial Access",
    sourcetype="access_combined" AND match(uri_path, "c2|beacon"), "Phase 4: C2 Beacon",
    sourcetype="linux_audit" AND match(_raw, "whoami|id|uname|passwd"), "Phase 5: Internal Recon",
    sourcetype="linux_audit" AND match(_raw, "tar|curl"), "Phase 6: Exfiltration",
    sourcetype="linux_audit" AND match(_raw, "openssl|ransom"), "Phase 7: Ransomware",
    true(), "Other")
| where event_type != "Other"
| table _time, sourcetype, event_type, _raw | sort _time