本文最后更新于:2019 , 八月 19日 星期一, 8:51 晚上

简介

PHP中,我们可以对输入进行注入攻击,命令注入也称命令执行
注入:通过利用无验证码变量构造特殊语句对服务器进行渗透
命令执行:可以执行系统或应用指令的漏洞(例如:CMD命令或bash命令)
而该漏洞的产生主要是基于一些函数的过滤不严导致

执行函数

  • system()

    执行外部程序,并且显示输出

    system($command[,int &$return_ar]);
    /*
    command:要执行的命令
    return_var:外部命令执行后的返回状态会设置到此变量中
    */

    执行系统外部命令时,直接将结果输出到浏览器

    执行成功:true,失败:false

  • exec()

    主要用于执行外部程序

    exec($command [, array &$output [, int &$return_var ]] );
    /*
    command:要执行的命令
    output:命令执行的输出填充此数组,每行没输出填充数组的一个元素
     数组中的数据不包含行尾的空白字符
     Ps:如果数组中已经包含部分元素,会在数组末尾追加内容
     如果你不想在数组末尾进行追加,在使用之前对数组进行重置(unset)
    return_var:命令执行后的返回状态会被写入到此变量
    */
    
    # 例子
    $command = "ls";
    exec($command,$array);
    print_r($array);
    
    // Linux中执行:php ./exec.php
  • shell_exec()

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

    shell_exec($cmd);
    // 如果执行过程中发生错误或者进程不产生输出,则返回NULL
  • passthru()

    执行外部程序并且显示原始输出

    passthru($command[,int &$return_var]);
    /*
    command:要执行的命令
    return_var:返回状态会被写入到此变量
    */

    当所执行的Unix命令输出二进制数据,并且需要直接传输到浏览器时,就需要用到此函数

  • pcntl_exec()

    在当前进程空间执行指定程序

    pcntl_exec($path[,$args[,$envs]]);
    /*
    path:必须是可执行程序路径 或 一个在文件第一行指定一个可执行文件路径标头的脚本
     例如第一行:#!/usr/local/bin/perl
    args(array):要传递给程序的参数的字符串数组
    envs(array):要传递给程序作为环境变量的字符串数组
     数组格式:key=>value
     key:传递的环境变量的名称
     value:环境变量值
    */
  • popen()

    打开进程文件指针

    popen(command,mode);
    /*
    command:要执行的命令
    mode:连接模式
     r:只读
     w:只写(打开并清空或创建一个新文件)
    */
    
    # 例子
    popen('whoami >> D:/2.txt','r');
  • proc_open()

    执行一个命令,并且打开用来输入/输出的文件指针

    proc_open($cmd, array $descriptorspec,array &$pipes[,string $cwd[,array $env [,array $other_options]]]);
    /*
    cmd:要执行的命令
    descriptorspec:一个索引数组
     数组的键表示描述符
     数组元素值表示PHP如何将这些描述传至子进程
     0 标准输入
     1 标准输出
     2 标准错误
    pipes:将被置为索引数组,其中的元素是被执行程序创建的管道对应到PHP这一端的文件指针
    cwd:要执行命令的初始工作目录,必须是绝对路径,设置为NULL表示使用默认值(当前目录)
    env:要执行的命令所使用的环境变量
    other_options:指定一些附加选项
     suppress_errors(winds平台):True,抑制本函数产生的错误
     bypass_shell(win平台):True,绕过cmd.xex shell
    */

另外反引号(`)也是可以执行命令,不过实际上这种方式也是调用的shell_exec()函数

echo `whoami`; // 在后面调用shell_exec()函数实现的

简易复现

这是自己手写的超级难看的靶场了吧

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>命令执行</title>
</head>
<body>
<form action="cmd.php" method="POST">
    Ping:<input type="text" name="cmd">
    <input type="submit" value="执行" name="run">
</form>
</body>
</html>

<?php
if(isset($_POST['run'])){
    $cmd = $_POST['cmd'];
    if(trim($cmd)){
        $run = 'ping ' . $cmd;
        echo "<pre>".iconv('GB2312','UTF-8',shell_exec($run))."</pre>";
    }else{
        echo "IP Error";
    }
}
?>

本意:这只是用来检测网址的连通情况
然而,发现我们可以使用一些其他符号进行绕过,执行其他的命令
例如:|


这里是因为没有对我们输入的字符进行过滤,导致了用户可以通过其他字符进行绕过

达到执行任意命令的效果


防御

  • 自定义函数过滤或使用正则
  • escapeshellarg()
  • escapeshellcmd()

代码审计   PHP      PHP代码审计

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

代码审计之文件读取
vauditdemo重装漏洞 复现