悟夜叉个人博客 技术专题 漏洞防御篇:命令执行漏洞(二)

漏洞防御篇:命令执行漏洞(二)

注:本篇为 上一篇 的延续内容,主要内容是讲解 DVWA high 和 impossible 防御等级的命令执行漏洞。

上一篇 Medium 只是屏蔽掉了两个命令连接符,那么我们在 DVWA Security 切换成 high 等级看一下。老规矩,打开 View Source 查看源码。

<?php

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

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

    // Remove any of the characters 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 的防御等级中屏蔽了所有符号,包括我们常见的,比如括号减号。如果用户输入了上面屏蔽的符号,就会自动删除,这样就导致我们没有办法进行命令执行。

那有的同学会问了,这代码已经写死了,我们不是没有办法进行命令执行攻击了吗?这里就需要大家仔细观看了,可能未来大家在打CTF比赛的时候会遇到这种场景。

因为做研发每天面对的无数行代码,有时候多敲了一个空格很难察觉的到。我们返回去看到第三行屏蔽的字符:‘| ‘ => ”,  发现了什么?是不是多出了一个空格。那说明程序只能拦截竖线+空格,你单独输入一个竖线,程序是拦截不了的。

那我们返回 DVWA 输入 127.0.0.1|whoami ,发现已经成功运行了。大家可能也发现了我在编写文章的时候,代码左右或中间都加了一个空格,是因为我要考虑美观效果。但是在代码世界可就不一样了,一个空格可能改变程序的走向,这个就需要大家要记住的点。

我们也可以加其他命令尝试一下,比如 dir,命令为:127.0.0.1|dir ,就能把网站目录给列出来了。

 ������ D �еľ��� WorkFiles
 ��������� 8C00-1CEA

 D:\backup\DVWA-master\vulnerabilities\exec ��Ŀ¼

2023/03/22  19:17    
          .
2023/03/22  19:17    
          ..
2023/03/22  19:17    
          help
2023/03/22  19:17             1,829 index.php
2023/03/22  19:17    
          source
               1 ���ļ�          1,829 �ֽ�
               4 ��Ŀ¼ 112,476,471,296 �����ֽ�

其实 Medium 和 High 防御等级的代码相差不多,只是多屏蔽了几个字符。在 High 的代码中,缺少了对空格的检测,代码中屏蔽掉了竖线+空格,但并不影响竖线的使用。在 High 的防御等级,他没有起到任何技术性的突破,那么接下来我们就来看一下,在开发中应该采取什么样的算法去防御这个漏洞。

我们将防御等级提高到 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();

?>

可以明显的发现代码量已经变的很多了,不过没有关系,我们没必要全部看得懂。只需要看到他防御的关键点,如下图所示。

关键点1:$target = stripslashes( $target );

首先我们输入的 IP 还是赋值给了 $target 这个变量,下面有一个 stripslashes($target) ,这是一个PHP的函数,意思是删除所有的反斜杠\ ” ,比如:stripslashes(“Who\’s Go\ya\sha?”),实际上输出的是 “ Who’s Goyasha? ”,那 $target = stripslashes( $target ) 的意思就是删除用户输入的斜杠。

开发者设计这个功能的时候,就只想让你输入一个 IP 进行检测,如果你乱输入的话就给你做相应的屏蔽。不管你做什么,先给你屏蔽了再说。

关键点2:$octet = explode( “.”, $target );

使用了一个PHP函数 explode() ,意思是利用 “ . ” 对我们输入的 IP 地址进行分割。比如我们输入的 IP 地址是 “ 58.123.46.23 ”,他就会把 “ . ” 给去掉并分割为4个部分,分别为58、123、46、23

关键点3:if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) )

首先我们来看出现的第一个PHP函数 is_numeric(),他是用来检测输入的内容是否为数字,后面跟着 $octet[0] ,这个 0 代表着上面拆分的第一个数值 58,如果是  $octet[1] 那就是 123,以此类推。如果检测到你输入的不是数字,那就给相应的错误提示。

再来看 sizeof( $octet ) == 4 这个大家可以猜一下是什么作用?这段代码是来判断你输入的是不是四组内容,可以看一下之前的是 is_numeric( $octet[3]) 只判断到了第四个数字。

那我突发奇想,假如没有 sizeof( $octet ) == 4 的判断,那我通过 “ 58.123.46.23.111|whoami ” 是否能查到用户名呢?因为只判断了 “ 58.123.46.23 ” 是不是数字,后面的信息他并没有验证。所以如果没有该验证点,是可以命令执行攻击成功的!

不是很关键的关键点:$target = $octet[0] . ‘.’ . $octet[1] . ‘.’ . $octet[2] . ‘.’ . $octet[3];

这段代码就是将上述判断的四个数字,再合成 IP 形式的,给四个数字加上 “ . ”(点),最后我们再将上面解析的做个总结:

1、如果用户输入了斜杠,stripslashes() 函数就将斜杠自动删除;
2、explode() 再将删除斜杠后的数据根据 “ . ”(点)进行分割成4组内容;
3、分别判断这4组内容都是不是数值,如果判断任意一组不是数值,那就报错;
4、把验证完成的四个数字在用 “ . ”(点)拼接起来,恢复成正常的 IP 格式。

这毕竟是 DVWA impossible 防御等级,单从命令执行漏洞已经无法对其进行攻击了。目前也是简单了解一下,研发人员是如何防御此类漏洞的。

那么两篇文章内容比较多,相信大家也都初步了解命令执行漏洞是如何执行发生的了,如果还有同学对这些内容有疑问的话,欢迎在两篇内容下方评论!如果有空我会私下在教大家的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

联系我们

联系我们

站长QQ/VX:82794

在线咨询: QQ交谈

邮箱: 82794@qq.com

任何技术问题请联系QQ,非特殊行业请勿加微信!龙信小伙伴请联系微信群找我。
关注微信
非商务合作请勿添加

非商务合作请勿添加微信

返回顶部