最近在我们在bash fuzz项目中,发现诸多问题,现在公布其中的3处本地拒绝服务漏洞的分析。该漏洞已经报告给bash的发开者,并且在最新版中得到了修复。

漏洞描述:

bash-4.3 libreadlinesavestring.c ( 或者bash-1.14.7 libreadlinereadline.c )文件的savestring()函数存在NULL指针引用,对该漏洞的成功利用会造成本地拒绝服务

 

危害等级:

低危-本地拒绝服务

 

漏洞验证:

i-love-bash

 

bash-c '>$(ss=111 declare -i ss )'

或者

bash -c 'vvv=1 unset vvv >>`declare -i vvv`'

 

 

修复方法:

---savestring.c   2010-08-0314:08:04.000000000 +0800

+++ savestring.c.new     2014-12-03 19:38:11.459000532 +0800

@@ -35,7 +35,7 @@

{

char *ret;

 

-  ret = (char *)xmalloc(strlen (s) + 1);

+  ret = (char *)xmalloc (NULL == s ? 1 : strlen (s) + 1);

strcpy (ret, s);

return ret;

}

 

详细分析

对该漏洞的理解分为三部分,如下:

1.神奇的NULL指针

根据调试信息,我们在declare_internal()中找到最终传入NULL指针的代码,如图1。

在NULL传输之前,我们需要构造诸多变量的值,如var,offset等。我们暂时把注意力放在NULL指针的传递上。NULL指针分别流经bind_variable()函数(图2),bind_tempenv_variable()函数(图3),最后到savestring()由于strlen(NULL)引发崩溃(图4)。在bind_tempenv_variable()函数(图3)中,我们注意到在进入savestring()之前,在temporary_env中查询了是否存在name变量(对应poc中的变量ss),代码如下:

var = temporary_env ? hash_lookup (name, temporary_env) :(SHELL_VAR *)NULL;

 

结果是找到了相关的值。于是在进入savestring()之后,作者显然未加验证,bash不出意料地发生崩溃。

现在我们已经了解是NULL导致程序崩溃,回想整个过程,我们猜想作者传入NULL的逻辑是有更大漏洞,下文将证明,这一推断是正确的。

图1

图2

图3

图4

2.为什么传NULL指针

现在让我们来寻找作者传入NULL的逻辑,在declare_internal()(见图1)中我们看到关键变量有两个,第一个是

if (offset)

offset的取值代码见图5,取决于assignment(),见图6,可以看出,类似”ss=111”这种形式,offset即为0。

接着我们看第二个关键变量,

var = mkglobal ? find_global_variable (name) : find_variable (name);

if (var == 0)

 

mkglobal的值一般为0,name值对应poc中的ss,为什么find_variable(“ss”)值会为空呢?我们知道在第一步分析中,在崩溃之前,bind_tempenv_variable()使用了如下查询的代码,并且返回非空。

var = temporary_env ? hash_lookup (name, temporary_env) :(SHELL_VAR *)NULL;

 

为什么之前找不到的ss变量,之后就找到了呢?

带着这个疑问,让我们看find_variable()函数(见图7)。可以看到,我们需要使find_variable_internal()返回0;如图8,我们发现find_variable_internal()的返回值可以由两种方式得到,分别是

var = hash_lookup (name, temporary_env);

var = var_lookup (name, vc);

 

即可以查询两张不同的表产生结果,分别是temporary_env和vc表!还记得bind_tempenv_variable()只能查询temporary_env吗?因此,显而易见的,poc代码之所以能造成崩溃,是因为前后查询不通的变量表,完整走出一条崩溃之路。

现在让我们看看这一条“崩溃之路“是如何实现的。

更进一步地查看find_variable()(图7)和find_variable_internal()(图8)代码,我们发现这里的逻辑存在微妙的错误,可以注意到find_variable_internal()的第二个参数的产生式为:

expanding_redir == 0 && (assigning_in_environment|| executing_builtin)

 

而选择查询哪张表的的关键参数search_tempenv的赋值式为:

search_tempenv = force_tempenv || (expanding_redir == 0&& subshell_environment);

 

可以注意到两个产生式都包含expanding_redir。如果expanding_redir == 1,其实就走人错误的查询表的方式!见图9,事实确实是expanding_redir的值为1。现在,我们确认bash作者在处理重定向的变量表查询逻辑时存在错误!但是,故事仍未结束。

图5

图6

图7

图8

图9

3.后续彩蛋

现在我们已经可以控制bash的运行逻辑,那我们继续深挖相关漏洞。我们暂时发现两处。

第一处:与本文原理相同但是攻击路径不同

bash-4.3/builtins/setattr.def

var = bind_variable (name, (char*)NULL, 0);

 

第二处:与本文原理相同但是攻击点不同

bash-4.3/builtins/declare.def

staticint declare_internal (list, local_var)

var = mkglobal ?bind_global_variable (name, (char *)NULL, 0) : bind_variable (name, (char*)NULL, 0);

/bash-4.3/variables.c文件中的

char *make_variable_value (var, value, flags)函数

else if (*value)会导致读0

 

 

【原文:Bash 3处本地拒绝服务0day分析 作者:max SP小编整理发布】

源链接

Hacking more

...