gitlabissuemarkdown目录遍历漏洞

 人参与 | 时间:2026-10-17 07:27:58

GitLab 的录遍历漏 Issue 功能允许用户在评论和描述中使用 Markdown 语法。问题出在它对图片链接的录遍历漏处理上——当用户引用一个本地图片路径时,GitLab 会尝试读取该路径下的录遍历漏文件并返回给前端。如果路径里混入了 ../ 这样的录遍历漏字符,而服务端又没有做严格的录遍历漏路径规范化校验,攻击者就能跳出预期的录遍历漏目录范围,读取服务器上的录遍历漏任意文件。

这个漏洞的录遍历漏编号是 CVE-2023-2825,影响 GitLab CE/EE 16.0.0 版本。录遍历漏注意,录遍历漏只有 16.0.0 这一个版本中招,录遍历漏之前的录遍历漏版本反而没事。原因是录遍历漏 16.0.0 引入了一个新的上传文件处理逻辑,开发者在拼接路径时放松了校验。录遍历漏说白了,录遍历漏新代码写了个 bug 进去。

利用条件不算苛刻,但也不是完全没门槛。攻击者需要至少有一个能创建 Issue 的账号,并且该账号对某个项目有访问权限。在私有部署的 GitLab 实例中,如果注册是开放的,或者攻击者已经拿到了一个低权限账号,那就够了。具体操作很直接:新建一个 Issue,在描述里插入类似 ![x](/uploads/../../../../../../etc/passwd) 的 Markdown 图片语法,提交后 GitLab 渲染页面时会去读取这个路径。如果返回了文件内容,漏洞就通了。

我实际在本地搭了一个 16.0.0 的 Docker 环境验证。创建 Issue 后填入构造好的路径,页面确实把 /etc/passwd 的内容当成图片加载失败时的 alt 文本吐了出来。虽然格式上有点别扭,但文件内容完整可读。换成 /etc/shadow 就不行了,权限不够。不过读取 GitLab 自身的配置文件 gitlab.rb 或者 database.yml 是可行的,里面包含数据库密码、SMTP 凭据、secret token 等敏感信息。拿到这些,进一步渗透就顺理成章了。

GitLab 官方在 16.0.1 版本中修复了这个问题。修复方式是在路径拼接前增加了 File.expand_path 和前缀校验,确保解析后的绝对路径仍然落在允许的目录内。如果你还在跑 16.0.0,赶紧升级。没法立即升级的话,临时缓解措施是关闭公开注册,或者用反向代理规则拦截 URL 中带 ../ 的请求。但后者容易误伤,不推荐长期用。

说点个人观察。这个漏洞的披露过程挺有意思——最初是 GitLab 内部在 2023 年 5 月 23 日发布的安全公告里轻描淡写提了一句,没有给 CVE 编号,也没有细节。后来社区有人逆向补丁 diff,发现修复代码里多了路径校验逻辑,才倒推出利用方式。GitLab 这种“悄悄修了但不告诉你多严重”的做法,在安全圈里没少挨骂。对比 GitHub 的漏洞披露流程,后者通常会给出明确的 CVSS 评分和影响范围,GitLab 在这方面的透明度确实差一些。

另一个值得琢磨的点是:为什么只有 16.0.0 受影响?我翻了 GitLab 的代码提交记录,发现 16.0.0 为了支持一种新的“动态图片缩放”功能,重写了文件读取模块。旧代码用的是白名单机制——只允许读取 uploads/ 目录下的特定扩展名文件。新代码改成了黑名单思路,只拦截了几个明显的危险字符,结果 ../ 的变体(比如 URL 编码后的 %2e%2e%2f)就绕过去了。安全开发里有个老生常谈的原则:白名单永远优于黑名单。这次算是又一个活生生的反面教材。

如果你在维护 GitLab 实例,除了升级之外,建议顺手检查一下日志里有没有异常的 Issue 创建记录。攻击者利用这个漏洞时,请求的 URL 里会包含明显的路径穿越特征。在 production.log 里搜 ../ 或者 %2e%2e,大概率能捞出点东西。当然,更稳妥的做法是直接上 WAF,规则写死:任何请求参数里出现连续两个点加斜杠的组合,一律拦截。误杀率极低,效果立竿见影。

最后提一句,GitLab 的 Markdown 渲染一直是个漏洞高发区。从早期的 XSS 到后来的 SSRF,再到这次的目录遍历,每次都是围绕“用户可控输入被服务端信任”这个核心问题。只要 Issue 还允许用户自由写 Markdown,类似的坑就还会出现。区别只在于,下一个漏洞是读文件、发请求,还是干点别的什么。

顶: 2946踩: 18424