关于DVWA靶场高难度命令执行的代码审计

发布时间 2023-06-15 21:38:42作者: i苏沐辰

image

需要的环境:dvwa

使用的工具:PHP手册

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

首先进行if判断,使用isset函数判断post传入的参数是否为空,如果不为空,执行下面的语句

image

trim

遇到了不熟悉的语句trim,翻PHP手册并尝试使用该语句,

$target = **<u>trim</u>**($_REQUEST[ 'ip' ]);

image

由手册得知,trim可以去除字符串首尾的空白字符,能够使页面更加整洁

尝试trim函数

如图,php代码内参数左边有一个空格,中间一个空格,右边有两个空格,为了更加直观的看出区别,使用管道符对两个变量进行分割,同时输出

image

网页页面看不出太大区别

image

右键查看网页的源代码,可以看出管道符左右的区别,使用trim函数后,参数中间空格不受影响,两边的空格消失,没什么太大作用,只是使页面更加整洁美观

image

=============================================

array

翻手册查询语句array

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

image

使用array函数可以创建一个数组

=============================================

查询语句str_replace,array_keys

$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
array_keys函数在str_replace函数中,从里到外对函数进行解析

array_keys

array_keys( $substitutions )
array_keys返回数组中的键名,可知该函数获取了array函数中的键名

image

尝试array_keys函数

使用var_dump输出array_keys函数的内容及类型

image

如图输出了一个索引数组

image

看起来不太明显,使用for循环对数组进行遍历

$arr1=array_keys($substitutions)
//定义一个变量arr1,把array_keys数组赋赋给变量arr1

    for($a=0,$a<sizeof($substitutions),$a++){
    //sizeof用于计算数组内元素的个数
	//定义一个变量a为0,当变量a小于$substitutions变量内元素个数的时候停止,变量a自增
    
    echo $arr1[$a]."<br \>";
	//取$arr1数组内的第$a个元素,返回给$arr1,并输出,为了更加直观,拼接一个换行
	//这样可以查看到array_keys返回的数组具体有什么
}

image

由此可知array_keys具体返回的数组

image

由此可知,array_keys函数将$substitutions数组中的键名取出并做成了一个新的索引数组

=============================================

str_replace

str_replace( array_keys( $substitutions ), $substitutions, $target )
str_replace函数可以对字符串进行替换

image

尝试str_replace函数
$substitutions = array(
        'ipconfig'  => '',
        'whoami'  => '',
        'pwd' => '',
    );
    $arr1 =  array_keys( $substitutions );

	$a="whoamiabcipconfig123pwd";
	echo $a.<br \>;
	//分别输出执行str_replace前后的字符串
	//str_replace(数组1返回的键名,数组1,变量(字符串))
	echo str_replace($arr1, $substitutions, $a);

image

如图可知,str_replace将(第三个参数)中的字符串与(第一个参数)数组1返回的键名进行匹配,有相同的字符串就会访问(第二个参数)数组1查看规则将其替换为空

解析语句str_replace( array_keys( $substitutions ), $substitutions, $target )

str_replace( array_keys( $substitutions ), $substitutions, $target )
//先通过array_keys返回$substitutions数组内的键名,然后根据键名,查找传递过来的$target,如果有与键名相匹配的字符,就根据$substitutions数组内的value值进行替换

=============================================

stristr

stristr( php_uname( 's' ), 'Windows NT' )
php_uname用于返回php系统信息

image

尝试php_name,由此可知,该函数用于判定当前操作系统的版本(由于Windows系统和*nix系统的ping规则不同,所以需要区分,分别进行操作)

image

stristr是strstr的忽略大小写版本

Windows不区分大小写,但是php区分大小写,所以需要stristr函数来忽略大小写

strstr用于查找字符串的首次出现
image

image

解析语句stristr( php_uname( 's' ), 'Windows NT' )
stristr( php_uname( 's' ), 'Windows NT' )
//查看当前的操作系统是否为Windows,忽略大小写

=============================================

全代码解析

<?php
if( isset( $_POST[ 'Submit' ]  ) ) {
//进行if判断,使用isset函数判断post传入的参数是否为空,如果不为空,执行下面的语句
    $target = trim($_REQUEST[ 'ip' ]);
//去除用户输入字符串首尾的空白字符,并返回给变量$target,使页面更加整洁
    $substitutions = array(
        '&'  => '',
        ';'  => '',
        '| ' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );  	//创建一个数组

    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
//先通过array_keys返回$substitutions数组内的键名,然后根据键名,查找传递过来的$target,如果有与键名相匹配的字符,就根据$substitutions数组内的value值进行替换,再将数值返回给$target
    if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
//if进行判断,查看当前的操作系统是否为Windows,忽略大小写,如果为windows,执行下面的语句,对目标进行ping命令,返回给变量$cmd
        $cmd = shell_exec( 'ping  ' . $target );
    }
    else {
//if判断如果不为Windows则默认为*nix系统,对目标进行ping命令,限制为4个包,返回给变量$cmd
        $cmd = shell_exec( 'ping  -c 4 ' . $target );
    }
//将返回的结果$cmd输出到页面
    echo "<pre>{$cmd}</pre>";
}
?>