导语:2026年7月24日,安全公司depthfirst正式公开了GitLab一个高危认证用户远程代码执行漏洞的完整攻击链。任何对项目有提交权限的认证用户,只需推送精心构造的Jupyter笔记本(.ipynb)并查看commit diff,即可在未修补的GitLab服务器上以git用户身份执行任意命令。无需管理员权限、无需CI runner、无需受害者交互——这是真正意义上的”一键RCE”。
一、漏洞概述
1.1 背景
这次漏洞的特殊之处在于它根本没有CVE编号。
depthfirst安全研究人员Yuhang Wu(吴宇航)向The Hacker News透露:GitLab官方在2026年6月10日发布的安全更新中,将Oj gem升级到3.17.3版本,但这一修复被列在”bug修复”列表中,而非”安全修复”表里。这意味着大量依赖GitLab安全更新公告来评估漏洞优先级的人员,很可能错过了这个严重程度被严重低估的缺陷。
受影响范围之广令人警醒:GitLab CE/EE从15.2.0到18.10.7,从18.11.0到18.11.4,从19.0.0到19.0.1,全部中招。所有版本层级——从Free到Ultimate——无一幸免。
1.2 影响评估
攻击者获得的代码执行权限以git系统用户身份运行,这意味着:
- 源代码仓库全部可读可窃取
- Rails secrets(数据库密码、session密钥、加密盐)暴露
- CI/CD凭据和管道配置被攻击者掌控
- GitLab能访问的内部服务均可被横向利用
- 攻击者可向代码仓库中植入后门,影响所有后续拉取者
二、技术分析:Oj gem的双重内存损坏
2.1 攻击入口:ipynbdiff
GitLab内置了一个名为ipynbdiff的组件,专门负责将仓库中的Jupyter笔记本(.ipynb文件,本质上是JSON)渲染为可视化的diff视图。当用户在GitLab Web界面中查看一个包含.ipynb文件的commit变更时,这个组件会被调用。
问题的根源在于:ipynbdiff将仓库中攻击者可控的.ipynb JSON内容直接传递给Oj gem进行解析——而Oj是一个以C语言实现的Ruby JSON解析器,内部使用手动管理的C内存。
这意味着:攻击者提交的JSON数据,会直接触及Oj的原生C内存层。
2.2 两个内存损坏漏洞串联
depthfirst的研究人员通过其AI安全研究系统自主发现了Oj gem中的两个内存损坏漏洞:
漏洞一:嵌套栈溢出控制回调
Oj解析器内部维护了一个固定1,024字节的嵌套栈。当JSON对象嵌套层数超过这个限制时,解析器会写穿这个栈缓冲区。更关键的是,通过精心构造输入,攻击者可以控制解析器的start callback(起始回调函数指针)。这为后续的代码执行流劫持埋下伏笔。
漏洞二:对象键长度截断泄漏堆指针
当Oj解析一个超长(65,565字节)的对象键时,在有符号16位字段中会被截断为29。这个截断操作不会报错,而是返回一个活跃的堆内存指针。更妙的是,这个指针会直接被渲染到GitLab的diff页面中——攻击者只需查看diff,就能读取到这个指针值。
2.3 完整攻击链
第一步:推送恶意notebook → 触发堆指针泄漏 → 从diff页面读取libc基地址
↓
第二步:推送更多notebook → 自动化探测并定位内存中的gadget
↓
第三步:推送最终载荷notebook → 触发嵌套栈溢出 → 劫持callback指向system()
↓
结果:以git用户身份执行任意命令
整个攻击链的精妙之处在于信息泄漏与写入控制的配合:
- 泄漏阶段:攻击者反复推送精心构造的.ipynb文件,利用截断漏洞从diff页面获取堆指针,逐渐定位到进程中的库函数地址
- 控制阶段:利用嵌套栈溢出,将Oj解析器的回调函数指针覆写为
system() - 执行阶段:当Oj解析攻击者推送的最后一个notebook时,调用
system("恶意命令"),完成命令执行
depthfirst在测试中测量,新部署的双worker GitLab实例,内存搜索阶段耗时5到10分钟;运行时间较长的实例则需要1到2小时。这是一次有准备的、确定性的攻击——不是撞大运,而是步步为营。
三、为什么这个漏洞被严重低估
3.1 修复被误归类
2026年6月10日,GitLab发布19.0.2、18.11.5和18.10.8三个版本,其中包含了Oj gem从3.17.x升级到3.17.3的变更。然而,这个修复被列在普通bug修复列表中,GitLab的安全修复表格中完全找不到相关条目。
没有CVE编号,没有CVSS评分,没有安全公告——这直接导致:
- 依赖NVD/CVE数据库进行漏洞管理的企业无法识别该漏洞
- 仅跟踪安全修复表格的安全团队可能认为无需紧急处理
- 很多企业可能至今仍在运行受影响的GitLab版本
3.2 受影响版本已超出维护期
对于GitLab 15.2到18.9版本,官方明确表示不会提供专门的修复补丁。这些版本已经超出了GitLab的安全维护时间线,运行这些版本的用户唯一的出路是:升级到官方维护的支持版本。
四、PoC下载
安全研究团队depthfirst已公开针对GitLab 18.11.3 x86-64架构的完整利用代码。该工具针对特定版本和CPU架构做了优化,包含gadget偏移量、寄存器状态和jemalloc内存分配器行为等参数。
PoC下载地址:
https://github.com/wupco/gitlab-rce-demo
工具特性:
- 针对GitLab 18.11.3 x86-64优化
- 自动化内存搜索定位libc基址
- 通过恶意.ipynb文件触发Oj gem漏洞
- 攻击耗时:5-10分钟(新部署实例)~1-2小时(长期运行实例)
注意: 该PoC针对特定版本和架构进行了调试,libc基址恢复依赖Puma master重启前的窗口期。移植到同架构其他GitLab版本通常只需更新gadget偏移量。
需要说明的是,当前公开的PoC针对特定的GitLab版本和CPU架构做了优化调整,包括gadget偏移量、寄存器状态和jemalloc内存分配器行为等均来自18.11.3测试环境。libc基地址的恢复依赖于Puma master重启前的窗口期,因此并非”开箱即用”的通用脚本。
然而,depthfirst的研究人员强调:移植到同一架构的其他GitLab构建版本,通常只需要更新gadget和符号偏移量——这并非高不可攀的门槛。真正的障碍在于切换CPU架构:x86-64的calling convention、gadget、寄存器用法和堆行为与ARM64完全不同,迁移工作量会显著增加。
五、影响版本与修复方案
| 组件 | 受影响版本 | 首个修复版本 |
|---|---|---|
| GitLab CE/EE | 15.2.0 ~ 18.10.7 | 18.10.8 |
| GitLab CE/EE | 18.11.0 ~ 18.11.4 | 18.11.5 |
| GitLab CE/EE | 19.0.0 ~ 19.0.1 | 19.0.2 |
| Oj gem | 3.13.0 ~ 3.17.1 | 3.17.3 |
立即升级到以下版本之一:
- GitLab 18.10.8 或更高18.10版本
- GitLab 18.11.5 或更高18.11版本
- GitLab 19.0.2 或更高19.x版本
没有配置层面的缓解措施。 depthfirst研究人员明确表示,目前没有经过验证的GitLab配置选项可以完全禁用ipynbdiff的notebook-diff渲染路径。从理论上说,阻止不受信任的用户访问notebook-diff渲染可以消除这个攻击入口,但操作难度极高。建议无法立即升级的用户联系GitLab获取针对性指导。
六、排查与检测
6.1 版本核查
对于使用Helm或Operator部署的GitLab,必须检查Puma Webservice容器内运行的GitLab版本,而不是Kubernetes Operator或Helm Chart的版本号——这两者可能与实际运行的GitLab应用版本不一致。
6.2 入侵指标
在GitLab Rails日志、Workhorse日志、反向代理日志中,重点关注以下异常:
- 短时间内大量.ipynb文件commit操作
- 同一项目多次请求commit-diff流式渲染接口
- 伴随Puma worker崩溃或重启的异常请求序列
- git账户产生的异常子进程、网络连接或对内部服务的访问
七、写在最后
这个漏洞给我们的教训是深刻的。
一个可以被普通认证用户利用、无需任何特殊权限、攻击代码已公开的RCE漏洞,居然在GitLab的安全更新中被低调处理,没有CVE,没有CVSS,没有安全修复标记。这不是技术问题,这是风险管理流程的问题。
漏洞是2026年5月21日报告的,Oj maintainer在5月27日合并了修复,6月4日Oj 3.17.3发布,6月10日GitLab悄悄修了这个漏洞。然后,直到7月24日depthfirst公开技术细节和PoC,整个业界才意识到这个漏洞的严重性。
整整六周,被严重低估的RCE漏洞静静地躺在bug修复列表里。
对于防御者而言,这意味着:不要把鸡蛋放在CVE这一个篮子里。CVE分配不及时、CVSS评分不准确、安全公告分类错误——这些都可能发生。真正的防御,需要更深层次的漏洞研究能力和积极主动的修补策略。
版权声明:本文由华盟网原创发布,保留所有权利。配图由华盟网授权使用。














暂无评论内容