前言
GitLab是利用Ruby_on_Rails的一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。它拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。团队成员可以利用内置的简单聊天程序(Wall)进行交流。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。
近日,8.9.0 及以下版本的 GitLab 被发现存在远程代码执行漏洞,攻击者利用漏洞可以远程控制 Gitlab 服务器,执行恶意的命令。
漏洞分析
漏洞出现在 file_import.rb 文件,当用户通过 Gitlab 的前端页面导入一个项目时,会调用此文件内的 import 函数:

其中 remove_symlinks 用于检测导入文件中是否存在符号链接,如果有,则进行删除操作:

remove_symlinks 函数内部使用 extracted_files 列出了解压出来的所有文件:

%r{.*/\.{1,2}$} 实现了对文件名的匹配,由于 ruby 中,$ 符用于匹配一行的结尾,也就是说,当文件名中含有换行符时,上面的代码并不能匹配出文件名。所以通过创建一个以 \n 为开头的符号链接文件就可以绕过匹配,从而避免了被 extracted_files 列出。
利用上述方法绕过检测后,会在 Gitlab 的 uploads 文件夹内创建项目文件夹,其中包含了指向另一个文件夹的符号链接文件,因此,向符号链接写入恶意文件,恶意文件就会被写入到其指向的文件夹。
漏洞复现
搭建好 Gitlab 的环境:

使用 POC 构造可以绕过检测的符号链接文件,制作恶意的压缩包。step1.tar.gz 用于创建符号链接文件,step2.tar.gz 用于向符号链接指向的文件夹传入提前生成好的 ssh 公钥。

通过 WEB 页面导入第一个压缩包:

此时服务器上的 /var/opt/gitlab/gitlab-rails/uploads/Tom/ 目录下已经有了刚刚导入的项目了,其中.\nevil 链接到了 /var/opt/gitlab:

这时从 WEB 页面删除掉刚刚导入的 test 项目(项目文件不会被删除),导入同项目名的第二个压缩包,此压缩包内包含攻击者的 ssh 公钥。

第二个压缩包被解压时,会尝试往目录 \nevil 里写入 .ssh/authorized_keys,而由于上一步的符号链接\nevil指向了 /var/opt/gitlab/.ssh/authorized_keys,因此,ssh 公钥会被写入到 /var/opt/gitlab/.ssh/authorized_keys 文件。

这时使用写入公钥对应的私钥对 gitlab 服务器进行 ssh 链接就可以以 git 用户身份远程登陆服务器了:

参考
作者: JenI 转载请注明出处,谢谢
Comments !