潜伏5年!GitLab高危RCE漏洞爆发,低权限即可控服

漏洞概要

2026年7月24日,Depthfirst研究团队发布了一个针对GitLab的远程代码执行(RCE)漏洞利用工具。该漏洞链是将Ruby JSON解析器Oj(Oj使用原生C实现)中的两个内存损坏漏洞组合起来,最终在GitLab Puma worker进程中实现完整命令执行。

任何能够向项目推送代码并查看提交diff的已认证用户均可触发该漏洞。研究人员指出,无需管理员权限、无需CI访问权限,也无需受害者交互。GitLab已于2026年6月10日修补了这两个漏洞,但将其归类为“Bug修复”而非安全补丁,因此在评估该版本时,运维人员没有理由将其视为紧急事件。

Depthfirst发布的报告指出:“系统列出的18个优先处理漏洞中,包含7个内存安全漏洞。其中两个——越界写入和堆指针泄露——在Oj中已存在近五年。Oj是GitLab使用的底层依赖,我们将两个漏洞组合后,在默认GitLab安装上实现了远程代码执行。”

技术分析

这两个漏洞于2021年8月8日被引入Oj解析器,潜伏了1753天。易受攻击的notebook路径随GitLab 15.2.0版本(2022年7月发布)引入,直到2026年6月10日才被修复。

攻击路径始于GitLab的notebook diff渲染器——一个名为ipynbdiff的内嵌gem,它负责将Jupyter的.ipynb文件转换为人类可读的diff。当用户打开notebook文件的commit diff时,GitLab会将原始仓库字节传递给Oj::Parser.usual.parse,该调用发生在Puma worker进程中。这个parse调用就是攻击入口。

报告继续写道:“调查是反向进行的:Depthfirst首先发现了应用底层的脆弱解析器,然后通过调用链回溯到用户可操控的产品边界。真正的请求则沿着相反方向,从GitLab commit diff进入原生C代码。”

由于Oj::Parser.usual返回的是进程级解析器单例,该单例在同一Puma worker中的所有线程间共享,因此一次损坏会影响该进程中后续的所有解析操作。

第一个漏洞是未校验的嵌套栈溢出。Oj在解析器对象内部使用一个固定大小的1024字节数组来跟踪JSON嵌套深度。当攻击者打开超过1024层嵌套数组时,Oj会持续向该缓冲区之后的一个字节集合选择器写入数据,覆盖相邻的解析器字段。攻击者无法精确控制每个字节(数组始终写入0x01),但可以控制写入的深度。当嵌套层数足够多时,这个单字节修改会改变buf.head(解析器内部缓冲区起始指针),将其向后移动127字节,落入解析器未拥有的内存区域。随后,强制调用realloc会缓存这个伪造的内部指针,而Ruby的Array分配会回收该区域,并且Array的元素内容(虽然被限制为有效的Ruby值,但仍受攻击者影响)会用一个选择的地址覆盖解析器的p->start回调指针。

第二个漏洞提供了所需的地址。一个超长的对象键(65565字节)的长度被从size_t截断为有符号16位整数,从而回绕为29。Oj为完整键分配堆内存并存储指向它的指针,但截断后的长度告诉返回路径从内联缓冲区读取29字节。巧合的是,这29字节的第6到第13字节恰好包含堆指针。GitLab在渲染diff时将其作为单元ID的一部分输出。

报告指出:“返回的字节0到5来自外部视图的对齐填充。字节6到13是活跃的key指针。最后15个返回字节来自联合存储区,该区域未被外部视图写入,可能包含陈旧的键条目内容。这是一种固定的29字节泄露,而非任意地址读取:它只暴露了该Key条目中已存在的字节,且从未解引用攻击者选择的指针。这些偏移量来自测试所用的x86_64 ABI,因此编译器布局是这一原语边界的一部分。”

获得堆指针后,攻击者通过将自循环指令地址写入p->start,并观察哪个解析操作会挂起,来探测候选的libc基址。在一个全新的双worker GitLab实例上,ASLR搜索耗时5到10分钟;在成熟的长运行实例上,预计时间为1到2小时。

一旦恢复库基址,利用程序会在单个diffs_stream请求中链式使用两个原语。同一个commit中的两个按字典序排列的notebook文件各自承载一个阶段:第一个notebook设置回调指针,抛出异常以避免立即执行,并让GitLab继续流式传输diff;第二个notebook的旧侧触发同一Puma worker中的p->start,通过两个libruby跳板进入system(),同时攻击者的命令处于正确的寄存器中。命令以git用户身份运行(即Puma所属账户),该账户可访问源代码、Rails密钥、服务凭证以及应用能触及的任何内部服务。

报告总结道:“成功利用后,攻击者可以以git(运行GitLab Puma worker的账户)身份执行命令。其实际影响范围取决于部署隔离程度,但可能包括仓库数据、Rails密钥、服务凭证以及应用可访问的内部服务。这可能导致源代码泄露、凭证窃取、代码库修改、持久化或横向移动。”

影响范围与修复建议

受影响的GitLab CE和EE版本包括:15.2.0至18.10.7、18.11.0至18.11.4以及19.0.0至19.0.1(所有层级)。15.2之前的版本在该路径中使用了不同的JSON解析器,因此不存在漏洞。15.2至18.9版本不在GitLab安全维护的补丁轨道内,不会收到后向移植——这些实例需要迁移到受支持的版本。对于Helm和Operator部署,相关版本是运行Puma的Webservice镜像内部GitLab的版本,而非chart版本。请升级至18.10.8、18.11.5或19.0.2。截至目前,Depthfirst和GitLab均未验证任何纯配置层面的缓解措施。