CVE-2026-85706 已遭利用:自托管 GitLab 的排查与应急处置指南

2026-10-04 38 预计阅读时间: 1 分钟
来源: infoq.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

CVE-2026-85706 是一个影响自托管 GitLab CE/EE 的严重路径遍历漏洞。风险不再停留在理论层面:已有攻击者主动利用该漏洞,未经身份验证即可尝试读取 GitLab 主机上的任意文件。对运维团队而言,这意味着不能只等待常规维护窗口,而应同时推进版本确认、暴露面收缩、日志排查和凭据轮换。

为什么任意文件读取尤其危险

路径遍历漏洞通常通过构造异常路径,让应用访问原本不应暴露的服务器文件。即使攻击者不能直接执行命令,任意文件读取也可能泄露:

  • GitLab 配置与密钥文件;
  • 数据库、对象存储或 SMTP 凭据;
  • OAuth、Webhook、Runner 及第三方集成令牌;
  • 私有仓库相关数据或备份文件;
  • SSH 私钥、服务账户配置和内部网络信息。

一旦读取到可复用的凭据,攻击者就可能绕过原漏洞入口,转而访问数据库、云存储、CI/CD Runner 或其他内部系统。因此,完成升级并不等于事件已经结束;如果实例曾暴露在互联网,应把后续工作当作一次潜在的凭据泄露事件处理。

来源摘要没有给出精确的受影响版本边界和修复版本号,因此不要凭经验猜测。应根据 GitLab 官方安全公告确认当前 CE/EE 版本是否受影响,并升级到公告明确列出的安全版本。

先确认资产,再缩小攻击面

在修改系统前,先记录版本、运行状态和部署方式。Omnibus 安装可以直接运行下面的脚本;它只采集基本信息,不会修改 GitLab:

#!/usr/bin/env bash
set -euo pipefail

OUT="gitlab-cve-2026-85706-inventory-$(date -u +%Y%m%dT%H%M%SZ).txt"

{
  echo "=== UTC time ==="
  date -u
  echo

  echo "=== Host ==="
  hostnamectl 2>/dev/null || hostname
  echo

  echo "=== GitLab environment ==="
  sudo gitlab-rake gitlab:env:info 2>&1
  echo

  echo "=== GitLab services ==="
  sudo gitlab-ctl status 2>&1
  echo

  echo "=== Listening sockets ==="
  sudo ss -lntp 2>&1
} | tee "$OUT"

sha256sum "$OUT" | tee "$OUT.sha256"
echo "Inventory written to $OUT"

如果使用容器部署,可以补充记录实际镜像,而不要只查看 Compose 文件中的预期标签:

docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
docker inspect --format '{{.Name}} -> {{.Config.Image}}' gitlab 2>/dev/null || true

确认受影响后,应优先升级。若暂时无法升级,可以在负载均衡器、防火墙或 VPN 层临时限制管理实例的访问来源。下面是一段可改造的 Nginx 访问控制示例;部署前必须把示例网段替换为组织真实的出口地址,并确认不会阻断 Runner、Webhook 和 SSO 回调:

# 放在 http 上下文中
geo $gitlab_source_allowed {
    default         0;
    203.0.113.0/24  1;  # 替换为公司 VPN 或办公出口 CIDR
    198.51.100.10/32 1; # 替换为必要的集成系统地址
}

server {
    listen 443 ssl;
    server_name gitlab.example.com;

    if ($gitlab_source_allowed = 0) {
        return 403;
    }

    location / {
        proxy_pass http://gitlab_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

这种限制只是临时缓解措施,不能替代安全升级。路径编码方式很多,单靠 WAF 规则也很难完整拦截所有变体。

从访问日志中寻找路径遍历迹象

Omnibus GitLab 通常把 Nginx 访问日志放在 /var/log/gitlab/nginx/。下面的命令搜索常见的明文、单层编码和双层编码遍历特征:

sudo zgrep -ahiE '(\.\./|%2e%2e|%252e%252e|%2e%2e%2f|%2e%2e/)' \
  /var/log/gitlab/nginx/gitlab_access.log* \
  | tee gitlab-path-traversal-candidates.log

wc -l gitlab-path-traversal-candidates.log

还可以汇总候选请求的来源地址:

awk '{print $1}' gitlab-path-traversal-candidates.log \
  | sort \
  | uniq -c \
  | sort -nr \
  | head -50

这些匹配只能作为线索:URL 可能经过代理重写,攻击者也可能使用其他编码方式;反过来,开发者提交的合法请求也可能触发正则表达式。没有匹配结果不能证明系统未被攻击,有匹配结果也需要结合响应状态、响应大小、时间线、代理日志和网络流量进一步确认。

如果日志显示可疑请求获得成功响应,应立即保存相关证据。不要先清理日志或重建主机。可以先复制日志并生成哈希:

IR_DIR="/root/gitlab-ir-$(date -u +%Y%m%dT%H%M%SZ)"
sudo install -d -m 700 "$IR_DIR"
sudo cp -a /var/log/gitlab/nginx "$IR_DIR/"
sudo cp -a /var/log/gitlab/gitlab-rails "$IR_DIR/" 2>/dev/null || true
sudo find "$IR_DIR" -type f -exec sha256sum {} \; \
  | sudo tee "$IR_DIR/SHA256SUMS" >/dev/null

echo "Evidence copied to $IR_DIR"

证据目录本身可能包含访问令牌、用户名和内部地址,应加密保存并限制访问。

升级之外,还要处理泄露后的影响

对于曾经公网可达且无法排除利用的实例,可以按下面的顺序处置:

  1. 隔离或限制入口:保留取证所需的日志和磁盘快照,同时减少新的攻击请求。
  2. 安装官方安全版本:遵循当前部署方式的升级路径,完成数据库迁移和服务重启,并重新确认实际运行版本。
  3. 轮换高价值凭据:包括管理员令牌、项目和群组访问令牌、Runner 令牌、Webhook 密钥、OAuth 密钥、数据库密码以及云服务凭据。
  4. 谨慎处理 GitLab 内部密钥:某些内部密钥的轮换会使现有加密数据、会话或集成失效,应严格遵循官方恢复和轮换流程,而不是直接删除密钥文件。
  5. 检查横向移动:审计 Git 操作、管理员登录、令牌创建、CI/CD 作业、Runner 注册、对象存储访问和数据库连接。
  6. 验证恢复状态:确认项目访问、流水线、Webhook、SSO、备份和恢复流程正常,并持续监控异常请求。

面向生产环境的检查清单

  • [ ] 已识别所有自托管 GitLab CE/EE 实例,包括测试、灾备和长期停机节点;
  • [ ] 已根据官方公告核对版本,而不是只依赖资产平台中的历史记录;
  • [ ] 已升级到明确修复 CVE-2026-85706 的安全版本;
  • [ ] 无法立即升级的实例已通过 VPN、代理或防火墙限制访问;
  • [ ] 已保存访问日志、应用日志、代理日志和必要的磁盘快照;
  • [ ] 已排查路径遍历特征,并关联响应状态、流量和身份审计记录;
  • [ ] 无法排除泄露时,已轮换 GitLab 及外部系统凭据;
  • [ ] 已检查 Runner、CI/CD、对象存储和数据库是否出现异常活动。

面对已经进入主动利用阶段的任意文件读取漏洞,最危险的做法是把“服务仍然正常”当作“系统没有失陷”。升级负责关闭入口,日志分析和凭据轮换则负责处理攻击者可能已经带走的东西;两部分都完成,才算真正结束应急处置。


相关推荐