Nervi0z/splunk-blue-team
GitHub: Nervi0z/splunk-blue-team
面向 SOC 安全分析师的 Splunk SPL 速查手册与检测规则库,涵盖基础语法、常用命令及针对各类攻击场景的即用型威胁狩猎查询。
Stars: 1 | Forks: 0
面向使用 Splunk 的 SOC 分析师的 SPL 参考与检测查询库。内容涵盖从基础到威胁狩猎的搜索管道,并提供按攻击场景分类的即用型查询。
专为需要在调查过程中快速响应并构建能对真实攻击进行有效告警的检测逻辑的一级 (Tier 1) 和二级 (Tier 2) 分析师而设计。
## 目录
- [SPL 工作原理](#how-spl-works)
- [SPL 速查表](#spl-quick-reference)
- [核心命令](#core-commands)
- [时间与过滤](#time-and-filtering)
- [聚合与统计](#aggregation-and-statistics)
- [按场景分类的检测查询](#detection-queries-by-scenario)
- [威胁狩猎查询](#threat-hunting-queries)
- [字段提取与丰富化](#field-extraction-and-enrichment)
- [性能优化技巧](#performance-tips)
- [资源](#resources)
## SPL 工作原理
Splunk 通过管道从左到右处理查询。每个 `|`(管道符)将结果传递给下一个命令。
```
search terms → | command1 → | command2 → | command3 → results
```
第一部分(在第一个 `|` 之前)始终是一个搜索——它过滤原始事件。`|` 之后的所有内容都是对结果进行转换或展示。
```
index="security" EventCode=4625
| stats count by Account_Name
| sort - count
| head 10
```
此查询:查找失败的登录事件 → 按账户统计 → 按降序排序 → 显示前 10 条。
**任何 SPL 查询的三个阶段:**
1. **搜索** —— 从索引中过滤事件(`index=`、`sourcetype=`、字段值、关键词)
2. **转换** —— 聚合、计算、重塑(`stats`、`eval`、`timechart`、`rex`)
3. **展示** —— 格式化输出(`table`、`sort`、`head`、`rename`)
## SPL 速查表
**您 80% 的时间都会用到的命令:**
| 命令 | 功能 | 示例 |
|---------|-------------|---------|
| `index=` | 选择数据源 | `index="wineventlog"` |
| `sourcetype=` | 按数据类型过滤 | `sourcetype="cisco:asa"` |
| `\| stats count by X` | 按字段分组统计事件数 | `\| stats count by src_ip` |
| `\| stats dc(X) by Y` | 统计每个 Y 对应的 X 的不同值数量 | `\| stats dc(dest_port) by src_ip` |
| `\| timechart span=1h count` | 随时间变化的事件趋势 | `\| timechart span=1h count by action` |
| `\| sort - count` | 按计数降序排序 | `\| sort - count` |
| `\| head 20` | 显示前 N 条结果 | `\| head 20` |
| `\| table X Y Z` | 选择要显示的字段 | `\| table _time src_ip dest_ip action` |
| `\| eval X=...` | 计算新字段 | `\| eval severity=if(count>100,"high","low")` |
| `\| where X>Y` | 转换后过滤 | `\| where count > 50` |
| `\| rename X as Y` | 重命名字段 | `\| rename Account_Name as user` |
| `\| dedup X` | 移除重复值 | `\| dedup src_ip` |
| `\| top limit=10 X` | 显示最频繁的值 | `\| top limit=10 user_agent` |
## 核心命令
### 搜索事件
```
index="wineventlog"
index="security" sourcetype="WinEventLog:Security"
index="firewall" action=blocked
host="srv-dc01" EventCode=4625
"failed password" source="/var/log/auth.log"
```
字段包含多个值时使用 `OR` 或括号:
```
index="security" (EventCode=4624 OR EventCode=4625 OR EventCode=4634)
```
通配符匹配:
```
index="proxy" uri="*.exe" OR uri="*.ps1" OR uri="*.bat"
src_ip="10.0.0.*"
Account_Name!="*$" -- exclude machine accounts
```
### 在原始事件中进行关键词搜索
```
index="security" "privilege escalation"
index="web" "cmd.exe" OR "powershell.exe"
index="mail" "phishing" OR "malware" OR ".exe attachment"
```
## 时间与过滤
务必指定时间范围。无限制的搜索既慢又耗费资源。
**相对时间(最常用):**
```
index="security" earliest=-24h latest=now
index="security" earliest=-7d@d latest=@d
index="security" earliest=-1h@h latest=@h
```
**绝对时间:**
```
index="security" earliest="2024-12-01T00:00:00" latest="2024-12-01T23:59:59"
```
**时间修饰符说明:**
- `@h` = 对齐到当前小时的开始
- `@d` = 对齐到当前天的开始
- `-24h` = 24 小时前
- `-7d@d` = 7 天前的一天开始时刻
**转换后过滤结果:**
```
| where count > 100
| where src_ip != "10.0.0.1"
| where isnotnull(user)
| where match(process_name, "(?i)powershell|cmd|wscript")
```
## 聚合与统计
### `stats` —— 核心主力命令
```
-- Count events by field
| stats count by src_ip
-- Multiple aggregations
| stats count, dc(dest_port) as unique_ports, values(dest_port) as ports by src_ip
-- Count and earliest/latest timestamp
| stats count, min(_time) as first_seen, max(_time) as last_seen by Account_Name
-- Sum and average
| stats sum(bytes) as total_bytes, avg(bytes) as avg_bytes by host
-- All distinct values as a list
| stats values(src_ip) as source_ips by user
```
### `timechart` —— 事件时间趋势图
```
-- Event count per hour
| timechart span=1h count
-- Count by category over time
| timechart span=1h count by action
-- Average bytes per hour by host
| timechart span=1h avg(bytes) by host
-- Limit to top N series
| timechart span=1h count by src_ip limit=5
```
### `eval` —— 计算新字段
```
-- Classify severity
| eval severity=if(count>500,"critical", if(count>100,"high","medium"))
-- Combine fields
| eval src_dest=src_ip + " -> " + dest_ip
-- Convert bytes to MB
| eval size_mb=round(bytes/1024/1024, 2)
-- Extract hour from timestamp
| eval hour=strftime(_time, "%H")
-- Detect executable extensions
| eval is_exe=if(match(uri, "(?i)\.(exe|ps1|bat|vbs|js|hta)$"), "yes", "no")
```
### `rex` —— 使用正则表达式提取字段
```
-- Extract an IP from a raw message field
| rex field=_raw "src=(?P
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
-- Extract username from Windows event message
| rex field=Message "Account Name:\s+(?P\S+)"
-- Extract command line arguments
| rex field=CommandLine "(?P[^\s]+)\s+(?P.*)"
```
## 按场景分类的检测查询
针对常见 SOC 检测场景的即用型查询。请根据您的环境调整索引名称和阈值。
### 身份验证 —— 暴力破解与凭证攻击
**按账户统计的失败登录(Windows EventCode 4625):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4625
Account_Name!="*$"
| stats count by Account_Name, Logon_Type, Workstation_Name
| sort - count
| where count > 10
```
**暴力破解:单一来源尝试多个账户:**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4625 earliest=-1h
| stats dc(Account_Name) as unique_accounts, count by Source_Network_Address
| where unique_accounts > 5
| sort - unique_accounts
```
**多次失败后成功登录(潜在的暴力破解成功):**
```
index="security" sourcetype="WinEventLog:Security" (EventCode=4625 OR EventCode=4624) earliest=-1h
| stats count(eval(EventCode=4625)) as failures,
count(eval(EventCode=4624)) as successes
by Account_Name
| where failures > 10 AND successes > 0
| eval ratio=round(failures/successes, 1)
| sort - failures
```
**账户锁定(EventCode 4740):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4740 earliest=-24h
| stats count by Account_Name, Subject_Account_Name
| sort - count
```
**非工作时间登录:**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4624 Logon_Type=10 earliest=-24h
| eval hour=strftime(_time, "%H")
| where hour < "08" OR hour > "18"
| table _time, Account_Name, Source_Network_Address, hour
| sort - _time
```
### 横向移动
**RDP 连接(EventCode 4624, Logon_Type=10):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4624 Logon_Type=10 earliest=-24h
| stats count, values(Source_Network_Address) as sources by Account_Name, host
| where count > 3
```
**PsExec 或远程服务安装(EventCode 7045):**
```
index="wineventlog" sourcetype="WinEventLog:System" EventCode=7045 earliest=-24h
| table _time, host, ServiceName, ImagePath, ServiceType
| where match(ServiceName, "(?i)psexec|remcom|paexec")
OR match(ImagePath, "(?i)\\\\admin\$|\\\\c\$|\\\\ipc\$")
```
**哈希传递指标(EventCode 4624, Logon_Type=3, NTLM):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4624
Logon_Type=3 Authentication_Package=NTLM earliest=-1h
Account_Name!="*$" Account_Name!="ANONYMOUS LOGON"
| stats count by Account_Name, Source_Network_Address, host
| sort - count
```
**SMB 访问管理共享(EventCode 5140):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=5140 earliest=-24h
(Share_Name="\\\\*\\ADMIN$" OR Share_Name="\\\\*\\C$" OR Share_Name="\\\\*\\IPC$")
| stats count by Account_Name, Source_Network_Address, Share_Name, host
| sort - count
```
### 持久化
**计划任务创建(EventCode 4698):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4698 earliest=-24h
| table _time, host, Account_Name, TaskName, TaskContent
| sort - _time
```
**安装新服务(EventCode 7045):**
```
index="wineventlog" sourcetype="WinEventLog:System" EventCode=7045 earliest=-24h
| table _time, host, ServiceName, ImagePath, AccountName
| sort - _time
```
**注册表 Run 键修改(Sysmon EventCode 13):**
```
index="sysmon" EventCode=13 earliest=-24h
(TargetObject="*\\CurrentVersion\\Run*" OR TargetObject="*\\CurrentVersion\\RunOnce*")
| table _time, host, User, TargetObject, Details
| sort - _time
```
### 进程执行与 Living-off-the-Land
**可疑的 PowerShell 执行(Sysmon EventCode 1):**
```
index="sysmon" EventCode=1 earliest=-24h
Image="*\\powershell.exe"
| where match(CommandLine, "(?i)encodedcommand|bypass|hidden|downloadstring|invoke-expression|iex|webclient|downloadfile|base64")
| table _time, host, User, CommandLine, ParentImage
| sort - _time
```
**LOLBins —— Living off the Land 二进制文件:**
```
index="sysmon" EventCode=1 earliest=-24h
| where match(Image, "(?i)certutil|mshta|wscript|cscript|regsvr32|rundll32|msiexec|installutil|msbuild")
| table _time, host, User, Image, CommandLine, ParentImage
| sort - _time
```
**PowerShell 脚本块日志记录(EventCode 4104):**
```
index="powershell" sourcetype="WinEventLog:Microsoft-Windows-PowerShell/Operational"
EventCode=4104 earliest=-24h
| where match(ScriptBlockText, "(?i)invoke-mimikatz|invoke-shellcode|downloadstring|net\.webclient|new-object.*webclient|convertto-securestring|start-bitstransfer")
| table _time, host, UserID, ScriptBlockText
| sort - _time
```
### 网络 —— 防火墙与代理
**被阻止的主要来源 IP:**
```
index="firewall" action=blocked earliest=-24h
| stats count by src_ip
| sort - count
| head 20
```
**高连接量(可能的 C2 信标):**
```
index="firewall" earliest=-1h
| stats count by src_ip, dest_ip, dest_port
| where count > 200
| sort - count
```
**指向可疑 TLD 的 DNS 查询:**
```
index="dns" earliest=-24h
| rex field=query "\.(?P[^.]+)$"
| where match(tld, "(?i)^(tk|ml|ga|cf|gq|pw|xyz|top|cc|ru)$")
| stats count, dc(query) as unique_domains by src_ip, tld
| sort - count
```
**大量出站数据传输:**
```
index="proxy" earliest=-24h
| stats sum(bytes_out) as total_out by src_ip, dest_host
| eval total_mb=round(total_out/1024/1024, 1)
| where total_mb > 100
| sort - total_mb
```
**连接到罕见外部 IP(异常):**
```
index="firewall" action=allowed dest_ip!="10.*" dest_ip!="192.168.*" dest_ip!="172.16.*" earliest=-1h
| stats count by src_ip, dest_ip, dest_port
| where count < 3
| sort - _time
```
## 威胁狩猎查询
基于假设的搜索,用于查找尚未触发警报的攻击者。
**狩猎:Kerberoasting(4769, RC4 加密):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4769 earliest=-24h
Ticket_Encryption_Type=0x17
Service_Name!="*$"
| stats count by Account_Name, Service_Name, Client_Address
| sort - count
```
**狩猎:信标——定期连接外部 IP:**
```
index="proxy" earliest=-6h dest_ip!="10.*" dest_ip!="192.168.*"
| stats count, avg(eval(floor(_time/300)*300)) as bucket_avg by src_ip, dest_ip
| where count > 20
| eval regularity=round(bucket_avg, 0)
| sort - count
```
**狩猎:凭证转储(LSASS 访问, Sysmon 10):**
```
index="sysmon" EventCode=10 earliest=-24h
TargetImage="*\\lsass.exe"
| where NOT match(SourceImage, "(?i)svchost|MsMpEng|WerFault|taskmgr|csrss")
| table _time, host, SourceImage, SourceUser, GrantedAccess
| sort - _time
```
**狩猎:异常的父子进程关系:**
```
index="sysmon" EventCode=1 earliest=-24h
| where match(ParentImage, "(?i)winword|excel|outlook|powerpnt|acrord32|chrome|firefox")
AND match(Image, "(?i)cmd|powershell|wscript|cscript|mshta|certutil")
| table _time, host, User, ParentImage, Image, CommandLine
| sort - _time
```
**狩猎:创建新用户账户(EventCode 4720):**
```
index="security" sourcetype="WinEventLog:Security" EventCode=4720 earliest=-7d
| table _time, host, Subject_Account_Name, Target_Account_Name
| sort - _time
```
## 字段提取与丰富化
**`lookup` —— 使用外部数据丰富:**
```
index="firewall"
| lookup threat_intel_ips src_ip OUTPUT threat_level, threat_type
| where isnotnull(threat_level)
| table _time, src_ip, dest_ip, threat_level, threat_type
```
**`inputlookup` —— 直接搜索查找表:**
```
| inputlookup threat_intel_ips
| where threat_level="critical"
```
**`iplocation` —— 为 IP 添加地理数据:**
```
index="firewall" action=allowed earliest=-24h dest_ip!="10.*"
| iplocation dest_ip
| stats count by dest_ip, Country, City
| sort - count
```
**`transaction` —— 将相关事件分组:**
```
index="security" sourcetype="WinEventLog:Security" (EventCode=4624 OR EventCode=4634)
Account_Name!="*$"
| transaction Account_Name, host startswith=EventCode=4624 endswith=EventCode=4634 maxspan=8h
| eval session_duration=round(duration/60, 1)
| table _time, Account_Name, host, session_duration
| sort - session_duration
```
## 性能优化技巧
始终先过滤,后转换。越早缩小事件范围,查询越快。
```
-- Slow: transforms all events then filters
index="security" | stats count by user | where count > 100
-- Fast: filter before transforming
index="security" EventCode=4625 | stats count by user | where count > 100
```
在每个查询中使用 `index=` 和 `sourcetype=` —— 切勿跨所有索引搜索。
指定时间范围。默认值为 24 小时,但没有明确时间的查询行为不可预测。
调试时,在开销较大的命令前添加 `| head 100` 以在样本上进行测试:
```
index="security" EventCode=4625
| head 100
| stats count by Account_Name
```
尽可能使用 `_time` 而不是转换时间戳——它是 Splunk 的原生时间字段,并且始终被索引。
## 资源
- [Splunk SPL 文档](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/WhatsInThisManual)
- [Splunk Security Essentials](https://splunkbase.splunk.com/app/3435/) —— 包含检测内容的免费 App
- [Boss of the SOC (BOTS)]() —— 用于练习的 Splunk CTF 数据集
- [TryHackMe — Splunk Rooms](https://tryhackme.com/hacktivities?tab=search&search=splunk)
- [Splunk 社区](https://community.splunk.com/)
## 贡献
欢迎提交 Issue 以建议新的检测查询、修正或额外场景。欢迎 Pull Request。
流程请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
许可证:[MIT](LICENSE)标签:AMSI绕过, GitHub开源, PB级数据处理, PE 加载器, PoC, Rex, SPL, Splunk命令, Splunk查询, Stats, Tier 1, Tier 2, 企业安全, 威胁检测, 字段提取, 安全运维, 安全运营中心, 数据聚合, 暴力破解, 检测规则, 横向移动, 红队行动, 编程规范, 网络安全, 网络映射, 网络资产发现, 网络资产管理, 蓝队战术, 隐私保护