1. High
1)源码分析
<?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>";
}
?>
从用户输入中移除特殊字符,例如 ‘&’、‘;’、‘|’ 、‘-’、‘$’ 、 ‘(’ 、 ‘)’ 、 和 ‘||’
不难发现特殊符号没有对 ‘|’(无空格) 进行替换,在输入框输入 ip地址|系统命令 并执行,便可轻松获取想获取的系统信息
2)实操
||前后加上空格即可
2. Impossible
1)源码分析
<?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();
?>
改进的地方包括:
输入的去除空白和字符过滤: 使用 trim() 函数删除输入中的前导和尾随空白字符,以避免用户输入的空白字符引起的问题。然后,使用一个黑名单数组 $substitutions 来定义需要替换为空字符串的特殊字符。使用 str_replace() 函数根据黑名单数组中的键值对进行字符替换,以过滤掉潜在的危险字符。
命令执行前的字符过滤: 在替换和过滤用户输入之后,再将过滤后的 $target 变量用于构造命令。这样可以确保命令中不包含潜在的恶意字符或命令注入的漏洞。
-
检查用户 token 和 session token 是否匹配。
……
checkToken( $_REQUEST[ ‘user_token’ ], $_SESSION[ ‘session_token’ ], ‘index.php’ );
……
checkdnsrr() — 给指定的主机(域名)或者IP地址做DNS通信检查,可以防止请求伪造。 -
去除 IP 地址中的反斜杠。
……
$target = stripslashes( $target );
……
stripslashes() — 反引用一个引用字符串。将反斜杠 ‘’ 转换为正斜杠 ‘/’ 。 -
将 IP 地址拆分成四个部分。
……
$octet = explode( “.”, $target );
……
explode() — 使用一个字符串分割另一个字符串。这里用 ‘.’ 将 IP 地址进行了分割。 -
检查 IP 地址分割后的各部分是否为单纯的数字,如果是,则将拆分的 IP 地址重新拼接,进而继续进行后续操作。
……
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];
……
is_numeric() — 检测变量是否为数字或数字字符串。
不难看出该方法对输入的 IP 地址做了合法性验证,只有输入符合 IPv4 格式的内容才能被正常执行,排除了一切可以注入其他命令的可能,安全性方面得到大幅提升。