DVWA 通关指南:Command Injection (指令注入)

Command Injection (指令注入)

The purpose of the command injection attack is to inject and execute commands specified by the attacker in the vulnerable application. In situation like this, the application, which executes unwanted system commands, is like a pseudo system shell, and the attacker may use it as any authorized system user. However, commands are executed with the same privileges and environment as the web service has.
命令注入攻击的目的是,在易受攻击的应用程序中注入和执行攻击者指定的命令。在这种情况下,执行不需要的系统命令的应用程序就像一个伪系统外壳,攻击者可以将其作为任何授权的系统用户使用。但是,执行命令的权限和环境与 web 服务相同。
Command injection attacks are possible in most cases because of lack of correct input data validation, which can be manipulated by the attacker (forms, cookies, HTTP headers etc.).
The syntax and commands may differ between the Operating Systems (OS), such as Linux and Windows, depending on their desired actions.
在大多数情况下,由于缺少正确的输入数据验证,攻击者对例如表单、cookies、HTTP标头等进行操控,使得命令注入攻击成为可能。此攻击也称为“远程命令执行 (RCE)”。
Remotely, find out the user of the web service on the OS, as well as the machines hostname via RCE.
通过 RCE 远程查找操作系统上 web 服务的用户以及机器主机名。

Low Level

This allows for direct input into one of many PHP functions that will execute commands on the OS. It is possible to escape out of the designed command and executed unintentional actions.
在该等级下允许直接输入指令给一些 PHP 函数,从而使这些指令将在操作系统上执行。在输入其他的一些的指令时,有可能发生不符合设计意图的命令被执行。
This can be done by adding on to the request, "once the command has executed successfully, run this command".
这可以通过在请求中添加“一旦命令成功执行,运行此命令”的其他指令来完成。

源码审计

源码如下,php_uname(mode) 函数会返回运行php的操作系统的相关描述,当参数是 “s” 时操作系统名称。stristr() 函数搜索字符串在另一字符串中的第一次出现,返回字符串的剩余部分(从匹配点),未找到所搜索的字符串返回 FALSE。在这里使用者 2 个函数,目的是为了区分 DVWA 搭建在什么系统上,因为 Windows 系统和 Linux 的 Ping 还是有区别的。不过对于最重要的传入的 ping 命令的参数 target,并没有进行任何过滤。

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

?>

攻击方式

由于在操作系统中,“&”、“&&”、“|”、“||”都可以作为命令连接符使用,由于网页没有对参数进行任何过滤,因此可以用连接符后面接上其他指令来执行。

Medium Level

The developer has read up on some of the issues with command injection, and placed in various pattern patching to filter the input. However, this isn't enough.Various other system syntaxes can be used to break out of the desired command.
开发人员已经知晓有关命令注入的一些问题,并使用了各种方式来过滤输入。然而这还不够,攻击者仍然可以使用各种其他系统语法来执行所需的命令。

源码审计

源码如下,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>";
}

?>

攻击方式

“&&” 连接符不能用了,那我们就用 “&” 连接符来替代就行了。

High Level

In the high level, the developer goes back to the drawing board and puts in even more pattern to match. But even this isn't enough.
在高层次中,开发人员使用了更全面的过滤,但这样还不够。
The developer has either made a slight typo with the filters and believes a certain PHP command will save them from this mistake.
开发人员在过滤器上犯了一点错误,并相信某个 PHP 命令能够将这个问题摆平。

源码审计

相比 Medium 级别的代码,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>";
}

?>

输入上一个等级的 payload,发现 DVWA 返回的是已经过滤之后的字符串。

攻击方式

现在虽然是把所有的连接符都过滤了,但是开发者在“| ”后面加了个空格,因此我们还是能够用 “|” 连接符进行绕过。

Impossible Level

In the impossible level, the challenge has been re-written, only to allow a very stricted input. If this doesn't match and doesn't produce a certain result, it will not be allowed to execute. Rather than "black listing" filtering (allowing any input and removing unwanted), this uses "white listing" (only allow certain values).
在“不可能”级别中代码被重新编写,只允许非常严格的输入。如果这不匹配并且没有产生特定的结果,它将不被允许执行。它不使用“黑名单”过滤(允许任何输入并删除不需要的内容),而是使用“白名单”(只允许某些值)。

<?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 );      //stripslashes 删除字符串中的反斜杠

    // Split the IP into 4 octects
    $octet = explode( ".", $target );      //explode 把字符串打散为数组

    // 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 级别的代码对参数 ip 进行了严格的限制,只有“数字.数字.数字.数字”的输入才会被接收执行, 加入了 Anti-CSRF token 进行进一步保障,使得命令注入漏洞不存在。

总结与防御

在一些 Web 程序中需要调用一些执行系统命令的函数,例如 PHP 的 system、exec、shell_exec 函数等。当攻击者能够直接操作命令执行的参数,并且没有代码对传入的参数进行过滤时,攻击者就能将用于搞破坏的系统命令夹带进来让系统执行。
在 Windows 系统和 Linux 系统中都有一些管道符,这些管道符可以被用来拼接攻击指令:

  • “&&”:前面的语句正确执行时,才执行后面的语句;
  • “&”:前面的语句执行出错时,执行后面的语句;
  • “|”:将前面的语句运行的结果,当做后面语句的输入,显示后面语句的执行结果;
  • “||”:前面的语句出错时,执行后面的语句。

对于指令注入漏洞,比较好的防御方式是尽可能别用命令执行函数,对于输入的参数要做好黑名单过滤或者白名单验证。

参考资料

新手指南:DVWA-1.9全级别教程之Command Injection
DVWA之Command injection(命令执行漏洞)

posted @ 2020-09-12 23:08  乌漆WhiteMoon  阅读(2049)  评论(0编辑  收藏  举报