Zip Slip漏洞综述
字数 1373 2025-08-29 08:32:18
Zip Slip漏洞深度分析与防御指南
1. Zip Slip漏洞概述
Zip Slip是一种广泛存在的关键存档提取漏洞,允许攻击者在系统中任意写入文件,可能导致远程命令执行。该漏洞由Snyk安全团队于2018年6月5日公开披露,影响上千个工程项目,包括HP、亚马逊、Apache等知名企业的项目。
1.1 漏洞影响范围
- 影响生态系统:Java、JavaScript、Ruby、.NET和Go等
- 影响存档格式:zip、tar、jar、war、cpio、apk、rar、7z等
- 特别严重领域:Java生态系统由于缺乏高效处理存档文件的中心库函数,问题尤为突出
2. 漏洞原理与利用方式
2.1 漏洞本质
Zip Slip是一种目录遍历漏洞,攻击者通过构造含有特殊路径的存档文件(如../../evil.sh),在提取时突破目标目录限制,向系统任意位置写入文件。
2.2 利用条件
- 恶意存档文件:包含一个或多个带有目录遍历路径的文件
- 不安全的提取代码:提取过程未对文件路径进行验证
2.3 典型攻击流程
- 攻击者构造包含恶意路径的存档文件(如
../../../tmp/evil.sh) - 受害者应用提取该存档文件
- 恶意文件被写入系统敏感位置(如
/tmp、/etc等) - 当系统或用户执行被覆盖的文件时,触发远程命令执行
3. 漏洞代码示例与修复方案
3.1 Java生态系统
漏洞代码示例
Enumeration<ZipEntry> 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));
}
修复方案
Enumeration<ZipEntry> entries = zip.getEntries();
while (entries.hasMoreElements()) {
ZipEntry e = entries.nextElement();
File f = new File(destinationDir, e.getName());
String canonicalPath = f.getCanonicalPath();
if (!canonicalPath.startsWith(destinationDir.getCanonicalPath() + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + e.getName());
}
InputStream input = zip.getInputStream(e);
IOUtils.copy(input, write(f));
}
3.2 JavaScript生态系统
漏洞代码示例
fs.createReadStream(path.join(dest, entry.path))
.pipe(fs.createWriteStream(path.join(targetPath, entry.path)));
修复方案
const extractPath = path.join(targetPath, entry.path);
if (extractPath.indexOf(path.resolve(targetPath)) !== 0) {
throw new Error("Entry is outside of the target dir: " + entry.path);
}
fs.createReadStream(path.join(dest, entry.path))
.pipe(fs.createWriteStream(extractPath));
3.3 .NET生态系统
漏洞代码示例
var entry = zip.GetEntry("../../evil.sh");
var fullPath = Path.Combine(destinationDirectory, entry.FullName);
entry.ExtractToFile(fullPath);
修复方案
var entry = zip.GetEntry("../../evil.sh");
var fullPath = Path.GetFullPath(Path.Combine(destinationDirectory, entry.FullName));
if (!fullPath.StartsWith(Path.GetFullPath(destinationDirectory))) {
throw new IOException("Entry is outside of the target dir: " + entry.FullName);
}
entry.ExtractToFile(fullPath);
3.4 Go生态系统
漏洞代码示例
for _, file := range reader.File {
err := os.MkdirAll(filepath.Dir(file.Name), os.ModePerm)
if err != nil {
return err
}
outFile, err := os.Create(file.Name)
if err != nil {
return err
}
// ...
}
修复方案
for _, file := range reader.File {
destPath := filepath.Join(dest, file.Name)
if !strings.HasPrefix(destPath, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("%s: illegal file path", file.Name)
}
err := os.MkdirAll(filepath.Dir(destPath), os.ModePerm)
if err != nil {
return err
}
outFile, err := os.Create(destPath)
if err != nil {
return err
}
// ...
}
4. 漏洞检测与防御措施
4.1 检测方法
- 代码审计:检查项目中是否存在不安全的存档提取代码
- 依赖扫描:使用工具(如Snyk)扫描项目依赖中是否存在有漏洞的库
- 测试用例:构造恶意存档文件测试应用是否会被利用
4.2 防御措施
-
路径规范化与验证:
- 使用
getCanonicalPath()(Java)、Path.GetFullPath()(.NET)、filepath.Clean()(Go)等方法规范化路径 - 验证最终路径是否在目标目录内
- 使用
-
使用安全库:
- 优先使用已修复该漏洞的库版本
- 避免从StackOverflow等社区复制未经安全验证的代码
-
安全开发实践:
- 在CI/CD流程中加入安全测试
- 定期更新依赖库
- 实施最小权限原则,限制应用的文件系统访问权限
5. 受影响项目与资源
5.1 已知受影响项目
- Oracle
- Amazon
- Spring/Pivotal
- Alibaba
- Jenkins
- Eclipse
- OWASP
- SonarQube
- OpenTable
- Arduino
- ElasticSearch
- Selenium
- Gradle
- JetBrains
5.2 参考资源
6. 总结
Zip Slip是一个严重且广泛存在的漏洞,主要由于不安全的存档提取实现导致。防御该漏洞的关键在于:
- 对所有提取的文件路径进行规范化处理
- 严格验证最终路径是否在目标目录内
- 使用已修复该漏洞的库版本
- 在开发流程中加入安全测试环节
通过实施这些措施,可以有效防范Zip Slip漏洞带来的安全风险。