java slip,Zip Slip学习笔记

就学习做下笔记

本质:么有对压缩包中的文件名进行合法性校验,直接将文件名拼接到待解压目录中,导致存在路径遍历风险。

Enumeration entries = zip.getEntries();

while (entries.hasMoreElements()) {

ZipEntry e = entries.nextElement();

//主要是这一步,毫无防备的拼接

File f = new File(destinationDir, e.getName());

InputStream input = zip.getInputStream(e);

IOUtils.copy(input, write(f));

}

解决方法

String canonicalDestinationDirPath = destinationDir.getCanonicalPath();

File destinationfile = new File(destinationDir, e.getName());

//关键在这一步骤

String canonicalDestinationFile = destinationfile.getCanonicalPath();

if (!canonicalDestinationFile.startsWith(canonicalDestinationDirPath)) {

throw new ArchiverException("Entry is outside of the target dir: " + e.getName());

}

关于复现

网上比较常见的例子是ant和zt-zip的,不过对于ant那个例子稍稍有点疑问,比如librebuff:Zip Slip任意文件覆盖漏洞分析这篇里面提到的unzip

public class Unzip {

public static void main(String[] args) throws IOException {

//解压zip的包

String fileAddress = "C:/Users/DELL/Desktop/zip_slip/test/evil.zip";

//zip文件解压路径

String unZipAddress = "C:/Users/DELL/Desktop/zip_slip/test/";

//去目录下寻找文件

File file = new File(fileAddress);

ZipFile zipFile = null;

try {

zipFile = new ZipFile(file,"GBK");//设置编码格式

} catch (IOException exception) {

exception.printStackTrace();

System.out.println("解压文件不存在!");

}

Enumeration e = zipFile.getEntries();

while(e.hasMoreElements()) {

ZipEntry zipEntry = (ZipEntry)e.nextElement();

System.out.println(zipEntry.getName());

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.deleteOnExit();

}

}

这里面用到的ZipEntry是Java.util.zip.ZipEntry,虽然ZipFile()方法属于ant但是本质来说其实是路径拼接的问题,也就是File f = new File(unZipAddress + zipEntry.getName());这步,所以这段代码即使在有过补丁的ant包中,也是可以执行成功的。实际上,这个漏洞在哪修复的呢:https://github.com/apache/ant/commit/e56e54565804991c62ec76dad385d2bdda8972a7#diff-32b057b8e95fa2b3f7d644552643010aR11

修复位置是自己封装的一个解压缩的一个文件,所以官方推荐的写法是这样的:

/**

* 解压缩文件和文件夹

*

* @param zipFilepath 需要被解压的zip文件路径

* @param destDir 将要被解压到哪个文件夹

* @throws BuildException

* @throws RuntimeException

*/

public static void unzip(String zipFilepath, String destDir) throws BuildException, RuntimeException {

if (!new File(zipFilepath).exists()) {

throw new RuntimeException("zip file " + zipFilepath + " does not exist.");

}

Project proj = new Project();

Expand expand = new Expand();

expand.setProject(proj);

expand.setTaskType("unzip");

expand.setTaskName("unzip");

expand.setEncoding("GBK");

expand.setSrc(new File(zipFilepath));

expand.setDest(new File(destDir));

expand.execute();

System.out.println("uncompress successed.");

}

追踪一下就知道这个setSrc后面的exactFile()调用了补丁函数。

如果是封装好了,可以认为是个组件漏洞, 不然就应该说这个漏洞是开发者自己写代码不小心,未经验证就拼接了路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值