Tar解压漏洞的验证方法及其临时修复方案 – 作者:LEdge1

*本文中涉及到的相关漏洞已报送厂商并得到修复,本文仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担。

*本文作者:LEdge1,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

之前WinRAR出现的漏洞,没几天网上就出现了各种利用这种漏洞的攻击了,想到这,我突然想起来Linux下也有这么一款解压软件也是有漏洞的。今天给大家说一说吧 !

我们在Linux下使用最多的压缩和解压工具就是tar了。如果说这款工具出现了漏洞,那么危害还是很大的。不过还真的出现了一个解压路径的漏洞:这个漏洞出现在tar解压命令上,如果恶意者提前构造好这种有害的压缩包。当我们在使用tar命令解压的时候导致压缩包解压到不是我们指定的目录下面,导致了文件覆盖,更有甚者进行远程的代码执行!

影响范围

GNU tar :1.14 ~1.29 (包含1.29)

影响系统包括所以使用GNU tar命令的linux系统

实验环境

操作机 : Kali Linux

实验工具

tar-poc.tar :这个文件是本次漏洞试验的POC,我们将使用本文件验证漏洞

tar-1.26.tar.gz :1.26版本的tar源码

实验步骤

步骤1:漏洞分析

在实现漏洞复现之前我们得了解一下,这个漏洞的是什么原因导致的。那我们就得对源码进行分析,在进行源码的分析过程中发现了paxnames.c这个文件是有问题的,那我们废话不多说进入源码存放文件夹,盘它:

cd /root/Desktop/ // 进入桌面

cat tar-1.26/lib/paxnames.c // 预览paxnames.c文件

在tar1.26的源码包中,lib文件夹下存放着函数库和一些配置文件,其中paxnames.c文件里面存放着检测文件名和路径安全性的相关函数和配置。就是检测程序考虑的不够完美导致了漏洞的出现。

打开后,可以看到如下代码:

char *

safer_name_suffix (char const*file_name, bool link_target,

    bool absolute_names)

{

 char const *p;

 if (absolute_names)

   p = file_name;

 else {

     /* Skip file system prefixes, leading file name components that contain

 "..", and leading slashes.  */

             size_tprefix_len = FILE_SYSTEM_PREFIX_LEN (file_name);

 

     for (p = file_name + prefix_len; *p; )

 {

         if (p[0] == '.' && p[1] == '.' &&(ISSLASH (p[2]) || !p[2]))

    prefix_len = p + 2 - file_name;

 

  do

    {

      char c = *p++;

      if (ISSLASH (c))

 break;

    }

  while (*p);

 }

 

     for (p = file_name + prefix_len; ISSLASH (*p); p++)

 continue;

     prefix_len = p - file_name;

 

     if (prefix_len)

 {

  const char *prefix;

  if (hash_string_insert_prefix (&prefix_table[link_target],file_name,

     prefix_len, &prefix))

    {

      static char const *const diagnostic[] =

      {

 N_("Removing leading `%s' from member names"),

 N_("Removing leading `%s' from hard link targets")

      };

      WARN ((0, 0, _(diagnostic[link_target]), prefix));

    }

 }

   }

在研究了一段时间之后发现,这段代码里面有个safer_name_suffix函数,他的任务就是检测文件名是否合法,文件后缀是否合法。

absolute_names 是一个变量,它用来获得文件的名称,如果absolute_names变量为0,那么就将文件名中文件系统的前缀给去掉。

在之前比较老的版本,如果压缩文件中存在 .. 字符串,系统会跳过不去处理这些文件。

而在后来的版本中,safer_name_suffix不再跳过文件名中包含 ../ 字符串的恶意字符,强制删除所有存在可能被恶意访问的字符,如 ../ ,把 ../ 之前的所有字符都删除,只会留下其后面的字符。

使其与解压目标路径变成相对路径,而压缩包中的内容就会覆盖恶意访问者指定的路径文件,漏洞就这样产生了。

例如:test.tar压缩包中有一个文件夹,其文件夹路径依次为 etc/motd../etc/shadow ,然后在执行命令 tar -C / -xvf test.taretc/motd ,意思是将test.tar里面的内容解压到etc/motd目录下。

但是在safer_name_suffix函数中经过一系列操作,已经将 ../ 之前的内容都去掉了,路径名只剩下 etc/shdow ,这时候, etc/shdow 就被覆盖了。

步骤2:使用POC验证漏洞

本步将使用POC验证漏洞.

现在我们使用POC来验证漏洞,因为此POC是覆盖 etc/shadow ,所以我们首先先查看一下原始的shadow文件有什么内容。

使用命令:

cat /etc/shadow // 预览shadow文件的内容

可以看到,里面记录了各个账户的用户名、加密过的密码、上次更改密码的日期等。

接下来我们来解压POC,将他解压到 etc 目录下,使用命令:

cd /root/Desktop

tar -C / -xvf tar-poc.tar etc/motd

其中,X的意思是从归档文件中释放文件。v的意思是输出tar处理文件的信息到屏幕。f的意思是使用归档文件,一般情况下f这个选项是必选的。

这时,再次查看 etc/shadow 文件,发现已经被替换。已经不是之前的内容。

我们明明是解压到etc/motd的目录下,它却解压到etc的根目录下,覆盖了shadow文件,因此到这里,我们就成功的验证了漏洞。

实验结果分析与总结

漏洞修复

自己琢磨了一段时间之后,发现在safer_name_suffix中添加判断,如果检测到 ../ 字符串,直接报错,然后退出程序,如下:

--- lib/paxnames.c.orig    2016-04-06 00:04:47.314860045 +0300

+++ lib/paxnames.c      2016-04-06 02:08:44.962297881 +0300

@@ -18,6 +18,7 @@

#include <system.h>

#include <hash.h>

#include <paxlib.h>

+#include <quotearg.h>

/* Hash tables of strings.  */

@@ -114,7 +115,15 @@

     for (p = file_name + prefix_len; *p; )

       {

         if (p[0] == '.' && p[1] == '.' &&(ISSLASH (p[2]) || !p[2]))

-          prefix_len = p + 2 - file_name;

+            {

+            static char const *constdiagnostic[] =

+            {

+              N_("%s: Member namecontains '..'"),

+              N_("%s: Hard link targetcontains '..'")

+            };

+            FATAL_ERROR ((0, 0,_(diagnostic[link_target]),

+                          quotearg_colon(file_name)));

+          }

这种方法的确可以修复漏洞,但还有一点不足,用户在配置文件或者操作文件时,如果遇到 ../ 这种情况,到一半就强行停止下来,这样的话用户体验度很差。

*本文作者:LEdge1,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

来源:freebuf.com 2019-03-21 09:00:32 by: LEdge1

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论