搜索

perl归档zip任意文件覆盖漏洞

发表于 2026-10-17 06:01:54 来源:烟消火灭网
```html Perl归档zip任意文件覆盖漏洞

Perl归档zip任意文件覆盖漏洞

你写了个Perl脚本,用Archive::Zip解压用户上传的意文压缩包,觉得挺方便。归档盖漏但攻击者传一个zip进来,意文里面藏个../../../../etc/cron.d/backdoor,归档盖漏你的意文脚本乖乖把文件写到系统目录里去了。这不是归档盖漏什么冷门CVE,就是意文路径穿越,但Perl的归档盖漏zip模块历史上在这块栽过好几次。

先看一个真实案例。意文2018年,归档盖漏Archive::Zip被曝出CVE-2018-10860,意文当时1.60及之前的归档盖漏版本,extractTree()方法压根不检查成员文件名里的意文..路径。你调一下extractTree(),归档盖漏它就按压缩包里写的相对路径往外解,没任何过滤。攻击者构造一个zip,里面塞个../../.ssh/authorized_keys,只要运行解压的进程有权限,文件直接覆盖到目标位置。这个漏洞影响面不小,很多Perl写的Web应用、备份脚本、CI工具都在用Archive::Zip。

修复方式倒不复杂。1.61版本加了检查,如果成员名包含..或者绝对路径,就拒绝解压。但问题在于,很多老代码依赖旧行为,升级后反而报错。我见过一个内部工具,升级Archive::Zip后解压全挂,因为压缩包里有些文件带./前缀,新版本直接抛异常。开发者只好自己写个eval包一层,忽略错误——这等于又把防护绕过去了。

# 存在漏洞的典型写法 my $zip = Archive::Zip->new($uploaded_file); $zip->extractTree(); # 1.60之前,这里没有任何路径校验 # 攻击者构造的zip成员名: # ../../../../home/user/.bashrc # /etc/passwd (绝对路径在某些版本也能写)

另一个坑是符号链接。zip格式支持存储符号链接,解压时如果按链接目标写文件,也能实现任意文件覆盖。比如压缩包里放一个符号链接link -> /etc/shadow,再放一个普通文件link,解压时先创建链接,再往链接里写数据,实际就改写了/etc/shadow。Archive::Zip在1.64之前对符号链接的处理也有问题,extractTree()会跟随链接写入。这个手法比..更隐蔽,因为文件名看起来完全正常。

注意: 不是只有Archive::Zip有问题。IO::Uncompress::Unzip、Archive::Extract这些模块在不同版本里都出过路径穿越。Perl的zip生态整体上对安全边界考虑得比较晚。

我翻过Archive::Zip的提交记录,1.61那个补丁其实挺粗暴的:在Archive::Zip::Member里加了个_isAbsolutePath和_containsDotDot检查,然后extractTree()里逐个成员判断。但如果你不用extractTree(),而是自己遍历成员、调extractToFile(),那检查逻辑得自己写。很多开发者根本不知道这回事,以为用了标准库就安全了。

怎么防?最简单的办法:解压前遍历所有成员名,用正则把..、绝对路径、符号链接都拦掉。别信压缩包里的任何路径信息。如果业务允许,解压到一个临时目录,再用File::Spec->catfile拼出目标路径,检查规范化后的路径是否还在预期根目录下。Perl里可以用File::Spec->canonpath和File::Spec->abs2rel做这个判断。

use File::Spec; use Cwd qw(abs_path); my $base = abs_path('/safe/extract/dir'); for my $member ($zip->members) {  my $name = $member->fileName; # 拒绝绝对路径和 .. next if $name =~ m{ ^/} || $name =~ /\.\./; my $target = File::Spec->catfile($base, $name); my $real = abs_path($target); # 注意:文件不存在时 abs_path 返回 undef # 更稳妥的做法:用 File::Spec->canonpath 做字符串规范化 my $canon = File::Spec->canonpath($target); die "path traversal" unless index($canon, $base) == 0; }

但这里有个细节:abs_path要求路径已存在,解压前目标文件还没创建,所以用不了。得用File::Spec->canonpath做纯字符串规范化,再比较前缀。另外Windows下路径分隔符和盘符也得考虑,Archive::Zip在Windows上对..\的处理更混乱。

说句实在的,Perl社区对这类漏洞的反应速度不算快。CVE-2018-10860从报告到修复花了几个月,期间很多发行版还在用旧版。如果你维护的代码里用了Archive::Zip,别光看版本号,把解压逻辑过一遍,自己加一层路径校验。压缩包这东西,从不可信来源来的,里面每个字节都可能是攻击载荷。

最后提一个容易忽略的点:Archive::Zip的extractTree()在1.61之后虽然拒绝了..,但如果你传了while选项或者自定义过滤器,还是可能绕过。安全这东西,永远别指望一个开关就搞定。

```
随机为您推荐
友情链接
版权声明:本站资源均来自互联网,如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

Copyright © 2016 Powered by perl归档zip任意文件覆盖漏洞,烟消火灭网   sitemap

回顶部