Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZIP bomb vulnerability in HuTool #2797

Closed
A-TGAO opened this issue Dec 12, 2022 · 6 comments
Closed

ZIP bomb vulnerability in HuTool #2797

A-TGAO opened this issue Dec 12, 2022 · 6 comments
Labels

Comments

@A-TGAO
Copy link

A-TGAO commented Dec 12, 2022

测试

JDK版本: jdk_8_291
hutool版本: 全版本

问题描述

中文

漏洞描述

hutool中存在zip bomb漏洞,此漏洞发生在zip解压时, zip炸弹文件中有大量刻意重复的数据,这种重复数据在压缩的时候是可以被丢弃的,这也就是压缩后的文件其实并不大的原因,但是当解压后,文件会变得非常大,通过脚本(https://github.com/CreeperKong/zipbomb-generator)
可以生成可利用的zip文件,如下图:
image
也就是说42KB的压缩包解压后大小为5.5G,10MB的压缩包解压后大小为281TB,46MB的压缩包解压后大小为4.5PB。
在HuTool组件中,未对上述情况做严格的防护,从而导致消耗服务器统存储资源,导致拒绝服务等情况发生。

漏洞影响

影响版本:release version 4.4.2 - release version 5.8.10
影响危害:消耗服务器统存储资源,导致拒绝服务等情况发生

漏洞发现

漏洞发生在cn.hutool.core.util.ZipUtil.java文件中。
如下方法未做任何防护:

  1. cn.hutool.core.util.ZipUtil#unzip(java.lang.String)
  2. cn.hutool.core.util.ZipUtil#unzip(java.lang.String, java.nio.charset.Charset)
  3. cn.hutool.core.util.ZipUtil#unzip(java.io.File)
  4. cn.hutool.core.util.ZipUtil#unzip(java.io.File, java.nio.charset.Charset)
  5. cn.hutool.core.util.ZipUtil#unzip(java.lang.String, java.lang.String)
  6. cn.hutool.core.util.ZipUtil#unzip(java.lang.String, java.lang.String, java.nio.charset.Charset)
  7. cn.hutool.core.util.ZipUtil#unzip(java.io.File, java.io.File)
  8. cn.hutool.core.util.ZipUtil#unzip(java.io.File, java.io.File, java.nio.charset.Charset)
  9. cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipFile, java.io.File)
  10. cn.hutool.core.util.ZipUtil#unzip(java.io.InputStream, java.io.File, java.nio.charset.Charset)
  11. cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipInputStream, java.io.File)

上述11个方法最后都会调用cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipFile, java.io.File, long)方法,但是第三个参数为-1L,如下图
image
继续跟进cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipFile, java.io.File, long)
image
如上图可以看到limit参数的作用是为了防止文件过大,但是前面提到的11中方法传入的limit参数值为-1L,因此不会检测压缩文件是否过大。
另外,计算文件大小采用zipEntry.getSize()方法,而size值可以在zip文件中伪造,从而逃过上述代码的检测,具体伪造方式可参考:https://blog.csdn.net/fenwangduanyan/article/details/112969329
jadx项目也发生过此漏洞:skylot/jadx#980

漏洞复现

HuTool中的zip bomb可分为两类:

  1. 第一类是上文中列出的11种方法,没有检测文件是否过大;
  2. 第二类是直接调用cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipFile, java.io.File, long)方法,且指定了第三个参数值,这种则需要伪造zip数据包中的size value。
    这里仅仅展示第一类利用方式,具体如下:
    利用此项目代码:https://github.com/CreeperKong/zipbomb-generator 生成恶意恶意压缩文件,运行python zipbomb.py --mode=quoted_overlap --alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZ --num-files=500 --compressed-size=1000000 > tgao.zip,即可生成1019kb的压缩文件
    image

编写如下java代码:

import cn.hutool.core.util.ZipUtil;
public class ZipBombTest {
    public static void main(String[] args) {
        ZipUtil.unzip("D:/download/zipbomb-generator-master/tgao.zip",
                "D:/download/zipbomb-generator-master/tgao");
    }
}

运行上述java代码,解压后的文件夹大小如下:
image
即1019kb的压缩文件解压后16.6GB,实际大于这个值,因为我的磁盘已经装不下更多的空间了。
image

修复建议

  1. 参考jadx项目的修复方式:skylot/jadx@9b1761f
  2. 设置一个解压后文件大小默认值或者一个压缩文件解压后和解压前所占空间的比例默认值,如果超过默认值,则进行回滚操作,删除已解压的文件

English

Description

zip bomb vulnerability exists in hutool. This vulnerability occurs when zip is decompressed. There are a lot of deliberately repeated data in the zip bomb file, which can be discarded during compression. Through script (https://github.com/CreeperKong/zipbomb-generator),
A usable zip file can be generated, as shown below:
image
In other words, the size of the 42KB package is 5.5 GB, that of the 10MB package is 281TB, and that of the 46MB package is 4.5PB.
The HuTool component does not strictly protect against the preceding situations. As a result, the storage resources of the server are consumed and service denial occurs.

Impact

Affected versions: release version 4.4.2 - release version 5.8.10
Impact Damage: The storage resources of the server are consumed, resulting in denial of service

Code Audit

vulnerability in cn.Hutool.Core.Util.ZipUtil.Java file.
The following methods do not have any protection:

  1. cn.hutool.core.util.ZipUtil#unzip(java.lang.String)
  2. cn.hutool.core.util.ZipUtil#unzip(java.lang.String, java.nio.charset.Charset)
  3. cn.hutool.core.util.ZipUtil#unzip(java.io.File)
  4. cn.hutool.core.util.ZipUtil#unzip(java.io.File, java.nio.charset.Charset)
  5. cn.hutool.core.util.ZipUtil#unzip(java.lang.String, java.lang.String)
  6. cn.hutool.core.util.ZipUtil#unzip(java.lang.String, java.lang.String, java.nio.charset.Charset)
  7. cn.hutool.core.util.ZipUtil#unzip(java.io.File, java.io.File)
  8. cn.hutool.core.util.ZipUtil#unzip(java.io.File, java.io.File, java.nio.charset.Charset)
  9. cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipFile, java.io.File)
  10. cn.hutool.core.util.ZipUtil#unzip(java.io.InputStream, java.io.File, java.nio.charset.Charset)
  11. cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipInputStream, java.io.File)

The above 11 method finally call the cn.Hutool.Core.Util.ZipUtil#unzip(Java.Util.Zip.ZipFile, Java.IO.File, long) method, but the third parameter to -1L, As shown below:
image
Continue to follow up the cn.hutool.core.util.ZipUtil#unzip(java.util.zip.ZipFile, java.io.File, long)
image
As you can see in the figure above, the limit parameter is used to prevent the file from being too large, but the previous method in 11 passed the limit parameter as -1L, so it does not detect if the compressed file is too large.
In addition, the zipEntry.getSize() method is used to calculate the file size, and the size value can be forged in the zip file, so as to escape the detection of the above code.
For details, please refer to: https://blog.csdn.net/fenwangduanyan/article/details/112969329
This vulnerability also occurred on the jadx project:skylot/jadx#980

Steps to reproduce

zip bombs in HuTool fall into two categories:

  1. The first type is the 11 methods listed above, which does not detect whether the file is too large;
  2. The second type is called directly cn.Hutool.Core.Util.ZipUtil#unzip(Java.Util.Zip.ZipFile, Java.IO.File, long)method, and specifies the third parameter values, In this case, The attacker can fake the size value in the zip packet.
    Only the first type of utilization is shown here, specifically as follows:
    Using the project code (https://github.com/CreeperKong/zipbomb-generator) to generate malicious malicious compressed file, Run python zipbomb.py --mode=quoted_overlap --alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZ --num-files=500 --compressed-size=1000000 > tgao.zip to generate the compressed file of 1019kb.
    image
    Write the following java code:
import cn.hutool.core.util.ZipUtil;
public class ZipBombTest {
    public static void main(String[] args) {
        ZipUtil.unzip("D:/download/zipbomb-generator-master/tgao.zip",
                "D:/download/zipbomb-generator-master/tgao");
    }
}

Run the above java code and the size of the extracted folder is as follows:
image
That's 16.6GB for a 1019kb zip file, which is more than that, because I can't fit any more space on my disk.
image

Bug Repair Suggestions

  1. Refer to the repair method of jadx project: skylot/jadx@9b1761f
  2. Set a default value for the size of the decompressed file or the ratio of the space occupied by the decompressed file to the space occupied by the decompressed file. If the ratio exceeds the default value, the decompressed file is rolled back to delete the decompressed file.
@A-TGAO
Copy link
Author

A-TGAO commented Dec 14, 2022

已经更新issue中的修复方法,请查看

@looly
Copy link
Member

looly commented Dec 14, 2022

感谢提供详细的描述,这个漏洞我先看下,稍后处理。

@looly looly added the bug label Dec 14, 2022
@looly
Copy link
Member

looly commented Dec 14, 2022

5.8.11修复此问题,感谢!

@looly looly closed this as completed Dec 14, 2022
@a1395685892
Copy link

建议设置一个开关,用于忽略此漏洞,公司内部的文件经常会使用这种压缩的npz格式
image
@looly

@kylincodelab
Copy link

怎么加的开关?

@looly
Copy link
Member

looly commented Jun 5, 2023

@kylincodelab 在6.0.0中,ZipReader.setMaxSizeDiff(-1)即可。

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants