本文最后更新于2019年05月08日,有任何建议或疑问,欢迎底部讨论。

Command Injection:命令注入,也可说是命令执行。

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 );
    }
    else {
        // *nix
        $cmd = shell_exec( 'ping  -c 4 ' . $target );
    }

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

此段代码关键在于三个函数 stristr() , php_uname() , shell_exec()
stristr(string,search,before_search):搜索字符串在另一字符串中的第一次出现。
http://www.w3school.com.cn/php/func_string_stristr.asp
php_uname(mode):返回运行 PHP 的系统的有关信息。

  • 'a':此为默认。包含序列 "s n r v m" 里的所有模式。
  • 's':操作系统名称。例如:FreeBSD。
  • 'n':主机名。例如: localhost.example.com。
  • 'r':版本名称,例如: 5.1.2-RELEASE。
  • 'v':版本信息。操作系统之间有很大的不同。
  • 'm':机器类型。例如:i386。

shell_exec():命令执行函数,与此类似的还有 exec(), system(), passthru()。

故此处可以在 ping 命令后接 && 执行系统命令:
2019-05-08T12:43:03.png

Medium

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

中级代码与低级别相比,过滤了 &&; ,因此直接 baidu.com&&net user 是不能执行命令的。
绕过:
1.使用单个 & :baidu.com&net user
注意: && 仅左侧命令执行成功,才执行右侧的命令, & 不管左侧命令执不执行都执行右侧命令。
2019-05-08T12:43:18.png
2.使用 &;& :代码将 ; 过滤为空,正好使 两个 & 完成拼接,和low代码一样执行。
2019-05-08T12:43:26.png

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

进一步加强了过滤,但是过滤不严谨, '| ' 管道符后面有个空格,那我们构造不带空格的 |,就行了
baidu.com|net user| 的用处是将其前面的输出作为后面的输入,然后打印结果:
2019-05-08T12:43:38.png
所以黑名单并不是安全的,这也是一些waf规则可绕过的原因。

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() 函数会删除字符串中的反斜杠,explode() 将输入的字符串打散为数组,返回分割后的字符串数组,is_numeric() 检测字符串是否为数字或者数字字符串,而且加入了 Anti-CSRF token,综上对输入IP进行了严格控制,且仅能 ping IP,不能 ping 域名。
2019-05-08T12:44:00.png
2019-05-08T12:44:07.png

文章目录