CVE-2026-21589 Atlassian Jira 未认证文件读取:双冒号如何越过插件资源边界
原创
messfree
messfree
MessFreeSecurity
2026年10月8日 12:12
北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
![]()
..::..::WEB-INF::web.xml
↓ Atlassian 路由把 :: 还原为 /
../../WEB-INF/web.xml
Jira 自带的资源 jira.webresources:color-picker-popup/images/ 是个现成的合法起点。请求进了 Web Resource 下载路由之后,用户控制的资源名依次经过 Router.unescapeSlashes()、ResourceServingHelpers.getResourceRelativeToWebResource(),最后落到 ResourceFactory.createResourceWithRelativePath()。
漏洞版本会照着这个相对路径创建并读取资源,但从头到尾没确认一件事:规范化之后的最终路径,还在不在原来的插件资源目录里。Tomcat 和前置代理先看到的是 ..::,Atlassian 应用稍后才把双冒号还原成斜杠。最终目录边界检查缺失,父目录跳转就在应用内部又活了过来。
把 atlassian-plugins-webresource 的 6.0.7 和 6.0.8 从 Atlassian Maven 仓库拉下来,用 javap 离线对比字节码:Router 里的双冒号转换原封不动,真正的修复在 ResourceFactory,6.0.8 先统一路径分隔符、执行 normalize(),再检查候选路径是不是仍以原资源目录开头,过不去就直接返回空。
修复思路简化一下:
Path base =normalize(resourceDirectory);
Path candidate =normalize(resolvedResourcePath);
if(!candidate.startsWith(base)){
returnnull;
}
这套离线分析确认了补丁的目录包含逻辑,但替代不了完整 Jira 环境的复现。本文没有向任何 Jira 目标发送过测试请求。
PoC 分析:固定文件探针,不是完整利用框架
watchTowr 公布的检测脚本不大,八十来行,本地下载的文件 81 行、57 行有效代码。脚本依次试 Jira、Confluence 和 Bitbucket,每种产品只发一个未认证 GET,只读一个固定文件。
Jira 探针的请求路径:
GET /download/resources/jira.webresources:color-picker-popup/images/..::..::..::..::..::WEB-INF::web.xml HTTP/1.1
Host: jira.example
脚本没把 HTTP 200 直接当成功。Jira 的响应正文里必须出现:
com.atlassian.jira.web.ServletContextProviderListener
这个类名是 Jira web.xml 里的内容。受保护路径能返回它,才算比较硬的未认证文件读取证据。Confluence 和 Bitbucket 的探针是同样的思路,各用各配置文件里的内部类名当标志。
短板也明显:没有请求超时,关了 TLS 证书校验,默认跟随重定向,也不区分 403、404、429 和 500。三个探针全部落空时,脚本只会告诉你“可能不存在漏洞”。WAF、反向代理、Context Path、定制插件资源、响应重写,都能造成假阴性。
还有些第三方 PoC 更糙,HTTP 200 加正文非空就算读取成功,登录页、WAF 拦截页、代理错误页全都能满足这个条件,信不得。另外,watchTowr 的公开仓库里并没有后续的 Crowd 接管脚本。所以验收以安装版本和集群节点状态为准,PoC 只算辅助证据。
攻击链:文件读取怎样走到身份系统
CVE-2026-21589 本身到文件读取为止。公开研究里那条高危链路,靠的是 Jira 与 Crowd 的集成配置。
发现公网 Jira
↓
通过 Web Resource 路由读取 WEB-INF/web.xml
↓
根据标准部署结构尝试已知配置路径
↓
读取 WEB-INF/classes/crowd.properties
↓
取得 Crowd 地址、应用名称和应用密码
↓
访问 Crowd 服务并使用应用身份认证
↓
按应用权限查询或修改用户、组关系
↓
条件满足时获得 Jira 或 Confluence 管理权限
Atlassian 的 Crowd 集成文档把 crowd.properties 放在 WEB-INF/classes/ 下。watchTowr 在自建实验环境里读到了这个文件,application.name、application.password、Crowd 服务地址,都在里面。
拿到 Crowd 应用凭据之后能做什么,取决于应用权限、目录配置和网络限制,公开研究在实验室里演示了用户相关操作。落到企业环境,还得查三样:Crowd 有没有限制来源 IP,应用身份能访问哪些目录,Jira 的管理员组是怎么映射的。
拿到 Jira 管理权限之后,读项目数据、改权限、建持久化账号、动安全配置,都可能发生。插件安装这类能力能不能进一步变成代码执行,要看管理权限划分、产品配置和额外的安全控制,从文件读取这个结果本身推不出来。
依赖条件:先判断链路能走到哪一段
基础文件读取,四个条件:
- 目标运行受影响的 Data Center 版本。
- Web Resource 路由可以从攻击者所在网络访问。
- 攻击者知道目标文件的准确路径和名称。
- 目标文件位于 Web 应用根目录内。
从文件读取走到 Crowd 身份控制,条件多得多:
- Jira 使用对应方式集成 Crowd。
crowd.properties
存在于公开研究覆盖的路径中。
3. 文件里保存的应用密码仍然有效。
4. 攻击者能够连接 Crowd 服务。
5. Crowd 的 IP 白名单允许攻击来源,或者没有配置来源限制。
6. 被盗应用身份拥有 Add User、Modify Group 等足够的目录操作权限。
7. Crowd 中的组关系能够映射到 Jira 或其他 Atlassian 产品的高权限角色。
没有 Crowd 集成,文件读取的风险也不会消失。企业自己往 WEB-INF 或 WEB-INF/classes 里放的属性文件、证书、密钥和备份,都可能把影响抬高。风险评估要回到你自己的部署目录,别只套公开实验环境。
排查:日志、版本和身份变更要放在同一条时间线上
第一步是建资产清单:产品、版本、节点、访问入口、反向代理、WAF、Context Path 和 Crowd 集成状态,一项一项记。Data Center 集群要逐节点核对,负载均衡后面藏一个旧节点,暴露面就还在。
排查窗口不能从公告日期起算。漏洞在公开披露之前就存在,日志保存期允许的话,把能拿的历史数据全部回溯。负载均衡、CDN、WAF、反向代理、Tomcat 和 Crowd 的日志都要保全,边缘入口和源站节点同时查。X-Forwarded-For 只有在请求确实经过受信任代理时,才能当来源地址用。
Atlassian 建议对访问日志中的请求路径最多做两次 URL 解码,然后找紧邻 /、\\\\ 或 :: 的 ..。没法统一解码的,直接对原始日志上官方正则:
(?is).*(?:/|\\\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\\.|%(?:25)*2e){2}(?:/|\\\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).*
日志检索优先看这些组合:
- URL 中同时出现
/download/resources/、..::和WEB-INF。 - 目标文件包含
web.xml、urlrewrite.xml或crowd.properties。 - 同一来源短时间尝试多种编码、不同穿越深度或多个 Atlassian 产品路径。
- 返回状态为 200,响应体量明显大于普通 404 页面。
- 探测后紧接着出现 Crowd REST 请求、异常用户创建、组成员变化或新管理员登录。
告警别只匹一条固定 PoC 字符串。攻击者可以换 URL 编码、双重编码、反斜杠,或者换其他产品的资源入口。检测逻辑要留住原始 URI,同时存一次解码和两次解码的结果,再关联来源 IP、User-Agent、状态码、响应字节数和后续的身份行为。
还有一类干扰来自内部:漏洞扫描器也会发类似请求。排除误报要核对扫描源地址、变更窗口和授权任务记录,不能一看到安全设备的 IP 就把事件关掉。反过来,日志没命中也不能直接排除风险,日志轮转、代理提前规范化路径、备用入口绕过、部分节点没接入采集,都是盲区。
一旦日志显示 crowd.properties 可能返回成功,按凭据泄露事件处理:查 Crowd 应用登录、USER_CREATED、CONFIGURATION_MODIFIED、用户属性修改、组成员调整、目录同步异常,以及同期 Jira、Confluence 里出现的新账号和高权限登录。
止血措施:先截断公网入口,再处理补丁和凭据
升级是根治。 Jira Software Data Center 升到 9.12.40、10.3.26、11.3.12 或后续安全版本;Jira Service Management Data Center 升到 5.12.40、10.3.26、11.3.12 或后续。集群里每个节点都要升完、核验版本之后再重新加入。
一时升不了的,先按 Atlassian 的建议限制实例的互联网访问:反向代理、VPN、零信任入口、来源允许列表,先把可达范围缩下来。别以为有登录页就安全,利用发生在未认证的资源路由,登录页拦不住。
Atlassian 还给了两类临时缓解:
- 在 WAF 或反向代理部署官方正则,阻断
/、\\\\、::与..相邻及其多次 URL 编码变体。 - 对 Jira、JSM、Confluence、Bamboo 和 Crowd 启用 Tomcat
RewriteValve,在应用上下文中加载官方rewrite.config。
这些规则要覆盖所有入口和所有集群节点,还要验证代理、容器和应用看到的 URI 是否一致。上线后用原始、一次编码、双重编码三种形式各测一遍,同时确认正常的插件资源还能加载。
出现疑似成功读取,或者历史日志不足以排除敏感配置泄露,补丁之外还有一轮凭据和身份止血:
- 轮换 Crowd 应用密码及同目录中可能暴露的其他密钥。
- 收紧 Crowd 网络访问和 IP 白名单,阻断互联网直达。
- 暂停或禁用异常账号,撤销可疑会话和高权限组成员关系。
- 对照变更记录检查用户、组、目录和应用配置。
- 保全反向代理、WAF、Tomcat、Jira 和 Crowd 日志,统一时间基准后重建事件链。
PoC 没命中不能替代版本核验。补丁版本、节点一致性、日志回溯、凭据轮换,一样都不能少。
结语
双冒号只是这条链路的外观。核心缺陷是插件资源框架接受了相对路径之后,没有确认最终文件还在不在原资源目录里。修复版把边界检查放在真正打开文件之前,前置代理、编码方式和路由转换之间的缝隙就堵上了。
企业排查照这个思路走:先定位信任边界,再看路径经过了哪些转换,最后确认文件读取之后还连着哪些身份和管理系统。一条文件读取告警,要这样一路落到补丁、凭据轮换和账号审计上,而不是停在“发现过一次访问”。
参考资料
- Atlassian:CVE-2026-21589 官方安全公告
https://confluence.atlassian.com/security/cve-2026-21589-arbitrary-file-access-vulnerability-impacts-multiple-products-1870495748.html - watchTowr Labs:CVE-2026-21589 技术分析
https://labs.watchtowr.com/you-wont-hear-about-these-even-in-myths-atlassian-jira-confluence-and-more-pre-auth-arbitrary-file-read-cve-2026-21589/ - watchTowr Labs:公开检测脚本
https://github.com/watchtowrlabs/watchTowr-vs-Atlassian-CVE-2026-21589 - Atlassian:Integrating Crowd with Jira
https://confluence.atlassian.com/crowd/integrating-crowd-with-atlassian-jira-192625.html








评论