linux破壳漏洞,破壳漏洞(Shellshock)分析CVE-2014-6271

漏洞产生原因

而这个漏洞在于,Bash把函数体解析完了之后,去执行了函数定义后面的语句,为啥会这样呢。

通过结合补丁,我对Bash的源码简单分析了下,Bash初始化时调用了builtins/evalstring.c里的parse_and_execute函数。是的,就等于Bash初始化环境时调用了类似其他高级语言中的eval函数,它负责解析字符串输入并执行。

继续看parse_and_execute的源码,关键点在这里:

218 else if (command = global_command)

219 {

220 struct fd_bitmap *bitmap;

它判断命令是否是一个定义成全局的,新的bash进程启动后,say_hello不仅被解析成函数了,还变成全局的了:

[lu4nx@lx-pc data]$ bash -c 'typeset -f'

say_hello ()

{

echo hello world

}

declare -fx say_hello

declare命令是Bash内置的,用来限定变量的属性,-f表示say_hello是一个函数,-x参数表示say_hello被export成一个环境变量,所以这句话的意思是让say_hello成了全局有效的函数。

其实Bash本身其实是想在启动时初始环境变量以及定义一些函数,而初始的方式就是去把 变量名=值 这样的赋值语句用eval去执行一次,如果出现了函数定义,就把它转变成函数,除此之外就不想让它干其他的了,可偏偏它在扫描到函数定义时,把它转变成函数的过程中不小心执行了后面的命令,这其实不是eval的错,这是做语法解析时没考虑严格,所以补丁加了这么一句话来判断函数体合法性:

if((flags&SEVAL_FUNCDEF)&& command->type!=cm_function_def)

上面的官方补丁打了补丁之后,随后被绕过

执行下面命令:

上面这段代码运行起来会报错,但是它要的就是报错,报错后会在你在当前目录下生成一个echo的文件,这个文件的内容是一个时间文本。下面是上面 这段命令执行出来的样子。

原理分析:

官方提供的第一个补丁主要修改了:

1、参数类型和个数的限制,从注释中即可看出:

#defineSEVAL_FUNCDEF0x080/* only allow function definitions */#defineSEVAL_ONECMD0x100/* only allow a single command */

2、给builtins/evalstring.c文件里的parse_and_execute加入了类型判断:

if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)

{

不合法,不是函数定义

break;

}

...

// 逻辑为真就表明参数不合法

if (flags & SEVAL_ONECMD)

break;

从上面即可看出补丁思路:如果不是函数定义、命令(command)超过一个就判为不合法。什么才算合法呢,Bypass POC给出了答案:

env X='() { (x)=>\' ./bash -c 'my echo hello'

只要函数体满足() {打头就行了。并且这条POC也满足单个命令(command),因为没出现“;”。

Bash Shell在eval的时候遇到语法问题(x)=被忽略了。语法出错后,在缓冲区中就会只剩下了 “>\”这两个字符

接着就来到重点了,新的bash进程执行了这条命令:

$>\

my echo hello

如果你了解bash,你会知道 \ 是用于命令行上换行的,于是相当于执行了$>\my echo hello

然后在路径下生成了my文件,内容为hello。

Bash语法极其怪异,让我们逐一分析。

字符\是个转移字符,会保留后面跟的文本,\my实际等于字符串my,如果没有\,新的bash进程会把my当作是命令。因为如果你在终端只输入\并回车,当前bash进程会阻塞等待你输入,在POC里,“输入”的就是my。

字符>就是传说中的重定向,假设要把进程A的输出写入到文件B中,就写成如下:

A > B

其实你写成> B A形式也可以,不信试试:

[lu4nx@lx-pc /tmp]$ > hi date

[lu4nx@lx-pc /tmp]$ cat hi

2014年 09月 27日 星期六 01:06:06 CST

这种前缀写法我也是头一次见到,这次分析Shell源码,看得出它的设计极其像一个Lisp解析器,我以为这种写法是照顾Lisper,因为 Bash结构基本上就是一个交互式(REPL)和eval,而Lisp解析器的核心就是eval,直到我看了Shell的Yacc语法分析 (parse.y)后,我才恍然大悟。重定向的语法定义如下:

redirection: '>' WORD

{

redir.filename = $2;

$$ = make_redirection (1, r_output_direction, redir);

}

这里表示,输出的文件是取自$2,$2在这段表示参数WORD,如果输入的语句是> A B,那么WORD的实参就是A;如果输入的语句是A > B,那么WORD的实参就是B。

所以POC的思路就是定义一个语法不合法的函数体,绕过函数定义的检测代码,然后执行了后面的命令,最终让Bash在初始化的时候执行了>\my echo hello。

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值