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>";
}
?>
1、stristr($h, $n):返回 n字符串 在 h字符串中第一次出现的位置开始到结尾的字符串。 (中间"i"表示不区分大小写)。
2、php_uname($mode): 返回运行 PHP 的系统的有关信息,s模式表示返回操作系统的信息。
3、shell_exec($cmd):通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
"ping"与输入参数$target拼接成命令,然后通过shell_exec()函数在shell中执行命令,可以利用命令连接符注入更多的命令。在不同操作系统可以使用的命令连接符:
Linux:; | & || &&
Windows:| & || &&
尝试输入:127.0.0.1&echo 11
可以看到后面一条命令"echo 11"执行成功,使用其它命令可以进一步利用这个漏洞。
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>";
}
?>
1、array_keys($array):返回一个索引数组,包含$array数组中的所有键名。
2、str_replace($search, $replace, $subject):如果 search 是一个数组而 replace 是一个字符串,那么 search 中每个元素的替换将始终使用这个字符串。
虽然加了黑名单,但是黑名单没有包含所有的敏感字符(事实证明,黑名单不是一个有效的安全机制,因为它有时候无法预料到名单以外的敏感字符)。
继续输入:127.0.0.1&echo 11,返回结果同Low一致,当然也可以利用其它连接字符,如 “|”、 “||“或者”;”(Linux下)。
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|echo 11
如果学习过shell的话,你就会知道”|"是一个管道符,连接两条命令,前一条命令的输出结果作为后一条命令的输入。不过,后一条命令有没有输入无所谓,只要能够执行命令即可。
还有一点,这题的黑名单扩展的部分字符也许说明这些字符都是可利用于攻击的字符。
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、stripslashes($str):可以理解为转义的逆过程,即去掉"\"。
2、explode($delimiter, $string):此函数返回由字符串组成的数组,每个元素都是 string 的一个子串,它们被字符串 delimiter 作为边界点分割出来。
3、is_numeric($var):如果 var 是数字和数字字符串则返回 TRUE,否则返回 FALSE。 形如 123,"123"等类型的数据就会返回 TURE。
4、sizeof($mix):此函数是count()函数的别名,用于计算数组中的单元数目,或对象中的属性个数
程序对"x.x.x.x"ip地址以"."分割的4个部分检测是否为数字或者数字字符串,那么之前的输入如"1|echo 11"这种数据就无法通过,因此无法注入命令了。