2021-02-02 15:45:0710040人阅读
1. 前言
Pear Archive_Tar是PEAR团队的一个基于PHP的可以对tar包进行创建、提取等操作的类库。近期,Archive_Tar被爆出存在多个安全漏洞,包括CVE-2020-28948、CVE-2020-28949、CVE-2020-36193等,影响了使用了该类库的下游应用如Drupal等。若开发的应用中使用存在漏洞版本(<=1.4.11),请及时更新到最新1.4.12版本。
2. Tar文件结构
在漏洞分析之前,我们还是先对tar文件及其结构做一下了解。tar是Unix和类Unix系统上的归档打包工具,可以将多个文件合并为一个文件,打包后的文件名亦为“tar”, tar代表未压缩的tar文件;已压缩的tar文件则附加数据压缩格式的扩展名,如经过gzip压缩后的tar文件,扩展名为“.tar.gz”。
tar文件主要由两部分组成:头结构、文件内容,文件头及内容以512字节为一个block进行分割,最后一个block不足部分以0补齐。
通过查阅标准文档可知,上述即为头结构的具体字段,每个字段的字节数以及字节偏移。在头记录中的所有字符均使用8位本地ASCII编码。结构体中每个字段都是连续的,即结构中没有冗余数据,媒介上的每个字符都连续存放。其中文件大小size、修改时间mtime、校验值chksum都是以八进制字节方式表示。header中的name、linkname、magic、uname和gname都是以'\0'为结尾的字符串,其他所有字段均以八进制的0填充。size和mtime字段包含额外一个空格,其他的数字字段宽度包含两个额外数字位:空格和结尾符。
我们尤其要注意typeflag字段,该字段表示文件的类型,在提取文件时,如果系统不支持指定的文件类型,则该文件将被视为普通文件,并打印警告信息到标准错误输出,常见typeflag取值及对应的文件类型如下,普通文件值为0,目录为5,软链则为2。
通过下面简单的python代码,可以将文件test.txt打包到test.tar中,并且可以自定义归档后test.txt的名称。
利用xxd查看归档文件test.tar的内容,并和文档中的头结构进行一一对应,文本的内容在头结构之后,详细如下图所示。
3. 漏洞分析
在了解tar文件结构后,我们再来分析Archive_Tar处理tar文件中暴露出来的漏洞,包括CVE-2020-28948在内的多个漏洞都是在提取文件时发生的。下载pear/Archive_Tar 1.4.10版本,并编写一个简单Demo提取创建好的Tar文件到当前目录。
跟进到Archive_Tar文件的构造函数,可以发现主要是通过文件的前两位头以及后缀来确定tar文件是否被压缩以及压缩格式,方便后面调用对应的解压方法。
Archive对象调用了extract方法,跟进到extract方法的定义,$p_path为提取文件的目标路径,默认的话则为当前目录。
跟进到extractModify方法,if条件语句中_openRead方法主要用来判断传递进行的tar文件或压缩文件是否能够以正确方式读取,如果tar文件路径为远程链接,则会将其缓存下来再判断。
满足上述条件后,会调用_extractList方法提取tar文件的内容了,该方法比较长,我们挑重点的部分讲一讲。1980行会循环调用_readBlock方法,每次读取512字节;若读取的block为头结构,则会调用_readHeader方法处理并将结果返回到$v_header中。
在_readHeader方法中,除了校验长度是否为512字节外,还会计算校验值并和头结构中chksum进行比对,防止文件被篡改或者损坏。计算方法如下:将头结构的前148字节后256字节的ascii值求和,再加上8个空格ascii值(chksum字段占用的8个字节)。
提取出filename字段后,还需要调用_maliciousFilename方法判断filename字段是否包含危险字符。
跟进到私有方法_maliciousFilename,该方法只校验了是否包含phar://、../、..\三种危险字符,这里似乎存在安全风险。
在完成头结构字段的提取和分析后,我们返回_extractList方法。当满足$p_path不为当前路径以及根目录时,会将传递的参数解压路径$p_path和原始文件名进行拼接,得到新的filename路径。
接下来判断typeflag的值,当等于5即为目录时,如果目录不存在会创建目录;当为2时即符号链接时,会判断link是否为filename创建的符号链接。
当typeflag都不是上述条件中的值时,即创建文件句柄,并将文件内容写入,此时会判断size字段是否为512的倍数,会根据长度读取到文件内容。
上述过程分析了Archive_Tar类库提取tar文件的整个过程,接下来我们看看最近几个漏洞的成因。
CVE-2020-28948
根据描述,CVE-2020-28948可能导致phar反序列化漏洞,主要是phar://被拦截但是可以用大写字符PHAR://绕过。此处漏洞成因是_maliciousFilename方法并没有校验可能存在大写字符绕过的情形,并且在提取方法_extractList中,存在多处文件系统函数如file_exists等处理filename字段。
当上述文件系统函数传入phar://伪协议的文件后,可以在不依赖unserialize()直接进行反序列化操作。
CVE-2020-28949
根据描述,Archive_Tar类只对phar伪协议做了防御,可以用file://协议来覆盖文件。但通过测试发现,可以将绝对路径的文件压缩,再利用Archive_Tar类库进行提取,同样可以实现文件覆盖。并且该漏洞需要在不设置解压路径的前提下才能触发漏洞,否则会将$p_path和传入的文件名进行拼接,导致覆盖失败。上述两个漏洞的修复措施如下,添加对://字段的检测,拦截包含伪协议的文件名。
CVE-2020-36193
该漏洞主要是没有对符号链接做判断,导致可以目录穿越。根据前面分析,并没有对符号链接路径是否在解压路径下做判断,导致可以构造符号链接将文件提取到任意路径下。可以用如下python代码构建poc:
其中testdir可以链接到需要穿越的目录,其typeflag为2。而后续添加的text.txt为普通文件typeflag为0。根据上述分析,会向testdir/target.txt写入文件内容,而当testdir链接到其他目录导致了漏洞发生。
可以看到官方的修复措施如下,判断了创建的符号链接路径是否在给定的解压路径之下。
4. 安全产品解决方案
百度度御关WAF、高级威胁感知系统,以及智能威胁狩猎平台已支持该类漏洞的检测和拦截,有需要的用户可以访问anquan.baidu.com联系我们。
参考: