DVWA--Command Injection
Low
命令注入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() 函数搜索字符串在另一字符串中的第一次出现。
注释:该函数是二进制安全的。
注释:该函数是不区分大小写的。如需进行区分大小写的搜索,请使用 strstr() 函数。
使用语法
stristr(string,search,before_search)
string 必需。规定被搜索的字符串。
search 必需。规定要搜索的字符串。
如果该参数是数字,则搜索匹配该数字对应的 ASCII 值的字符。
before_search 可选。默认值为 "false" 的布尔值。
如果设置为 "true",它将返回 search 参数第一次出现之前的字符串部分。
比如这样使用,返回world 以及之后的
这样该改成true,返回前面的字符串
php_uname
返回运行 PHP 的系统的有关信息
参数
mode 是单个字符,用于定义要返回什么信息:
'a':此为默认。包含序列 "s n r v m" 里的所有模式。
's':操作系统名称。例如: FreeBSD。
'n':主机名。例如: localhost.example.com。
'r':版本名称,例如: 5.1.2-RELEASE。
'v':版本信息。操作系统之间有很大的不同。
'm':机器类型。例如:i386。
使用php_uname 来判断操作系统来执行不同系统的ping 命令
可以看到对ip参数没有任何过滤,,直接就是post获取到输入内容,然后提交到shell执行,这样我们可以使用&&再后面跟上我们的命令
127.0.0.1 && whoami ,可以看到成功执行
直接创建用户
到了这一步已经是可以进行进一步提权了,剩下的操作就不用多说了吧。
Medium
再来看看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>"; } ?>
可以看到他把 && 和; 分号做了过滤,仅此而已,我们还可以用 & | 这种来绕过
还可以根据他的过滤规则来构造绕过 比如 127.0.0.1 &;&net user 这样就相当于是 127.0.0.1 && net user
这里我们再看一下cmd 的特殊字符
“|”:表示管道命令
解释:将第一条命令的结果作为第二条命令的参数来使用
“&”:表示组合命令
解释:不管前面命令是否执行,都会执行后面的命令,相当于or
“&&”:表示组合命令
解释:前面命令能执行才执行后面命令,相当于and
“||”:表示组合命令
解释:如果前面命令不执行则执行后面的命令
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>"; } ?>
这里对很多特殊字符做了过滤,把我们能用的都给过滤了,所以我们可以考虑根据他过滤规则来构造绕过
127.0.0.1 |;| net user = 127.0.0.1 | net user
为什么这种payload能绕过,注意看代码,'| '='', 在| 后面有空格,也就是我们可以利用这点让他过滤掉;| 这样我们前面的| 成功逃逸
或者是127.0.0.1 |net user 也可以
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函数把输入字符串从"."开始分割开成4份,再用is_numeric一个个判断每个部分是不是数字或者数字字符串,并且对输入字符串限制了4字节.
很难对其利用进行命令执行了。