SSRF绕过filter_var(),preg_match()和parse_url()
1.利用curl的变量解释符$
php版本
利用代码
/*ssrf.php*/
<?php echo "Argument: ".$argv[1]."n"; // check if argument is a valid URL if(filter_var($argv[1], FILTER_VALIDATE_URL)) { // parse URL $r = parse_url($argv[1]); print_r($r); // check if host ends with baidu.com if(preg_match('baidu.com$/', $r['host'])) { // get page from URL exec('curl -v -s "'.$r['host'].'"', $a); print_r($a); } else { echo "Error: Host not allowed"; } } else { echo "Error: Invalid URL"; } ?>
Bash将$baidu分析为一个空变量,并且使用curl请求了sec-redclub<empty> .com。
然而这只发生在curl语法中。 实际上,正如上面的屏幕截图所示,由parse_url()解析的主机名仍然是 sec-redclub$baidu.com。 $baidu变量并没有被解释。 只有当使用了exec()函数而且脚本又使用[host]来创建一个curl HTTP请求时,Bash才会将其转换为一个空变量。
所以应避免PHP脚本使用exec()或system()函数来调用像curl,wget之类的系统命令。
2.file_get_content()代替exec()或system()打cookie
<?php
echo "Argument: ".$argv[1]."n";
// check if argument is a valid URL
if(filter_var($argv[1], FILTER_VALIDATE_URL)) {
// parse URL
$r = parse_url($argv[1]);
print_r($r);
// check if host ends with google.com
if(preg_match('/baidu.com$/', $r['host'])) {
// get page from URL
$a = file_get_contents($argv[1]);
echo($a);
} else {
echo "Error: Host not allowed";
}
} else {
echo "Error: Invalid URL";
}
?>