Splunk CVE-2018-11409认证绕过漏洞深度解析
1. 这个CVE不是“能打”而是“必须懂”:Splunk Web接口的认证绕过到底有多危险
你有没有遇到过这样的情况:在渗透测试报告里看到CVE-2018-11409,标题写着“Splunk Enterprise Web界面未授权访问漏洞”,但翻遍公开PoC,要么是Python脚本调用几个HTTP请求就完事,要么是直接贴出curl命令加一串base64编码的payload,最后只有一句“可获取系统信息”。我第一次复现它时也这么想——不就是个登录页绕过吗?直到我在客户内网环境里用它顺手拉出了整个Splunk部署的server.conf、web.conf和所有已启用App的源码包,连管理员刚上传的自定义Python脚本(含数据库连接密钥)都完整下载下来。这才意识到:这不是一个“能打”的漏洞,而是一个认证机制彻底崩塌后,整个Splunk管理平面裸奔的信号灯。
这个漏洞的核心关键词非常明确:Splunk、CVE-2018-11409、信息泄露、vulfocus靶场、未授权访问、Web接口绕过。它不属于那种需要堆砌复杂利用链的高危漏洞,而是一种典型的“设计失守型”缺陷——Splunk Enterprise在7.0.0至7.0.8、6.6.0至6.6.8、6.5.0至6.5.10版本中,其Web服务对/en-US/splunkd/__raw/services/这一路径下的REST API端点,完全未校验用户会话状态,且未强制要求任何身份凭证。攻击者无需密码、无需Token、甚至不需要构造Cookie,只要知道目标IP和端口,就能像访问静态资源一样GET任意内部配置接口。更关键的是,Splunk默认监听在8000端口,且Web服务与后台splunkd进程共用同一套认证逻辑——当Web层这道门没锁死,后端所有配置、日志、应用数据就全暴露在HTTP明文之下。
适合谁来深入理解它?不是只盯着“一键getshell”的红队新手,而是真正要落地运维Splunk的企业安全工程师、负责日志平台加固的SRE、以及所有在生产环境部署过Splunk却从未审计过其Web接口权限模型的架构师。因为它的危害不在于“能不能打穿”,而在于“你根本不知道它已经敞开了多久”。我在某金融客户做基线检查时发现,他们三台Splunk Search Head已在线运行两年,从未升级,而/en-US/splunkd/__raw/services/admin/users这个接口返回了全部27个账户的哈希(SHA512-crypt格式),其中3个是admin组成员——这些哈希后来被成功离线破解,直接导致整个日志分析平台沦陷。所以这篇复现,我们不走“复制粘贴PoC”的捷径,而是从vulfocus靶机启动开始,一层层剥开Splunk Web认证的失效逻辑、原始请求的构造原理、真实数据的提取路径,以及最关键的——为什么官方补丁只是加了一行ACL规则,而不是重构整个路由鉴权体系。
2. vulfocus靶机不是玩具,是精准还原生产环境的手术台
很多人把vulfocus当成CTF刷分工具,点几下启动靶机、跑个脚本、截图提交就完事。但如果你真把它当“玩具”,那复现CVE-2018-11409时就会栽跟头——因为vulfocus提供的splunk-cve_2018_11409镜像,是基于Splunk Enterprise 7.0.3官方Docker镜像深度定制的,它不仅复现了漏洞本身,还刻意保留了生产环境中最典型的错误配置:默认启用Web服务、禁用HTTPS重定向、未修改admin初始密码、且所有REST API端点均未配置IP白名单。这意味着你在vulfocus里复现的过程,和你在客户现场抓包分析时看到的流量特征、响应结构、甚至错误码细节,几乎完全一致。
先说环境准备。vulfocus靶机启动后,你会得到一个类似192.168.123.10:8000的访问地址。别急着打开浏览器输admin/changeme,先做三件事:第一,用nmap -sV -p 8000 192.168.123.10确认服务版本,输出会明确显示Splunkd httpd 7.0.3;第二,用curl -I http://192.168.123.10:8000/en-US/检查HTTP头,重点关注X-Splunkd-Session-Id是否为空、Set-Cookie是否缺失;第三,直接访问http://192.168.123.10:8000/en-US/splunkd/__raw/services/,观察返回内容——如果看到XML格式的API服务列表(含admin/users、apps/local、configs/conf-splunk等),恭喜,漏洞已稳定触发。这里有个极易被忽略的细节:vulfocus镜像默认关闭了Splunk的enableSplunkWebSSL选项,所以所有通信都是HTTP明文,这恰恰放大了漏洞危害——你不需要解密TLS流量,所有请求响应都能在Burp Suite中直接查看、修改、重放。
为什么强调vulfocus的“生产级还原”?因为Splunk的REST API路由机制极其特殊。它不像常规Web框架那样按Controller/Action分发请求,而是采用/services/<namespace>/<endpoint>的扁平化路径设计,所有请求最终由splunkd进程统一处理。而CVE-2018-11409的根源,正在于/en-US/splunkd/__raw/这个前缀的路由解析逻辑存在短路:当Web服务器收到以/en-US/splunkd/__raw/开头的请求时,会跳过完整的会话验证流程,直接将请求透传给后台splunkd,并允许其返回原始JSON/XML数据。vulfocus镜像特意保留了这一逻辑,就是为了让你在复现时能清晰看到:不是某个具体API接口有漏洞,而是整个__raw路由前缀的访问控制策略完全缺失。我在某次甲方复测中,客户质疑“我们没开8000端口”,结果我用nmap -p 8000,8089 10.10.10.50扫出8089端口(Splunkd管理端口)开放,再构造http://10.10.10.50:8089/services/admin/users,同样返回了用户列表——这说明漏洞本质是Splunkd服务自身的鉴权缺陷,Web端口只是最便捷的入口。
提示:vulfocus靶机的admin初始密码是
changeme,但复现漏洞时绝对不要登录。一旦你用正确凭据登录,Splunk Web会生成有效Session Cookie,后续所有请求都会携带该Cookie,导致你无法观察到“未授权状态下的原始响应”。真正的复现,必须全程保持无Cookie、无认证头的干净请求状态。
3. 不是“发送请求”,而是“理解Splunk的路由信任链如何断裂”
很多复现文章把步骤简化为“curl -X GET 'http://target:8000/en-US/splunkd/__raw/services/admin/users'”,然后贴出返回的XML。这就像告诉你“按下开关灯就亮”,却不解释电流为何能绕过保险丝。要真正掌握CVE-2018-11409,你必须拆解Splunk Web服务的三层信任链:前端HTTP服务器(nginx/lighttpd)→ Web容器(splunkweb)→ 后台守护进程(splunkd)。漏洞爆发点,就在第二层与第三层之间的协议桥接环节。
先看正常登录流程:当你在浏览器输入admin/changeme,前端HTTP服务器将请求转发给splunkweb进程;splunkweb验证凭据后,生成一个加密的Session ID(存于Cookie),并建立与splunkd的本地Unix Socket连接;此后所有用户操作,splunkweb都以该Session ID为凭证,通过Socket向splunkd代理请求。而/en-US/splunkd/__raw/路径的致命设计在于:它被splunkweb识别为“直连splunkd的原始通道”,跳过了Session ID校验环节,且splunkd自身在处理此类请求时,未强制要求提供有效的认证Token。你可以把这理解为公司大门(HTTP服务器)和核心机房(splunkd)之间修了一条VIP通道,但忘了给VIP通道装门禁卡读卡器。
现在动手验证这个断裂点。打开Burp Suite,拦截一个正常的已登录请求,比如GET /en-US/splunkd/__raw/services/apps/local,观察其请求头:你会发现Cookie字段包含splunkd_session_id=xxx,Authorization头为空。接着,新建一个无Cookie的请求:GET /en-US/splunkd/__raw/services/apps/local HTTP/1.1,Host头设为目标IP,其他头全删。发送后,如果返回200 OK和大量XML数据(含每个App的app.manifest、default/data/ui/nav/等路径),说明信任链已断裂。此时对比两个响应的Content-Length:未授权响应通常比授权响应大15%-20%,因为splunkd返回了更原始、未过滤的元数据。
更关键的是路径构造逻辑。Splunk的REST API遵循严格命名空间规范,/services/admin/users返回用户列表,/services/configs/conf-splunk返回splunk.conf配置,/services/apps/local返回所有本地App。但CVE-2018-11409的威力在于,它允许你绕过命名空间限制,直接访问底层文件系统。尝试请求/en-US/splunkd/__raw/services/properties/,你会看到一个<s:key name="file">标签列表,其中包含server.conf、web.conf、inputs.conf等关键配置文件名。再构造/en-US/splunkd/__raw/services/properties/server%2Fconf%2Fserver.conf(注意URL编码),splunkd会直接返回server.conf的明文内容!这就是为什么漏洞描述为“信息泄露”而非“远程代码执行”——它不给你shell,但它把整个系统的“说明书”和“钥匙串”全摊在你面前。
注意:Splunk 7.0.x版本对
/services/properties/路径的访问有额外限制,需配合output_mode=json参数才能获取完整内容。实测发现,GET /en-US/splunkd/__raw/services/properties/server%2Fconf%2Fserver.conf?output_mode=json返回的JSON中,entry[0].content字段即为base64编码的配置文件明文。这是很多PoC脚本遗漏的关键细节——不加output_mode=json,你可能只拿到空响应或404。
4. 从信息泄露到横向渗透:一条完整的攻击链推演
复现漏洞的终点,从来不是看到一串XML。真正的价值在于,如何把/services/admin/users返回的哈希、/services/properties/web.conf里的root_endpoint配置、/services/apps/local列出的App清单,串联成一条可落地的横向渗透路径。我在某能源集团的红队演练中,正是用这套链路,在37分钟内从一台Splunk Search Head跳转至其对接的Hadoop集群NameNode服务器。
第一步:枚举用户与角色。请求/en-US/splunkd/__raw/services/admin/users?output_mode=json,解析返回JSON中的entry数组。每个entry包含name(用户名)、roles(角色列表)、password_hash(哈希)。重点找role_admin、role_power等高权限角色。Splunk默认使用SHA512-crypt算法(标识符$6$),用hashcat -m 1800可在普通GPU上10分钟内破解弱口令。我曾在一个靶场中,用rockyou.txt字典+规则best64.rule,12秒就破解出admin:Summer2023!。
第二步:定位敏感配置文件。请求/en-US/splunkd/__raw/services/properties/,提取所有file字段值。重点关注web.conf(含root_endpoint、sslCertPath)、server.conf(含pass4SymmKey、sslRootCAPath)、inputs.conf(含monitor://监控路径)。例如,web.conf中[settings]段的root_endpoint = /splunk意味着所有Web资源实际挂载在/splunk/路径下;而server.conf中[general]段的pass4SymmKey = abcd1234efgh5678是Splunk集群间通信的对称密钥——若该集群启用了Search Head Clustering,此密钥可直接用于伪造集群节点身份。
第三步:导出App源码实施供应链攻击。请求/en-US/splunkd/__raw/services/apps/local?output_mode=json,获取所有App的name和label。对每个App,构造/en-US/splunkd/__raw/services/apps/local/{app_name}/export(如/en-US/splunkd/__raw/services/apps/local/SplunkUniversalForwarder/export)。splunkd会返回一个ZIP包,解压后可见default/app.conf、bin/目录下的Python脚本。我在某次复现中,发现一个名为SIEM-Enrichment的App,其bin/enrich_ip.py脚本硬编码了MongoDB连接字符串:mongodb://admin:Passw0rd@10.20.30.40:27017/siem_db。直接连接该MongoDB,即可获取所有告警事件的原始日志。
第四步:反向定位日志源系统。Splunk的inputs.conf常包含[monitor:///var/log/nginx/access.log]这类配置。提取路径后,结合/services/properties/返回的host字段(如host = web-server-01.internal),即可确定日志来源主机。进一步请求/en-US/splunkd/__raw/services/search/jobs/export?search=search%20index%3Dmain%20|%20head%201&output_mode=json,可导出最近一条原始日志,其中host字段即为真实服务器主机名。至此,你已从Splunk管理平面,精准定位到业务系统的物理服务器,完成从信息泄露到横向移动的关键跃迁。
5. 补丁不是魔法,是给断裂的信任链焊上一道物理锁
Splunk官方在7.0.9版本发布的补丁(SPL-142122),其核心改动只有两行代码:在splunkweb的路由配置文件中,为/en-US/splunkd/__raw/路径添加了强制会话验证规则。具体来说,是在$SPLUNK_HOME/etc/system/local/web.conf的[settings]段新增:
[expose] /expose/splunkd/__raw = require_login同时,在$SPLUNK_HOME/etc/system/default/web.conf中,将/en-US/splunkd/__raw/路径的默认ACL从*(所有人可访问)改为admin(仅admin角色)。这看似简单,实则直击要害——它没有重构整个splunkd鉴权模块(成本太高),而是选择在信任链最薄弱的入口处,加装一道“物理锁”。
但补丁的落地效果,高度依赖运维人员的配置习惯。我在审计23家已升级至7.1.0+的客户时发现,仍有17家存在“补丁逃逸”风险:他们手动修改过web.conf,但未同步更新[expose]段配置;或在local/web.conf中覆盖了[expose]设置,导致规则失效。最典型的是某电商客户,其local/web.conf中存在:
[expose] /expose/splunkd/__raw =空值意味着“不强制任何验证”,直接覆盖了默认的require_login。这种配置错误,比未打补丁更危险——因为它让你误以为“已修复”。
因此,真正的加固不能只靠升级。我给客户的四步检查清单如下:
- 确认版本:
$SPLUNK_HOME/bin/splunk version,确保≥7.0.9或≥6.6.9; - 检查web.conf:
grep -A 5 "\[expose\]" $SPLUNK_HOME/etc/system/{local,default}/web.conf,确认/expose/splunkd/__raw值为require_login; - 验证ACL:
curl -I http://localhost:8000/en-US/splunkd/__raw/services/admin/users,响应头中应包含X-Content-Type-Options: nosniff且返回401而非200; - 审计自定义App:检查所有第三方App的
default/app.conf,确认未在[expose]段添加新的__raw路径映射。
最后分享一个实战技巧:很多客户因兼容性问题无法立即升级,我推荐用Nginx做前置代理,强制拦截/en-US/splunkd/__raw/路径。配置片段如下:
location ~ ^/en-US/splunkd/__raw/ { deny all; return 403 "Access to __raw API is disabled for security"; }此方案零侵入、零重启,上线后立即生效。我在某银行核心日志平台实施该方案,3分钟内阻断了所有针对__raw路径的扫描行为,且未影响任何正常Web功能。这印证了一个朴素道理:最高明的安全加固,往往不是最复杂的代码,而是最坚决的访问控制。
我在实际运维中发现,Splunk管理员最常犯的错误,是认为“关掉Web服务就能规避风险”。但事实是,Splunk的Web服务与splunkd进程深度耦合,禁用Web会导致Search Head无法工作。真正的解法,永远是理解其设计逻辑,在信任链的断裂点精准施加控制。CVE-2018-11409的价值,不在于它多难利用,而在于它像一面镜子,照出我们在设计任何Web管理界面时,是否真正思考过“谁有权访问这个路径”——而不是默认所有人都该有权限。
