首页 > 技术文章 > 命令注入和DVWA命令注入实例

Zeker62 2021-08-17 19:51 原文

什么是命令注入?

在开发者开发程序过程中,一些高级应用可能需要调用一些外部程序:比如命令行获取信息、exe可执行文件等等。调用的时候会用到一些系统命令函数,通过这些函数,可以在其中注入一些恶意代码

命令注入漏洞产生原因

  • 用户输入作为拼接
  • 没有足够的安全过滤

危害

  • 继承web服务器程序执行系统命令
  • 继承web服务器权限,读写文件
  • 反弹shell,即服务器主动联系攻击方
  • 控制网站
  • 控制服务器

相关函数(PHP)

  • system() / passthru()函数:可以将字符串参数直接作为系统命令来执行:
<?php
if($_GET['cmd']){
	$str=$_GET['cmd'];
	system($str);
}
?>
<?php
if($_GET['cmd']){
	$str=$_GET['cmd'];
	passthru($str);
}
?>

可以这样传递参数,比如:

?cmd=ipconfig	
  • exec()函数:效果和system()函数一致,但是返回的结果有限,且不打印输出。
  • shell_exec()函数:效果和system()一致,但是没有打印输出。
<?php
if($_GET['cmd']){
	$str=$_GET['cmd'];
	print exec($str);
}
?>
<?php
if($_GET['cmd']){
	$str=$_GET['cmd'];
	print shell_exec($str);
}
?>
  • popen()效果和system()一样,但是不返回结果,返回结果指针
<?php
if($_GET['cmd']){
	$str=$_GET['cmd'];
	popen($str,'r/w') >> 1.txt;
}
?>
  • 反引号 ` :反引号里面的内容被当做命令
<?php
if($_GET['cmd']){
	$str=$_GET['cmd'];
	print `$str`
}
?>

漏洞利用

  • 查看文件:?cmd=type C:\windows…
  • 显示当前路径(绝对路径):?cmd=cd
  • 写入文件:?cmd=echo “<?php @$_GET['aaa'];?>” > C://windows…

防御方法:

  • 减少命令函数的使用,并且使用disable_function=里面禁掉一些函数
  • 在进入命令执行的函数或者方法之前对参数进行过滤
  • 参数的值尽量使用单引号包裹,在拼接的时候使用addslashes()函数对单引号,反斜杠,双引号进行转义

实战 DVWA

在这里插入图片描述
知识点:

  • command1 & command2 :两个命令都执行
  • command1 && command2 :与执行,第一个成功执行第二个才会执行
  • command1 | command2 :或执行,只执行第二个
  • command1 || command2:第一个执行成功,第二个不执行。第一个执行失败,第二个执行

low难度:

使用以下命令:

  • 127.0.0.1 & whoami
  • 127.0.0.1 && whoami
  • 127.0.0.1 | whoami
  • 127.0.0.0.1 || whoami

发现都可以得到whoami,下面进行代码审计:


<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = $_REQUEST[ 'ip' ]; //获取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() 函数搜索字符串在另一字符串中的第一次出现的位置,返回剩余的字符串 注释:该函数是二进制安全的。
注释:该函数是不区分大小写的。如需进行区分大小写的搜索,请使用 strstr() 函数。

php_uname — 返回运行 PHP 的系统的有关信息 ‘a’:此为默认。包含序列 “s n r v m” 里的所有模式。
‘s’:操作系统名称。例如: FreeBSD。
‘n’:主机名。例如: localhost.example.com。
‘r’:版本名称,例如: 5.1.2-RELEASE。
‘v’:版本信息。操作系统之间有很大的不同。 ‘m’:机器类型。例如:i386。

发现,这个难度情况下并没有对输入的命令进行过滤,所以我们可以为所欲为

Medium难度:

使用刚才的四个命令测试,发现只有127.0.0.1 && whoami这个命令不管用,猜测可能是对&&进行了过滤:
代码审计:


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

?>

发现关键过滤代码:

$substitutions = array(
    '&&' => '',
    ';'  => '',
);

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

对&&和;替换成了空字符串

High难度:

输入刚才四条命令,发现四个都不可以:
这时候代码审计:
关键代码:

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

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

好像对所有的可能性都进行了过滤?但是仔细观察发现,对于竖线的过滤,后面还有一个空格,所以我们在输入管线代码的时候不要加上空格:
在这里插入图片描述
就可以成功了。

Impossible难度:

输入前面所有的可能,发现怎么做都不对
代码审计:
关键代码:

// 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];
        。。。。。。。
        else {
        // Ops. Let the user name theres a mistake
        echo '<pre>ERROR: You have entered an invalid IP.</pre>';
    }

又是一大堆看不懂的函数:

stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。
explode() 函数把字符串打散为数组。
is_numeric() 函数用于检测变量是否为数字或数字字符串。

那么很显然,这个过滤器先将字符串按照 . 将命令进行分割成数组,然后看看每个数组是不是数字,如果不是就报错。

这种暂时还没想到破解之法,这种过滤是非常严格了,但是代码执行起来肯定好慢,先进行代码审计进行学习一波。

推荐阅读