Fork me on GitHub

PHP SSRF Techniques

写前面

这篇文章讲的实在是太棒了 https://medium.com/secjuice/php-ssrf-techniques-9d422cb28d51

php版本:

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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('/google\.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";
}
?>

首先调用了filter_var进行URL的验证,然后再用parse_url去解析URL,php7的版本中这个函数是没有问题的

同时通过preg_match函数限定只能以google.com结尾

如果达到ssrf呢?

正常情况下

攻击者:

此时$r[‘host’]显然不是以google.com结尾的

绕过URL验证和正则表达式

许多URL schema保留某些特殊含义的字符:它们在URL的特定于方案的部分中的外观具有指定的语义。如果在方案中保留对应于八位字节的字符,则必须对八位字节进行编码。字符“;”,“/”,“?”,“:”,“@”,“=”和“&”可以保留用于方案内的特殊含义。在方案中不能保留其他字符。

什么是URL schema

通常会用一些保留字符,比如;=,分割参数和参数值

一个可能是用name;v=1.1来表示name=version 1.1,然而也可以用name,1.1达到相同的效果,这根据算法来区分

curl或者wget会认为evil.com;google.comhostnameevil.com,querystringgoogle.com

但是并没有绕过filter_var函数
filter_var()函数可以解析很多不同的URL scheme

如果改成这样:

随便改,改成不认识的就行

此时已经成功地绕过了URL验证和正则表达式

但是curl命令却没有执行,于是考虑加上端口号

再次修改:

php test.php "111://evil.com:80;google.com:80/"

同样用逗号也行

parse_url只会尽可能地分割URL,而不是验证它,作者还提到了一种更好的方式:

0://evil$google.com

注意这里必须用单引号括起来。。

实现XSS

作者之后修改了代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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('/google\.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";
}
?>

作者想要注入一点东西,但是并没有成功

继续尝试:

data://google.com/plain;base64,SSBsb3ZlIFBIUAo=

此时注入成功了

那么XSS就很容易了

参考

PHP SSRF Techniques


Some trick in ssrf and unserialize()
/)