JavaWeb解压缩漏洞之ZipSlip与Zip炸弹

前言

前面一篇博文《Android Zip解压缩目录穿越导致文件覆盖漏洞》介绍过 Android 系统 Zip 文件解压缩场景下的目录穿越漏洞,近期在学习 JavaWeb 代码审计的时候从 github 看到《OpenHarmony-Java-secure-coding-guide.md》中“从 ZipInputStream 中解压文件必须进行安全检查”章节提及 JavaWeb 系统同样涉及此类目录穿越漏洞,同时还涉及 Zip 炸弹的攻击场景,故在此学习记录下。

Zip Slip

此类漏洞指的是解压 zip 文件时没有校验各解压文件的名字,如果文件名包含 ../ 会导致解压文件被释放到目标目录之外的目录。

在《Android Zip解压缩目录穿越导致文件覆盖漏洞》一文已经讲过原理,不再过多赘述。直接沿用原来的恶意 Zip 生成代码和 Zip 解压缩代码即可:

import zipfiledef zip_slip_file(output_path):try:with open("source/test.txt", "r") as f:binary = f.read()zipFile = zipfile.ZipFile(output_path, "a", zipfile.ZIP_DEFLATED)zipFile.writestr("../../test.txt", binary)zipFile.close()except Exception as e:print(e)if __name__ == '__main__':zip_slip_file(r'result/test.zip')
    public static void unzipFile(String zipPtath, String outputDirectory) throws IOException {File file = new File(outputDirectory);if (!file.exists()) {file.mkdirs();}InputStream inputStream = new FileInputStream(zipPtath); ;ZipInputStream zipInputStream = new ZipInputStream(inputStream);byte[] buffer = new byte[1024 * 1024];int count;ZipEntry zipEntry;while ((zipEntry = zipInputStream.getNextEntry()) != null){if (!zipEntry.isDirectory()) {String fileName = zipEntry.getName();System.out.println("解压文件的名字: " + fileName + ",解压文件的大小: " + zipEntry.getSize());file = new File(outputDirectory + File.separator + fileName);file.createNewFile();FileOutputStream fileOutputStream = new FileOutputStream(file);while ((count = zipInputStream.read(buffer)) > 0) {fileOutputStream.write(buffer, 0, count);}fileOutputStream.close();}}zipInputStream.close();System.out.println("解压完成!");}

运行结果如下,成功进行路径穿越:
image.png
在实际漏洞利用中,可借助上述 Zip Slip 漏洞,对系统重要文件或可执行文件进行被覆盖,从而造成系统故障或任意代码执行的危害。

Zip 炸弹

重点介绍下 Zip 炸弹,先看下 OpenHarmony Java 安全编码指导文档的相关描述:
image.png
Zip 炸弹的大致原理是 zip 炸弹文件中有大量刻意重复的数据,这种重复数据在压缩的时候是可以被丢弃的,这也就是压缩后的文件其实并不大的原因。最为典型的 Zip 炸弹就是 42.zip,一个 42KB 的文件,解压完其实是个 4.5 PB(1 PB=1024 TB) 的“炸弹”,详细原理可参见:A better zip bomb。

漏洞演示

Github 有生成 Zip 炸弹的现成项目: CreeperKong/zipbomb-generator。

脚本用法很简单,如下指定生成包含一个 3.9G 左右大小的 test.zip 文件:

python zipbomb.py --mode=quoted_overlap --num-files=1 --compressed-size=3999999 > test.zip

image.png
修改 --num-files=10 参数则可以令 zip 中包含 10 个重复的上述文件(当然还可以包含更多):
image.pngimage.png
由上面可见,如果 Web 服务器从客户端发送过来的 http 报文中提取 zip 文件并进行解压缩的时候没校验 zip 文件夹内部文件的大小的话,将导致攻击者可以传递 zip 炸弹耗尽服务器资源,形成严重的 Dos 攻击。

历史上知名组件的相关漏洞的话可以参见 ZIP bomb vulnerability in HuTool:
image.png

错误修补

上文提到使用 zipEntry.getSize() 函数获取 zip 文件大小是不可取,zipEntry.getSize()是从 zip 文件中的固定字段中读取单个文件压缩前的大小,如何篡改并欺骗服务器?

先模仿一段存在缺陷的修复代码:

    public static void unzipFile(String zipPtath, String outputDirectory) throws IOException {File file = new File(outputDirectory);if (!file.exists()) {file.mkdirs();}InputStream inputStream = new FileInputStream(zipPtath); ;ZipInputStream zipInputStream = new ZipInputStream(inputStream);byte[] buffer = new byte[1024 * 1024];int count;ZipEntry zipEntry;while ((zipEntry = zipInputStream.getNextEntry()) != null){if (!zipEntry.isDirectory()) {String fileName = zipEntry.getName();System.out.println("解压文件的名字: " + fileName + ",解压文件的大小: " + zipEntry.getSize());// 判断被压缩的文件的大小,单个文件不得大于4Mbif(zipEntry.getSize() < 4096){file = new File(outputDirectory + File.separator + fileName);file.createNewFile();FileOutputStream fileOutputStream = new FileOutputStream(file);while ((count = zipInputStream.read(buffer)) > 0) {fileOutputStream.write(buffer, 0, count);}fileOutputStream.close();}else {System.out.println("文件大小超出限制!");return;}}}zipInputStream.close();System.out.println("解压完成!");}

image.png
上述代码判断被压缩的文件的大小,单个文件不得大于 4Mb,如何绕过?

步骤很简单,首先下载用于修改二进制文件的 010editor 软件,安装后打开上面演示用的 Zip 炸弹 test.zip(包含了一个 3.9G 的大文件):
image.png
image.png
修改图示 frUncompressedsize 字段的值后,重新运行 Java 程序对其进行解压缩,可成功绕过文件大小限制,解压出目标文件:
image.png
用 VSCode 可成功打开上述解压缩出来的文件(文件内容全都是 aaaaa……),意味着文件并未损坏:
image.png
可以看到,此时zipEntry.getSize() 函数获取到的压缩文件大小已经变成我们修改完以后的值(10),同时成功解压缩出 3.9G 大小的目标文件,成功绕过了修复代码对于压缩文件的大小限制。

值得注意的是,从上述截图也可以看到修改了 zip 文件的 frUncompressedsize 字段的值以后,解压缩 zip 文件会报错,如果直接使用 7-zip 进行解压缩的话更是直接报错而终止,提取不出任何文件:

java.util.zip.ZipException: invalid entry size (expected 10 but got 396289 bytes)at java.util.zip.ZipInputStream.readEnd(ZipInputStream.java:384)at java.util.zip.ZipInputStream.read(ZipInputStream.java:196)at java.io.FilterInputStream.read(FilterInputStream.java:107)at Util.Util.unzipFile(Util.java:42)at Main.main(Main.java:14)

image.png
但是通过实践也可以看到,通过上述 Java 代码可成功解压缩出来目标文件,这样子的话就不影响我们通过修改 zip 文件的 frUncompressedsize 字段的值,制作 zip 炸弹绕过服务端的文件大小校验检测,完成攻击利用。

安全编码

最后直接看看《OpenHarmony-Java-secure-coding-guide》提供的 Zip 文件解压缩的安全编码示例:

private static final long MAX_FILE_COUNT = 100L;
private static final long MAX_TOTAL_FILE_SIZE = 1024L * 1024L;...public void unzip(FileInputStream zipFileInputStream, String dir) throws IOException {long fileCount = 0;long totalFileSize = 0;try (ZipInputStream zis = new ZipInputStream(zipFileInputStream)) {ZipEntry entry;String entryName;String entryFilePath;File entryFile;byte[] buf = new byte[10240];int length;while ((entry = zis.getNextEntry()) != null) {entryName = entry.getName();//先对文件名的合法性进行校验entryFilePath = sanitizeFileName(entryName, dir);entryFile = new File(entryFilePath);if (entry.isDirectory()) {creatDir(entryFile);continue;}fileCount++;//对zip压缩包中的文件数量进行限制,设置了上限阈值if (fileCount > MAX_FILE_COUNT) {throw new IOException("The ZIP package contains too many files.");}//此处不再同通过zipEntry.getSize()函数获取 zip 文件大小,而是通过文件数据流直接读取整个文件的数据并统计大小try (FileOutputStream fos = new FileOutputStream(entryFile)) {while ((length = zis.read(buf)) != -1) {totalFileSize += length;zipBombCheck(totalFileSize);fos.write(buf, 0, length);}}}}
}//防止压缩文件名携带../导致的Zip Slip路径穿越漏洞
private String sanitizeFileName(String fileName, String dir) throws IOException {File file = new File(dir, fileName);String canonicalPath = file.getCanonicalPath();if (canonicalPath.startsWith(dir)) {return canonicalPath;}throw new IOException("Path Traversal vulnerability: ...");
}private void creatDir(File dirPath) throws IOException {boolean result = dirPath.mkdirs();if (!result) {throw new IOException("Create dir failed, path is : " + dirPath.getPath());}...
}//防止zip炸弹
private void zipBombCheck(long totalFileSize) throws IOException {if (totalFileSize > MAX_TOTAL_FILE_SIZEG) {throw new IOException("Zip Bomb! The size of the file extracted from the ZIP package is too large.");}
}

上述示例中,一共做了 3 项目安全检查:

  1. 在解压每个文件之前对其文件名进行校验,如果校验失败,整个解压过程会被终止,防止路径穿越漏洞;
  2. 解压缩过程中,对每个文件通过文件数据流识别其实际大小,如果达到指定的阈值(MAX_TOTAL_FILE_SIZE),会抛出异常终止解压操作;
  3. 同时,程序会统计解压出来的文件的数量,如果达到指定阈值(MAX_FILE_COUNT),会抛出异常终止解压操作。

总结

从上面的安全示例编码可以看到,简简单单的一个常见 Zip 文件解压缩过程,需要做的安全校验却并不少。总的来说,研发人员在编写对用户可见的 zip 文件上传功能时,一定要严格校验好 zip 文件中待解压缩的文件文件名是否包含../非法字符,校验带解压的文件大小,同时禁止通过 zipEntry.getSize() 函数获取 zip 文件大小,最后也需要校验下解压缩出来的文件总数(设置阈值,毕竟积少成多,通过大量中小型文件也可以完成 zip 炸弹攻击)。

本文参考文章:

  1. Java代码审计指南;
  2. OpenHarmony-Java-secure-coding-guide;
  3. 压缩炸弹(zipbomb)制作(附演示);
  4. 一个42KB的文件,是如何解压完变成一个4.5PB的数据;
  5. https://github.com/CreeperKong/zipbomb-generator;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/288383.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何理解CDN?说说实现原理?

一、是什么 CDN (全称 Content Delivery Network)&#xff0c;即内容分发网络 构建在现有网络基础之上的智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发、调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c;降…

Lua热更新(xlua)

发现错误时检查是否:冒号调用 只需要导入asset文件夹下的Plugins和Xlua这两个文件即可,别的不用导入 生成代码 和清空代码 C#调用lua using Xlua; 需要引入命名空间 解析器里面执行lua语法 lua解析器 LuaEnv 单引号是为了避免引号冲突 第二个参数是报错时显示什么提示…

pytorch常用的模块函数汇总(1)

目录 torch&#xff1a;核心库&#xff0c;包含张量操作、数学函数等基本功能 torch.nn&#xff1a;神经网络模块&#xff0c;包括各种层、损失函数和优化器等 torch.optim&#xff1a;优化算法模块&#xff0c;提供了各种优化器&#xff0c;如随机梯度下降 (SGD)、Adam、RMS…

工业物联网关的应用及相关产品-天拓四方

随着科技的飞速发展&#xff0c;智能制造业已成为工业领域的转型方向。在这一转变中&#xff0c;工业物联网关发挥着至关重要的作用。作为连接物理世界与数字世界的桥梁&#xff0c;工业物联网关不仅实现了设备与设备、设备与云平台之间的互联互通&#xff0c;更通过实时数据采…

Fabric Measurement

Fabric Measurement 布料测量

低功耗、低成本 NAS 的可能性

使用现状&#xff1a;多台工作电脑&#xff0c;家里人手一台&#xff0c;还在两个住处 有好几台工作电脑&#xff0c;不同电脑有不同的用途&#xff0c;最大的问题就是各个电脑上文件的同步问题&#xff0c;这里当然就需要局域网里的公共文件夹&#xff0c;在NAS的问题上查了网…

FreeRTOS(三)

第二部分 事件组 一、事件组的简介 1、事件 事件是一种实现任务间通信的机制&#xff0c;主要用于实现多任务间的同步&#xff0c;但事件通信只能是事件类型的通信&#xff0c;无数据传输。其实事件组的本质就是一个整数(16/32位)。可以是一个事件发生唤醒一个任务&#xff…

【C语言进阶篇】编译和链接

【C语言进阶篇】编译和链接 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;C语言&#x1f353; &#x1f33c;文章目录&#x1f33c; 编译环境与运行环境 1. 翻译环境 2. 编译环境&#xff1a;预编译&#xff08;预处理&#xff09;编…

Mac上的Gatekeeper系统跟运行时保护

文章目录 问题&#xff1a;无法打开“xxx.xxx”&#xff0c;因为无法验证开发者。macOS无法验证此App是否包含恶意软件。如何解决&#xff1f; 参考资料门禁运行时保护 问题&#xff1a;无法打开“xxx.xxx”&#xff0c;因为无法验证开发者。macOS无法验证此App是否包含恶意软件…

解析SpringBoot自动装配原理前置知识:解析条件注释的原理

什么是自动装配&#xff1f; Spring提供了向Bean中自动注入依赖的这个功能&#xff0c;这个过程就是自动装配。 SpringBoot的自动装配原理基于大量的条件注解ConditionalOnXXX&#xff0c;因此要先来了解一下条件注解相关的源码。 以ConditionalOnClass为例 首先来查看Conditi…

兼顾陪读|本科学历律师自费赴美国加州大学伯克利分校访学

S律师拟陪同孩子赴海外就读&#xff0c;决定以访问学者身份&#xff0c;申请美国J类签证出国以兼顾陪读。因本科学历&#xff0c;无文章且有地域要求&#xff0c;自己申请无果后做了全权委托。为此我们酌情制定了三条申请策略&#xff0c;最终落实加州大学伯克利分校的访学职位…

NSString有哪些创建对象的方法?创建的对象分别存储在什么区域?

NSString有哪些创建对象的方法&#xff1f;创建的对象分别存储在什么区域&#xff1f; 一般通过NSString创建对象的方法有&#xff1a; NSString *string1 "123";NSString *string2 [[NSString alloc] initWithString:"123"];NSString *string3 [NSSt…

解决方案:如何安装neo4j软件

文章目录 一、安装JDK二、安装neo4j 一、安装JDK 第一步先安装JDK&#xff0c;因为neo4j环境需要JDK&#xff0c;过程比较多&#xff0c;截图如下&#xff1a; 安装JDK网址 https://www.oracle.com/java/technologies/downloads winR&#xff0c;输入cmd&#xff0c;再输入j…

Leetcode70. 爬楼梯(动态规划)

Leetcode原题 Leetcode70. 爬楼梯 标签 记忆化搜索 | 数学 | 动态规划 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f;示例 1&#xff1a;输入&#xff1a;n 2 输出&#xff1a;2 解…

数据分析之POWER Piovt透视表分析与KPI设置

将几个数据表之间进行关联 生成数据透视表 超级透视表这里的字段包含子字段 这三个月份在前面的解决办法 1.选中这三个月份&#xff0c;鼠标可移动的时候移动到后面 2.在原数据进行修改 添加列获取月份&#xff0c;借助month的函数双击日期 选择月份这列----按列排序-----选择月…

C++ 控制语句(一)

一 顺序结构 程序的基本结构有三种&#xff1a; 顺序结构、分支结构、循环结构 大量的实际问题需要通过各种控制流程来解决。 1.1 顺序结构 1.2 简单语句和复合语句 二 循环 2.1 for循环 语句流程图 注意&#xff1a;使用for语句的灵活性 三 while语句 四 do while语句

【LLM多模态】Cogvlm图生文模型结构和训练流程

note Cogvlm的亮点&#xff1a; 当前主流的浅层对齐方法不佳在于视觉和语言信息之间缺乏深度融合&#xff0c;而cogvlm在attention和FFN layers引入一个可训练的视觉专家模块&#xff0c;将图像特征与文本特征分别处理&#xff0c;并在每一层中使用新的QKV矩阵和MLP层。通过引…

【LaTeX】7实现章节跳转

使用 LaTeX 实现章节跳转 写在最前面1. 引入 hyperref 包2. 标记章节3. 引用章节示例代码注意 小技巧总结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你的陪伴与支持 ~ &#x1f680; 欢迎一起踏上探险之旅&#xff0c;…

Vue 3中ref和reactive的区别

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

碳课堂|什么是碳资产?企业如何进行碳资产管理?

碳资产是绿色资产的重要类别&#xff0c;在全球气候变化日益严峻的背景下备受关注。在“双碳”目标下&#xff0c;碳资产管理是企业层面实现碳减排目标和低碳转型的关键。 一、什么是碳资产&#xff1f; 碳资产是以碳减排为基础的资产&#xff0c;是企业为了积极应对气候变化&…