DVWA-03-Command Injection

目录

1.概念

2.实验

2.1 Low

2.2 Medim

2.3 High

2.4 Impossible


1.概念

Command Injection,即命令注入,是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。

相关函数
在PHP中可以调用外部程序的常见函数:

   system(args) 有回显


<?php
echo '<pre>';

// 输出 shell 命令 "ls" 的返回结果
// 并且将输出的最后一样内容返回到 $last_line。
// 将命令的返回值保存到 $retval。
$last_line = system('ls', $retval);

// 打印更多信息
echo '
</pre>
<hr />Last line of the output: ' . $last_line . '
<hr />Return value: ' . $retval;
?>

  passthru(args)(有回显)

 passthru ( string $command , int $return_var = ? )

参数

command

    要执行的命令。
return_var

    如果提供 return_var 参数, Unix 命令的返回状态会被记录到此参数。

    exec(args) (回显最后一行-必须echo输出)


<?php
// 输出运行中的 php/httpd 进程的创建者用户名
// (在可以执行 "whoami" 命令的系统上)
echo exec('whoami');
?>


    shell_exec(args) (无回显-必须输出)


<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>


    popen(handle,mode)(无回显)


<?php
$handle = popen("/bin/ls", "r");
?>

popen ( string $command , string $mode )


command

    命令。
mode

    模式。


    proc_open(‘cmd’,‘flag’,‘flag’)(无回显)
  

 proc_open ( string $cmd , array $descriptorspec , array &$pipes , string $cwd = null , array $env = null , array $other_options = null ) : resource

类似 popen() 函数, 但是 proc_open() 提供了更加强大的控制程序执行的能力。 

2.实验

2.1 Low

先来审计下代码

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = $_REQUEST[ 'ip' ];

    // Determine OS and execute the ping command.
    if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
        // Windows
        $cmd = shell_exec( 'ping  ' . $target ); //.是php里的算术运算符,用来连接两个字符串
    }
    else {
        // *nix
        $cmd = shell_exec( 'ping  -c 4 ' . $target );
    }

    // Feedback for the end user
    echo "<pre>{$cmd}</pre>";
}

?> 

运算符

. 是php里的算术运算符,用来连接两个字符串

变量:

$_POST 变量,在 PHP 中,预定义的 $_POST 变量用于收集来自 method="post" 的表单中的值。

$_REQUEST 变量,预定义的 $_REQUEST 变量包含了 $_GET、$_POST 和 $_COOKIE 的内容。$_REQUEST 变量可用来收集通过 GET 和 POST 方法发送的表单数据。

函数介绍

1.isset(),用于检测变量是否已设置并且非NULL

2.stristr(string,search,before_search),返回字符串的剩余部分,如果未找到所搜索的字符串,则返回FALSE

3.php_uname(mode),这个函数会返回运行php的操作系统的相关描述,参数mode可取值”a” (此为默认,包含序列”s n r v m”里的所有模式),”s ”(返回操作系统名称),”n”(返回主机名),” r”(返回版本名称),”v”(返回版本信息), ”m”(返回机器类型)。

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

代码分析:通过判端系统执行不同的命令,但是未对参数ip做任何过滤

利用,利用管道符,构造输入内容,好用的二个符号

"&"如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。

"|" 直接执行后面的命令

其他的符号

"&&" : 如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句只能为真

“||” :当前面的语句执行出错,执行后面的语句。例如:ping 1 ||whoami

";" : 执行完前面的语句再执行后面的。例如: ping 127.0.0.1;whoami,在linux中

2.2 Medim

先来审计代码

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = $_REQUEST[ 'ip' ];

    // Set blacklist
    $substitutions = array(
        '&&' => '',
        ';'  => '',
    );

    // Remove any of the charactars in the array (blacklist).
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );

    // 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>";
}

?> 

与低级的比较多了下面的代码,设置了黑名单进行过滤 "&&",";"符号,但依旧有安全问题,可以看到完全没有对我们的"|","&",等其他符号过滤,所以有时候黑名单的作用是有限的

// Set blacklist
    $substitutions = array(
        '&&' => '',
        ';'  => '',
    );

    // Remove any of the charactars in the array (blacklist).
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); 

也可以使用&;&这种格式,进行绕过,因为会将;过滤掉。

array_keys ( array $array , mixed $search_value = null , bool $strict = false ) : array

 array_keys() 返回 input 数组中的数字或者字符串的键名。

如果指定了可选参数 search_value,则只返回该值的键名。否则 input 数组中的所有键名都会被返回。
参数

input

    一个数组,包含了要返回的键。
search_value

    如果指定了这个参数,只有包含这些值的键才会返回。
strict

    判断在搜索的时候是否该使用严格的比较(===)。

<?php
$array = array(0 => 100, "color" => "red");
print_r(array_keys($array));

$array = array("blue", "red", "green", "blue", "blue");
print_r(array_keys($array, "blue"));

$array = array("color" => array("blue", "red", "green"),
               "size"  => array("small", "medium", "large"));
print_r(array_keys($array));
?>

str_replace():把字符串 "Hello world!" 中的字符 "world" 替换成 "Peter":

<?php
echo str_replace("world","Peter","Hello world!");
?>

2.3 High

老规矩,先看代码,进一步完善了黑名单,可以看到已经对我们经常可以用到的符号做了过滤,但是黑名单限制还是有局限性

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = trim($_REQUEST[ 'ip' ]);

    // Set blacklist
    $substitutions = array(
        '&'  => '',
        ';'  => '',
        '| ' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );

    // Remove any of the charactars in the array (blacklist).
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );

    // 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>";
}

?> 

我们仔细观察审计,发现"| "居然有一个空格,但是我们可以用" |",“|”来进行参数构造


2.4 Impossible

进行代码审计

<?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();

?> 
  • stripslashes(string)

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

  • explode(separator,string,limit)   使用一个字符串分割另一个字符串,并返回由字符串组成的数组。注释:"separator" 参数不能是一个空字符串。
  • is_numeric(string)   检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。

通过对各个参数的了解,我们发现最高难度的对输入的参数做了严格的限制,"数字.数字.数字.数字"的格式才会被接收执行,因此命令注入暂时没有思路进行下去了。同时,在代码的最后加入了Anti-CSRF,增加了其他方面的安全性。

猜你喜欢

转载自blog.csdn.net/weixin_43198291/article/details/114123775
今日推荐