PHP代码审计学习(6)——命令执行

命令执行

  应用程序有时需要调用一些执行系统命令的函数,如在PHP中,使用system、exec、shell_exec、passthru、popen、proc_popen等函数可以执行系统命令。当黑客能控制这些函数中的参数时,就可以将恶意的系统命令拼接到正常命令中,从而造成命令执行漏洞,这就是命令执行漏洞。

  DVWA的命令审计:https://www.cnblogs.com/Lee-404/p/13038623.html

挖掘思路

  1、用户可以控制输入,没有对应用的输入进行过滤

  2、存在危险函数,直接搜索危险函数

命令执行的漏洞分类

  1、代码层过滤不严

    商业应用的一些核心代码封装在二进制文件中,在web应用中通过system函来调用:system("/bin/program --arg$arg");

  2、系统的漏洞造成

    bash破壳漏洞(CVE-2014-6271)

  3、调用第三方组件存在命令执行

    如WordPress中用来处理图片的ImageMagick组件、JAVA中的命令执行漏洞(struts2/ElasticsearchGroovy等)、ThinkPHP命令执行

  漏洞危害

  1. 继承Web服务程序的权限去执行系统命令或读写文件
  2. 反弹shell
  3. 控制整个网站甚至服务器
  4. 进一步内网渗透
  5. 等等

  命令通配符

    |、||、&、&&的区别:
    &:无论左边是false还是true,右边都执行
    &&:具有短路效果,左边是false,右边不执行。
    |:无论左边是false还是true,右边都会执行
    ||:具有短路效果,左边是true,右边不执行

危险函数

  system

    system函数可以用来执行一个外部的应用程序并将相应的执行结果输出,函数原型如下:

    string system(string command, int&return_var)

    command是要执行的命令,return_var存放执行命令的执行后的状态值。

<?php
if(isset($_REQUEST['cmd'])){
    $cmd = ($_REQUEST["cmd"]);
    system($cmd);//eval($cmd);
    echo "</pre>$cmd<pre>";
    die;
}
?>   

 

  exce

    exec函数可以用来执行一个外部的应用程序

    string exec (string command, array&output, int &return_var)

    其中,command是要执行的命令,output是获得执行命令输出的每一行字符串,return_var存放执行命令后的状态值。

<?php
if(isset($_REQUEST['cmd'])){
    $cmd = ($_REQUEST["cmd"]);
    echo exec($cmd);//eval($cmd);
    echo "</pre>$cmd<pre>";
    die;
}
?>

    其实用法差不多

  passthru

    passthru函数可以用来执行一个UNIX系统命令并显示原始的输出,当UNIX系统命令的输出是二进制的数据,并且需要直接返回值给浏览器时,需要使用passthru函数来替代system与exec函数。Passthru函数原型如下:

    void passthru (string command, int&return_var)

    其中,command是要执行的命令,return_var存放执行命令后的状态值

  shell_exce

    shell_exec — 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回

    string shell_exec ( string $cmd )

    其中,command是要执行的命令。

  反引号

    命令执行的输出。 如果执行过程中发生错误或者进程不产生输出,则返回 NULL

<?php
   echo `whoami`; 
?>

    在php中称之为执行运算符,PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出,使用反引号运算符“`”的效果与函数 shell_exec() 相同。

代码中常见位置 

  https://blog.csdn.net/weixin_33798152/article/details/92606607?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-7

  system("$arg"); //可控点直接是待执行的程序

  system("/bin/prog $arg"); //可控点是传入程序的整个参数

  system("/bin/prog -p $arg"); //可控点是传入程序的某个参数的值(无引号包裹)

  system("/bin/prog --p=\"$arg\"");//可控点是传入程序的某个参数的值(有双引号包裹)

  system("/bin/prog --p='$arg'"); //可控点是传入程序的某个参数的值(有单引号包裹)

 

  第一种情况

    如果我们能直接控制$arg,那么就能执行执行任意命令了,没太多好说的。

  第二种情况

    我们能够控制的点是程序的整个参数,我们可以直接用&& || 或 | 等等,利用与、或、管道命令来执行其他命令(可以涉及到很多linux命令行技巧)。

还有一个偏门情况,当$arg被 escapeshellcmd处理之后,我们不能越出这个外部程序的范围,我们可以看看这个程序自身是否有“执行外部命令”的参数或功能,比如linux下的sendmail 命令自带读写文件功能,我们可以用来写webshell。

  第三种情况

    我们控制的点是一个参数,我们也同样可以利用与、或、管道来执行其他命令,情境与二无异。

  第四种情况

    这种情况压力大一点,有双引号包裹。如果引号没有被转义,我们可以先闭合引号,成为第三种情况后按照第三种情况来利用,如果引号被转义(addslashes),我们也不必着急。linux shell 环境下双引号中间的变量也是可以被解析的,我们可以在双引号内利用反引号执行任意命令 `id`

  第五种情况

    这是最难受的一种情况了,因为单引号内只是一个字符串,我们要先闭合单引号才可以执行命令。如:system("/bin/prog –p='aaa' | id")

    危害自然不言而喻,执行命令可以读写文件、反弹shell、获得系统权限、内网***等。

    在漏洞检测中,除了有回显的命令注入(比如执行dir 命令或者cat 读取系统文件);还可以使用盲打的方式,比如curl远程机器的某个目录(看access.log),或者通过dns解析的方式获取到漏洞机器发出的请求

过滤函数

  Escapesshellcmd()
  过滤整条命令

  功能:escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。
反斜线(\)会在以下字符之前插入: &#;`|?~<>^()[]{}$*, \x0A 和 \xFF。 ‘ 和 “ 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。
定义 :string escapeshellcmd ( string $command)

  Escapeshellarg()
  过滤整个参数
  功能 :escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,shell 函数包含 exec(), system() 执行运算符(反引号
)

  定义 :string escapeshellarg ( string $arg )

漏洞修复

  1. 尽量少用执行命令的函数或者直接禁用
  2. 参数值尽量使用引号包括
  3. 在使用动态函数之前,确保使用的函数是指定的函数之一
  4. 在进入执行命令的函数/方法之前,对参数进行过滤,对敏感字符进行转义
  5. 对PHP语言来说,不能完全控制的危险函数最好不要使用
posted @ 2020-06-16 10:25  Lee-404  阅读(658)  评论(0编辑  收藏  举报
Live2D